Merge lp:~trb143/openlp/webengine-migrate-trunk into lp:~openlp-dev/openlp/webengine-migrate
- webengine-migrate-trunk
- Merge into webengine-migrate
Proposed by
Tim Bentley
Status: | Merged |
---|---|
Merged at revision: | 2865 |
Proposed branch: | lp:~trb143/openlp/webengine-migrate-trunk |
Merge into: | lp:~openlp-dev/openlp/webengine-migrate |
Diff against target: |
13824 lines (+5142/-2981) 57 files modified
openlp/core/app.py (+5/-1) openlp/core/common/actions.py (+1/-1) openlp/core/common/mixins.py (+2/-1) openlp/core/common/registry.py (+7/-0) openlp/core/lib/mediamanageritem.py (+37/-26) openlp/core/lib/plugin.py (+5/-4) openlp/core/lib/pluginmanager.py (+74/-62) openlp/core/lib/serviceitem.py (+7/-2) openlp/core/loader.py (+48/-0) openlp/core/state.py (+175/-0) openlp/core/ui/icons.py (+1/-1) openlp/core/ui/mainwindow.py (+4/-26) openlp/core/ui/media/__init__.py (+1/-38) openlp/core/ui/media/mediacontroller.py (+70/-163) openlp/core/ui/media/mediaplayer.py (+2/-1) openlp/core/ui/media/playertab.py (+9/-10) openlp/core/ui/media/vendor/mediainfoWrapper.py (+0/-129) openlp/core/ui/media/vendor/vlc.py (+3861/-1850) openlp/core/ui/media/vlcplayer.py (+4/-4) openlp/core/ui/pluginform.py (+29/-27) openlp/core/ui/settingsform.py (+5/-6) openlp/core/ui/slidecontroller.py (+52/-104) openlp/plugins/alerts/alertsplugin.py (+3/-0) openlp/plugins/alerts/lib/alertsmanager.py (+1/-1) openlp/plugins/bibles/bibleplugin.py (+3/-0) openlp/plugins/custom/customplugin.py (+3/-0) openlp/plugins/images/imageplugin.py (+3/-0) openlp/plugins/media/lib/mediaitem.py (+52/-149) openlp/plugins/media/mediaplugin.py (+4/-51) openlp/plugins/presentations/presentationplugin.py (+3/-0) openlp/plugins/songs/lib/mediaitem.py (+11/-5) openlp/plugins/songs/songsplugin.py (+3/-0) openlp/plugins/songusage/songusageplugin.py (+3/-0) scripts/check_dependencies.py (+2/-1) scripts/jenkins_script.py (+7/-6) tests/functional/openlp_core/api/endpoint/test_controller.py (+4/-0) tests/functional/openlp_core/common/test_registry.py (+1/-1) tests/functional/openlp_core/lib/test_mediamanageritem.py (+12/-0) tests/functional/openlp_core/lib/test_pluginmanager.py (+70/-25) tests/functional/openlp_core/lib/test_serviceitem.py (+19/-8) tests/functional/openlp_core/test_state.py (+151/-0) tests/functional/openlp_core/ui/media/test_mediacontroller.py (+33/-104) tests/functional/openlp_core/ui/media/test_vlcplayer.py (+4/-4) tests/functional/openlp_core/ui/test_maindisplay.py.THIS (+283/-0) tests/functional/openlp_core/ui/test_mainwindow.py (+4/-6) tests/functional/openlp_core/ui/test_media.py (+13/-11) tests/functional/openlp_core/ui/test_slidecontroller.py (+1/-0) tests/functional/openlp_core/widgets/test_views.py (+15/-13) tests/functional/openlp_plugins/images/test_upgrade.py (+4/-2) tests/functional/openlp_plugins/media/test_mediaplugin.py (+1/-27) tests/functional/openlp_plugins/songs/test_mediaitem.py (+0/-1) tests/interfaces/openlp_core/lib/test_pluginmanager.py (+16/-12) tests/interfaces/openlp_core/ui/media/__init__.py (+0/-21) tests/interfaces/openlp_core/ui/media/vendor/__init__.py (+0/-21) tests/interfaces/openlp_core/ui/media/vendor/test_mediainfoWrapper.py (+0/-49) tests/interfaces/openlp_core/ui/test_mainwindow.py (+14/-3) tests/openlp_core/projectors/test_projector_db.py (+0/-4) |
To merge this branch: | bzr merge lp:~trb143/openlp/webengine-migrate-trunk |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tomas Groth | Approve | ||
Review via email: mp+362287@code.launchpad.net |
Commit message
Fixed trunk merge so now matches that.
Description of the change
To post a comment you must log in.
Revision history for this message
Tomas Groth (tomasgroth) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'openlp/core/app.py' |
2 | --- openlp/core/app.py 2018-10-24 21:02:06 +0000 |
3 | +++ openlp/core/app.py 2019-01-27 20:26:59 +0000 |
4 | @@ -35,8 +35,10 @@ |
5 | |
6 | from PyQt5 import QtCore, QtWebEngineWidgets, QtWidgets # noqa |
7 | |
8 | +from openlp.core.state import State |
9 | from openlp.core.common import is_macosx, is_win |
10 | from openlp.core.common.applocation import AppLocation |
11 | +from openlp.core.loader import loader |
12 | from openlp.core.common.i18n import LanguageManager, UiStrings, translate |
13 | from openlp.core.common.path import copytree, create_paths |
14 | from openlp.core.common.registry import Registry |
15 | @@ -115,8 +117,10 @@ |
16 | # Check if OpenLP has been upgrade and if a backup of data should be created |
17 | self.backup_on_upgrade(has_run_wizard, can_show_splash) |
18 | # start the main app window |
19 | + loader() |
20 | self.main_window = MainWindow() |
21 | Registry().execute('bootstrap_initialise') |
22 | + State().flush_preconditions() |
23 | Registry().execute('bootstrap_post_set_up') |
24 | Registry().initialise = False |
25 | self.main_window.show() |
26 | @@ -134,7 +138,7 @@ |
27 | if Settings().value('core/update check'): |
28 | check_for_update(self.main_window) |
29 | self.main_window.is_display_blank() |
30 | - self.main_window.app_startup() |
31 | + Registry().execute('bootstrap_completion') |
32 | return self.exec() |
33 | |
34 | @staticmethod |
35 | |
36 | === modified file 'openlp/core/common/actions.py' |
37 | --- openlp/core/common/actions.py 2018-10-02 04:39:42 +0000 |
38 | +++ openlp/core/common/actions.py 2019-01-27 20:26:59 +0000 |
39 | @@ -20,7 +20,7 @@ |
40 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
41 | ############################################################################### |
42 | """ |
43 | -The :mod:`~openlp.core.utils.actions` module provides action list classes used |
44 | +The :mod:`~openlp.core.common.actions` module provides action list classes used |
45 | by the shortcuts system. |
46 | """ |
47 | import logging |
48 | |
49 | === modified file 'openlp/core/common/mixins.py' |
50 | --- openlp/core/common/mixins.py 2018-10-02 04:39:42 +0000 |
51 | +++ openlp/core/common/mixins.py 2019-01-27 20:26:59 +0000 |
52 | @@ -50,7 +50,8 @@ |
53 | setattr(self, name, self.logging_wrapper(m, self)) |
54 | return self._logger |
55 | |
56 | - def logging_wrapper(self, func, parent): |
57 | + @staticmethod |
58 | + def logging_wrapper(func, parent): |
59 | """ |
60 | Code to added debug wrapper to work on called functions within a decorated class. |
61 | """ |
62 | |
63 | === modified file 'openlp/core/common/registry.py' |
64 | --- openlp/core/common/registry.py 2018-10-24 21:02:06 +0000 |
65 | +++ openlp/core/common/registry.py 2019-01-27 20:26:59 +0000 |
66 | @@ -205,6 +205,7 @@ |
67 | Registry().register(de_hump(self.__class__.__name__), self) |
68 | Registry().register_function('bootstrap_initialise', self.bootstrap_initialise) |
69 | Registry().register_function('bootstrap_post_set_up', self.bootstrap_post_set_up) |
70 | + Registry().register_function('bootstrap_completion', self.bootstrap_completion) |
71 | |
72 | def bootstrap_initialise(self): |
73 | """ |
74 | @@ -217,3 +218,9 @@ |
75 | Dummy method to be overridden |
76 | """ |
77 | pass |
78 | + |
79 | + def bootstrap_completion(self): |
80 | + """ |
81 | + Dummy method to be overridden |
82 | + """ |
83 | + pass |
84 | |
85 | === modified file 'openlp/core/lib/mediamanageritem.py' |
86 | --- openlp/core/lib/mediamanageritem.py 2018-10-02 04:39:42 +0000 |
87 | +++ openlp/core/lib/mediamanageritem.py 2019-01-27 20:26:59 +0000 |
88 | @@ -130,6 +130,9 @@ |
89 | self.has_file_icon = False |
90 | self.has_delete_icon = True |
91 | self.add_to_service_item = False |
92 | + self.can_preview = True |
93 | + self.can_make_live = True |
94 | + self.can_add_to_service = True |
95 | |
96 | def retranslate_ui(self): |
97 | """ |
98 | @@ -183,11 +186,14 @@ |
99 | if self.has_delete_icon: |
100 | toolbar_actions.append(['Delete', StringContent.Delete, UiIcons().delete, self.on_delete_click]) |
101 | # Preview |
102 | - toolbar_actions.append(['Preview', StringContent.Preview, UiIcons().preview, self.on_preview_click]) |
103 | + if self.can_preview: |
104 | + toolbar_actions.append(['Preview', StringContent.Preview, UiIcons().preview, self.on_preview_click]) |
105 | # Live Button |
106 | - toolbar_actions.append(['Live', StringContent.Live, UiIcons().live, self.on_live_click]) |
107 | + if self.can_make_live: |
108 | + toolbar_actions.append(['Live', StringContent.Live, UiIcons().live, self.on_live_click]) |
109 | # Add to service Button |
110 | - toolbar_actions.append(['Service', StringContent.Service, UiIcons().add, self.on_add_click]) |
111 | + if self.can_add_to_service: |
112 | + toolbar_actions.append(['Service', StringContent.Service, UiIcons().add, self.on_add_click]) |
113 | for action in toolbar_actions: |
114 | if action[0] == StringContent.Preview: |
115 | self.toolbar.addSeparator() |
116 | @@ -211,27 +217,30 @@ |
117 | icon=UiIcons().edit, |
118 | triggers=self.on_edit_click) |
119 | create_widget_action(self.list_view, separator=True) |
120 | - create_widget_action(self.list_view, |
121 | - 'listView{plugin}{preview}Item'.format(plugin=self.plugin.name.title(), |
122 | - preview=StringContent.Preview.title()), |
123 | - text=self.plugin.get_string(StringContent.Preview)['title'], |
124 | - icon=UiIcons().preview, |
125 | - can_shortcuts=True, |
126 | - triggers=self.on_preview_click) |
127 | - create_widget_action(self.list_view, |
128 | - 'listView{plugin}{live}Item'.format(plugin=self.plugin.name.title(), |
129 | - live=StringContent.Live.title()), |
130 | - text=self.plugin.get_string(StringContent.Live)['title'], |
131 | - icon=UiIcons().live, |
132 | - can_shortcuts=True, |
133 | - triggers=self.on_live_click) |
134 | - create_widget_action(self.list_view, |
135 | - 'listView{plugin}{service}Item'.format(plugin=self.plugin.name.title(), |
136 | - service=StringContent.Service.title()), |
137 | - can_shortcuts=True, |
138 | - text=self.plugin.get_string(StringContent.Service)['title'], |
139 | - icon=UiIcons().add, |
140 | - triggers=self.on_add_click) |
141 | + if self.can_preview: |
142 | + create_widget_action(self.list_view, |
143 | + 'listView{plugin}{preview}Item'.format(plugin=self.plugin.name.title(), |
144 | + preview=StringContent.Preview.title()), |
145 | + text=self.plugin.get_string(StringContent.Preview)['title'], |
146 | + icon=UiIcons().preview, |
147 | + can_shortcuts=True, |
148 | + triggers=self.on_preview_click) |
149 | + if self.can_make_live: |
150 | + create_widget_action(self.list_view, |
151 | + 'listView{plugin}{live}Item'.format(plugin=self.plugin.name.title(), |
152 | + live=StringContent.Live.title()), |
153 | + text=self.plugin.get_string(StringContent.Live)['title'], |
154 | + icon=UiIcons().live, |
155 | + can_shortcuts=True, |
156 | + triggers=self.on_live_click) |
157 | + if self.can_add_to_service: |
158 | + create_widget_action(self.list_view, |
159 | + 'listView{plugin}{service}Item'.format(plugin=self.plugin.name.title(), |
160 | + service=StringContent.Service.title()), |
161 | + can_shortcuts=True, |
162 | + text=self.plugin.get_string(StringContent.Service)['title'], |
163 | + icon=UiIcons().add, |
164 | + triggers=self.on_add_click) |
165 | if self.has_delete_icon: |
166 | create_widget_action(self.list_view, separator=True) |
167 | create_widget_action(self.list_view, |
168 | @@ -462,10 +471,12 @@ |
169 | Allows the list click action to be determined dynamically |
170 | """ |
171 | if Settings().value('advanced/double click live'): |
172 | - self.on_live_click() |
173 | + if self.can_make_live: |
174 | + self.on_live_click() |
175 | elif not Settings().value('advanced/single click preview'): |
176 | # NOTE: The above check is necessary to prevent bug #1419300 |
177 | - self.on_preview_click() |
178 | + if self.can_preview: |
179 | + self.on_preview_click() |
180 | |
181 | def on_selection_change(self): |
182 | """ |
183 | |
184 | === modified file 'openlp/core/lib/plugin.py' |
185 | --- openlp/core/lib/plugin.py 2018-10-02 04:39:42 +0000 |
186 | +++ openlp/core/lib/plugin.py 2019-01-27 20:26:59 +0000 |
187 | @@ -24,11 +24,9 @@ |
188 | """ |
189 | import logging |
190 | |
191 | -from PyQt5 import QtCore |
192 | - |
193 | from openlp.core.common.i18n import UiStrings |
194 | from openlp.core.common.mixins import RegistryProperties |
195 | -from openlp.core.common.registry import Registry |
196 | +from openlp.core.common.registry import Registry, RegistryBase |
197 | from openlp.core.common.settings import Settings |
198 | from openlp.core.version import get_version |
199 | |
200 | @@ -61,7 +59,7 @@ |
201 | VisibleName = 'visible_name' |
202 | |
203 | |
204 | -class Plugin(QtCore.QObject, RegistryProperties): |
205 | +class Plugin(RegistryBase, RegistryProperties): |
206 | """ |
207 | Base class for openlp plugins to inherit from. |
208 | |
209 | @@ -326,6 +324,9 @@ |
210 | """ |
211 | return self.text_strings[name] |
212 | |
213 | + def set_plugin_text_strings(self): |
214 | + pass |
215 | + |
216 | def set_plugin_ui_text_strings(self, tooltips): |
217 | """ |
218 | Called to define all translatable texts of the plugin |
219 | |
220 | === modified file 'openlp/core/lib/pluginmanager.py' |
221 | --- openlp/core/lib/pluginmanager.py 2018-09-07 14:59:21 +0000 |
222 | +++ openlp/core/lib/pluginmanager.py 2019-01-27 20:26:59 +0000 |
223 | @@ -26,9 +26,10 @@ |
224 | |
225 | from PyQt5 import QtWidgets |
226 | |
227 | +from openlp.core.state import State |
228 | from openlp.core.common import extension_loader |
229 | from openlp.core.common.applocation import AppLocation |
230 | -from openlp.core.common.i18n import UiStrings |
231 | +from openlp.core.common.i18n import translate, UiStrings |
232 | from openlp.core.common.mixins import LogMixin, RegistryProperties |
233 | from openlp.core.common.registry import RegistryBase |
234 | from openlp.core.lib.plugin import Plugin, PluginStatus |
235 | @@ -53,11 +54,22 @@ |
236 | def bootstrap_initialise(self): |
237 | """ |
238 | Bootstrap all the plugin manager functions |
239 | - """ |
240 | - self.find_plugins() |
241 | - # hook methods have to happen after find_plugins. Find plugins needs |
242 | - # the controllers hence the hooks have moved from setupUI() to here |
243 | - # Find and insert settings tabs |
244 | + Scan a directory for objects inheriting from the ``Plugin`` class. |
245 | + """ |
246 | + glob_pattern = os.path.join('plugins', '*', '[!.]*plugin.py') |
247 | + extension_loader(glob_pattern) |
248 | + plugin_classes = Plugin.__subclasses__() |
249 | + for p in plugin_classes: |
250 | + try: |
251 | + p() |
252 | + self.log_debug('Loaded plugin {plugin}'.format(plugin=str(p))) |
253 | + except TypeError: |
254 | + self.log_exception('Failed to load plugin {plugin}'.format(plugin=str(p))) |
255 | + |
256 | + def bootstrap_post_set_up(self): |
257 | + """ |
258 | + Bootstrap all the plugin manager functions |
259 | + """ |
260 | self.hook_settings_tabs() |
261 | # Find and insert media manager items |
262 | self.hook_media_manager() |
263 | @@ -70,36 +82,23 @@ |
264 | # Call the initialise method to setup plugins. |
265 | self.initialise_plugins() |
266 | |
267 | - def find_plugins(self): |
268 | - """ |
269 | - Scan a directory for objects inheriting from the ``Plugin`` class. |
270 | - """ |
271 | - glob_pattern = os.path.join('plugins', '*', '[!.]*plugin.py') |
272 | - extension_loader(glob_pattern) |
273 | - plugin_classes = Plugin.__subclasses__() |
274 | - plugin_objects = [] |
275 | - for p in plugin_classes: |
276 | - try: |
277 | - plugin = p() |
278 | - self.log_debug('Loaded plugin {plugin}'.format(plugin=str(p))) |
279 | - plugin_objects.append(plugin) |
280 | - except TypeError: |
281 | - self.log_exception('Failed to load plugin {plugin}'.format(plugin=str(p))) |
282 | - plugins_list = sorted(plugin_objects, key=lambda plugin: plugin.weight) |
283 | - for plugin in plugins_list: |
284 | - if plugin.check_pre_conditions(): |
285 | - self.log_debug('Plugin {plugin} active'.format(plugin=str(plugin.name))) |
286 | - plugin.set_status() |
287 | - else: |
288 | - plugin.status = PluginStatus.Disabled |
289 | - self.plugins.append(plugin) |
290 | + def bootstrap_completion(self): |
291 | + """ |
292 | + Give all the plugins a chance to perform some tasks at startup |
293 | + """ |
294 | + self.application.process_events() |
295 | + for plugin in State().list_plugins(): |
296 | + if plugin and plugin.is_active(): |
297 | + plugin.app_startup() |
298 | + self.application.process_events() |
299 | |
300 | - def hook_media_manager(self): |
301 | + @staticmethod |
302 | + def hook_media_manager(): |
303 | """ |
304 | Create the plugins' media manager items. |
305 | """ |
306 | - for plugin in self.plugins: |
307 | - if plugin.status is not PluginStatus.Disabled: |
308 | + for plugin in State().list_plugins(): |
309 | + if plugin and plugin.status is not PluginStatus.Disabled: |
310 | plugin.create_media_manager_item() |
311 | |
312 | def hook_settings_tabs(self): |
313 | @@ -109,8 +108,8 @@ |
314 | Tabs are set for all plugins not just Active ones |
315 | |
316 | """ |
317 | - for plugin in self.plugins: |
318 | - if plugin.status is not PluginStatus.Disabled: |
319 | + for plugin in State().list_plugins(): |
320 | + if plugin and plugin.status is not PluginStatus.Disabled: |
321 | plugin.create_settings_tab(self.settings_form) |
322 | |
323 | def hook_import_menu(self): |
324 | @@ -119,8 +118,8 @@ |
325 | item to the import menu. |
326 | |
327 | """ |
328 | - for plugin in self.plugins: |
329 | - if plugin.status is not PluginStatus.Disabled: |
330 | + for plugin in State().list_plugins(): |
331 | + if plugin and plugin.status is not PluginStatus.Disabled: |
332 | plugin.add_import_menu_item(self.main_window.file_import_menu) |
333 | |
334 | def hook_export_menu(self): |
335 | @@ -128,8 +127,8 @@ |
336 | Loop through all the plugins and give them an opportunity to add an |
337 | item to the export menu. |
338 | """ |
339 | - for plugin in self.plugins: |
340 | - if plugin.status is not PluginStatus.Disabled: |
341 | + for plugin in State().list_plugins(): |
342 | + if plugin and plugin.status is not PluginStatus.Disabled: |
343 | plugin.add_export_menu_item(self.main_window.file_export_menu) |
344 | |
345 | def hook_tools_menu(self): |
346 | @@ -137,18 +136,19 @@ |
347 | Loop through all the plugins and give them an opportunity to add an |
348 | item to the tools menu. |
349 | """ |
350 | - for plugin in self.plugins: |
351 | - if plugin.status is not PluginStatus.Disabled: |
352 | + for plugin in State().list_plugins(): |
353 | + if plugin and plugin.status is not PluginStatus.Disabled: |
354 | plugin.add_tools_menu_item(self.main_window.tools_menu) |
355 | |
356 | - def hook_upgrade_plugin_settings(self, settings): |
357 | + @staticmethod |
358 | + def hook_upgrade_plugin_settings(settings): |
359 | """ |
360 | Loop through all the plugins and give them an opportunity to upgrade their settings. |
361 | |
362 | :param settings: The Settings object containing the old settings. |
363 | """ |
364 | - for plugin in self.plugins: |
365 | - if plugin.status is not PluginStatus.Disabled: |
366 | + for plugin in State().list_plugins(): |
367 | + if plugin and plugin.status is not PluginStatus.Disabled: |
368 | plugin.upgrade_settings(settings) |
369 | |
370 | def initialise_plugins(self): |
371 | @@ -156,43 +156,55 @@ |
372 | Loop through all the plugins and give them an opportunity to initialise themselves. |
373 | """ |
374 | uninitialised_plugins = [] |
375 | - for plugin in self.plugins: |
376 | - self.log_info('initialising plugins {plugin} in a {state} state'.format(plugin=plugin.name, |
377 | - state=plugin.is_active())) |
378 | - if plugin.is_active(): |
379 | - try: |
380 | - plugin.initialise() |
381 | - self.log_info('Initialisation Complete for {plugin}'.format(plugin=plugin.name)) |
382 | - except Exception: |
383 | - uninitialised_plugins.append(plugin.name.title()) |
384 | - self.log_exception('Unable to initialise plugin {plugin}'.format(plugin=plugin.name)) |
385 | + |
386 | + for plugin in State().list_plugins(): |
387 | + if plugin: |
388 | + self.log_info('initialising plugins {plugin} in a {state} state'.format(plugin=plugin.name, |
389 | + state=plugin.is_active())) |
390 | + if plugin.is_active(): |
391 | + try: |
392 | + plugin.initialise() |
393 | + self.log_info('Initialisation Complete for {plugin}'.format(plugin=plugin.name)) |
394 | + except Exception: |
395 | + uninitialised_plugins.append(plugin.name.title()) |
396 | + self.log_exception('Unable to initialise plugin {plugin}'.format(plugin=plugin.name)) |
397 | + display_text = '' |
398 | + |
399 | if uninitialised_plugins: |
400 | - QtWidgets.QMessageBox.critical(None, UiStrings().Error, 'Unable to initialise the following plugins:\n' + |
401 | - '\n'.join(uninitialised_plugins) + '\n\nSee the log file for more details', |
402 | + display_text = translate('OpenLP.PluginManager', 'Unable to initialise the following plugins:') + \ |
403 | + '\n\n'.join(uninitialised_plugins) + '\n\n' |
404 | + error_text = State().get_text() |
405 | + if error_text: |
406 | + display_text = display_text + error_text + '\n' |
407 | + if display_text: |
408 | + display_text = display_text + translate('OpenLP.PluginManager', 'See the log file for more details') |
409 | + QtWidgets.QMessageBox.critical(None, UiStrings().Error, display_text, |
410 | QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok)) |
411 | |
412 | def finalise_plugins(self): |
413 | """ |
414 | Loop through all the plugins and give them an opportunity to clean themselves up |
415 | """ |
416 | - for plugin in self.plugins: |
417 | - if plugin.is_active(): |
418 | + for plugin in State().list_plugins(): |
419 | + if plugin and plugin.is_active(): |
420 | plugin.finalise() |
421 | self.log_info('Finalisation Complete for {plugin}'.format(plugin=plugin.name)) |
422 | |
423 | - def get_plugin_by_name(self, name): |
424 | + @staticmethod |
425 | + def get_plugin_by_name(name): |
426 | """ |
427 | Return the plugin which has a name with value ``name``. |
428 | """ |
429 | - for plugin in self.plugins: |
430 | - if plugin.name == name: |
431 | + for plugin in State().list_plugins(): |
432 | + if plugin and plugin.name == name: |
433 | return plugin |
434 | return None |
435 | |
436 | - def new_service_created(self): |
437 | + @staticmethod |
438 | + def new_service_created(): |
439 | """ |
440 | Loop through all the plugins and give them an opportunity to handle a new service |
441 | """ |
442 | - for plugin in self.plugins: |
443 | + for plugin in State().list_plugins(): |
444 | if plugin.is_active(): |
445 | plugin.new_service_created() |
446 | |
447 | === modified file 'openlp/core/lib/serviceitem.py' |
448 | --- openlp/core/lib/serviceitem.py 2018-12-01 05:52:49 +0000 |
449 | +++ openlp/core/lib/serviceitem.py 2019-01-27 20:26:59 +0000 |
450 | @@ -32,6 +32,7 @@ |
451 | |
452 | from PyQt5 import QtGui |
453 | |
454 | +from openlp.core.state import State |
455 | from openlp.core.common import md5_hash |
456 | from openlp.core.common.applocation import AppLocation |
457 | from openlp.core.common.i18n import translate |
458 | @@ -348,7 +349,7 @@ |
459 | self.processor = header.get('processor', None) |
460 | self.has_original_files = True |
461 | self.metadata = header.get('item_meta_data', []) |
462 | - if 'background_audio' in header: |
463 | + if 'background_audio' in header and State().check_preconditions('media'): |
464 | self.background_audio = [] |
465 | for file_path in header['background_audio']: |
466 | # In OpenLP 3.0 we switched to storing Path objects in JSON files |
467 | @@ -525,6 +526,10 @@ |
468 | path_from = frame['path'] |
469 | else: |
470 | path_from = os.path.join(frame['path'], frame['title']) |
471 | + if isinstance(path_from, str): |
472 | + # Handle service files prior to OpenLP 3.0 |
473 | + # Windows can handle both forward and backward slashes, so we use ntpath to get the basename |
474 | + path_from = Path(path_from) |
475 | return path_from |
476 | |
477 | def remove_frame(self, frame): |
478 | @@ -593,7 +598,7 @@ |
479 | self.is_valid = False |
480 | break |
481 | elif self.is_command(): |
482 | - if self.is_capable(ItemCapabilities.IsOptical): |
483 | + if self.is_capable(ItemCapabilities.IsOptical) and State().check_preconditions('media'): |
484 | if not os.path.exists(slide['title']): |
485 | self.is_valid = False |
486 | break |
487 | |
488 | === added file 'openlp/core/loader.py' |
489 | --- openlp/core/loader.py 1970-01-01 00:00:00 +0000 |
490 | +++ openlp/core/loader.py 2019-01-27 20:26:59 +0000 |
491 | @@ -0,0 +1,48 @@ |
492 | +# -*- coding: utf-8 -*- |
493 | +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 |
494 | + |
495 | +############################################################################### |
496 | +# OpenLP - Open Source Lyrics Projection # |
497 | +# --------------------------------------------------------------------------- # |
498 | +# Copyright (c) 2008-2018 OpenLP Developers # |
499 | +# --------------------------------------------------------------------------- # |
500 | +# This program is free software; you can redistribute it and/or modify it # |
501 | +# under the terms of the GNU General Public License as published by the Free # |
502 | +# Software Foundation; version 2 of the License. # |
503 | +# # |
504 | +# This program is distributed in the hope that it will be useful, but WITHOUT # |
505 | +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # |
506 | +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # |
507 | +# more details. # |
508 | +# # |
509 | +# You should have received a copy of the GNU General Public License along # |
510 | +# with this program; if not, write to the Free Software Foundation, Inc., 59 # |
511 | +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
512 | +############################################################################### |
513 | +""" |
514 | +The :mod:`~openlp.core.loader` module provides a bootstrap for the singleton classes |
515 | +""" |
516 | + |
517 | +from openlp.core.state import State |
518 | +from openlp.core.ui.media.mediacontroller import MediaController |
519 | +from openlp.core.lib.pluginmanager import PluginManager |
520 | +from openlp.core.display.render import Renderer |
521 | +from openlp.core.lib.imagemanager import ImageManager |
522 | +from openlp.core.ui.slidecontroller import LiveController, PreviewController |
523 | + |
524 | + |
525 | +def loader(): |
526 | + """ |
527 | + God class to load all the components which are registered with the Registry |
528 | + |
529 | + :return: None |
530 | + """ |
531 | + State().load_settings() |
532 | + MediaController() |
533 | + PluginManager() |
534 | + # Set up the path with plugins |
535 | + ImageManager() |
536 | + Renderer() |
537 | + # Create slide controllers |
538 | + PreviewController() |
539 | + LiveController() |
540 | |
541 | === added file 'openlp/core/state.py' |
542 | --- openlp/core/state.py 1970-01-01 00:00:00 +0000 |
543 | +++ openlp/core/state.py 2019-01-27 20:26:59 +0000 |
544 | @@ -0,0 +1,175 @@ |
545 | +# -*- coding: utf-8 -*- |
546 | +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 |
547 | + |
548 | +############################################################################### |
549 | +# OpenLP - Open Source Lyrics Projection # |
550 | +# --------------------------------------------------------------------------- # |
551 | +# Copyright (c) 2008-2018 OpenLP Developers # |
552 | +# --------------------------------------------------------------------------- # |
553 | +# This program is free software; you can redistribute it and/or modify it # |
554 | +# under the terms of the GNU General Public License as published by the Free # |
555 | +# Software Foundation; version 2 of the License. # |
556 | +# # |
557 | +# This program is distributed in the hope that it will be useful, but WITHOUT # |
558 | +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # |
559 | +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # |
560 | +# more details. # |
561 | +# # |
562 | +# You should have received a copy of the GNU General Public License along # |
563 | +# with this program; if not, write to the Free Software Foundation, Inc., 59 # |
564 | +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
565 | +############################################################################### |
566 | + |
567 | +""" |
568 | +The :mod:`core` module provides state management |
569 | + |
570 | +All the core functions of the OpenLP application including the GUI, settings, logging and a plugin framework are |
571 | +contained within the openlp.core module. |
572 | +""" |
573 | +import logging |
574 | + |
575 | +from openlp.core.common.registry import Registry |
576 | +from openlp.core.common.mixins import LogMixin |
577 | +from openlp.core.lib.plugin import PluginStatus |
578 | + |
579 | + |
580 | +log = logging.getLogger() |
581 | + |
582 | + |
583 | +class StateModule(LogMixin): |
584 | + def __init__(self): |
585 | + """ |
586 | + Holder of State information per module |
587 | + """ |
588 | + super(StateModule, self).__init__() |
589 | + self.name = None |
590 | + self.order = 0 |
591 | + self.is_plugin = None |
592 | + self.status = PluginStatus.Inactive |
593 | + self.pass_preconditions = False |
594 | + self.requires = None |
595 | + self.required_by = None |
596 | + self.text = None |
597 | + |
598 | + |
599 | +class State(LogMixin): |
600 | + |
601 | + __instance__ = None |
602 | + |
603 | + def __new__(cls): |
604 | + """ |
605 | + Re-implement the __new__ method to make sure we create a true singleton. |
606 | + """ |
607 | + if not cls.__instance__: |
608 | + cls.__instance__ = object.__new__(cls) |
609 | + return cls.__instance__ |
610 | + |
611 | + def load_settings(self): |
612 | + self.modules = {} |
613 | + |
614 | + def save_settings(self): |
615 | + pass |
616 | + |
617 | + def add_service(self, name, order, is_plugin=False, status=PluginStatus.Active, requires=None): |
618 | + """ |
619 | + Add a module to the array and load dependencies. There will only be one item per module |
620 | + :param name: Module name |
621 | + :param order: Order to display |
622 | + :param is_plugin: Am I a plugin |
623 | + :param status: The active status |
624 | + :param requires: Module name this requires |
625 | + :return: |
626 | + """ |
627 | + if name not in self.modules: |
628 | + state = StateModule() |
629 | + state.name = name |
630 | + state.order = order |
631 | + state.is_plugin = is_plugin |
632 | + state.status = status |
633 | + state.requires = requires |
634 | + state.required_by = [] |
635 | + self.modules[name] = state |
636 | + if requires and requires in self.modules: |
637 | + if requires not in self.modules[requires].required_by: |
638 | + self.modules[requires].required_by.append(name) |
639 | + |
640 | + def missing_text(self, name, text): |
641 | + """ |
642 | + Updates the preconditions state of a module |
643 | + |
644 | + :param name: Module name |
645 | + :param text: Module missing text |
646 | + :return: |
647 | + """ |
648 | + self.modules[name].text = text |
649 | + |
650 | + def get_text(self): |
651 | + """ |
652 | + return an string of error text |
653 | + :return: a string of text |
654 | + """ |
655 | + error_text = '' |
656 | + for mod in self.modules: |
657 | + if self.modules[mod].text: |
658 | + error_text = error_text + self.modules[mod].text + '\n' |
659 | + return error_text |
660 | + |
661 | + def update_pre_conditions(self, name, status): |
662 | + """ |
663 | + Updates the preconditions state of a module |
664 | + |
665 | + :param name: Module name |
666 | + :param status: Module new status |
667 | + :return: |
668 | + """ |
669 | + self.modules[name].pass_preconditions = status |
670 | + if self.modules[name].is_plugin: |
671 | + plugin = Registry().get('{mod}_plugin'.format(mod=name)) |
672 | + if status: |
673 | + self.log_debug('Plugin {plugin} active'.format(plugin=str(plugin.name))) |
674 | + plugin.set_status() |
675 | + else: |
676 | + plugin.status = PluginStatus.Disabled |
677 | + |
678 | + def flush_preconditions(self): |
679 | + """ |
680 | + Now all modules are loaded lets update all the preconditions. |
681 | + |
682 | + :return: |
683 | + """ |
684 | + for mods in self.modules: |
685 | + for req in self.modules[mods].required_by: |
686 | + self.modules[req].pass_preconditions = self.modules[mods].pass_preconditions |
687 | + plugins_list = sorted(self.modules, key=lambda state: self.modules[state].order) |
688 | + mdl = {} |
689 | + for pl in plugins_list: |
690 | + mdl[pl] = self.modules[pl] |
691 | + self.modules = mdl |
692 | + |
693 | + def is_module_active(self, name): |
694 | + return self.modules[name].status == PluginStatus.Active |
695 | + |
696 | + def check_preconditions(self, name): |
697 | + """ |
698 | + Checks if a modules preconditions have been met. |
699 | + |
700 | + :param name: Module name |
701 | + :return: Have the preconditions been met. |
702 | + :rtype: bool |
703 | + """ |
704 | + if self.modules[name].requires is None: |
705 | + return self.modules[name].pass_preconditions |
706 | + else: |
707 | + mod = self.modules[name].requires |
708 | + return self.modules[mod].pass_preconditions |
709 | + |
710 | + def list_plugins(self): |
711 | + """ |
712 | + Return a list of plugins |
713 | + :return: an array of plugins |
714 | + """ |
715 | + plugins = [] |
716 | + for mod in self.modules: |
717 | + if self.modules[mod].is_plugin: |
718 | + plugins.append(Registry().get('{mod}_plugin'.format(mod=mod))) |
719 | + return plugins |
720 | |
721 | === modified file 'openlp/core/ui/icons.py' |
722 | --- openlp/core/ui/icons.py 2018-10-30 19:46:55 +0000 |
723 | +++ openlp/core/ui/icons.py 2019-01-27 20:26:59 +0000 |
724 | @@ -79,7 +79,7 @@ |
725 | 'book': {'icon': 'fa.book'}, |
726 | 'bottom': {'icon': 'fa.angle-double-down'}, |
727 | 'box': {'icon': 'fa.briefcase'}, |
728 | - 'clapperboard': {'icon': 'fa.chess-board'}, |
729 | + 'clapperboard': {'icon': 'fa.film'}, |
730 | 'clock': {'icon': 'fa.clock-o'}, |
731 | 'clone': {'icon': 'fa.clone'}, |
732 | 'close': {'icon': 'fa.times-circle-o'}, |
733 | |
734 | === modified file 'openlp/core/ui/mainwindow.py' |
735 | --- openlp/core/ui/mainwindow.py 2018-10-30 19:46:55 +0000 |
736 | +++ openlp/core/ui/mainwindow.py 2019-01-27 20:26:59 +0000 |
737 | @@ -30,6 +30,7 @@ |
738 | |
739 | from PyQt5 import QtCore, QtGui, QtWidgets |
740 | |
741 | +from openlp.core.state import State |
742 | from openlp.core.api import websockets |
743 | from openlp.core.api.http import server |
744 | from openlp.core.common import add_actions, is_macosx, is_win |
745 | @@ -41,23 +42,18 @@ |
746 | from openlp.core.common.registry import Registry |
747 | from openlp.core.common.settings import Settings |
748 | from openlp.core.display.screens import ScreenList |
749 | -from openlp.core.lib.imagemanager import ImageManager |
750 | -from openlp.core.display.render import Renderer |
751 | from openlp.core.lib.plugin import PluginStatus |
752 | -from openlp.core.lib.pluginmanager import PluginManager |
753 | from openlp.core.lib.ui import create_action |
754 | from openlp.core.projectors.manager import ProjectorManager |
755 | from openlp.core.ui.aboutform import AboutForm |
756 | from openlp.core.ui.firsttimeform import FirstTimeForm |
757 | from openlp.core.ui.formattingtagform import FormattingTagForm |
758 | from openlp.core.ui.icons import UiIcons |
759 | -from openlp.core.ui.media.mediacontroller import MediaController |
760 | from openlp.core.ui.pluginform import PluginForm |
761 | from openlp.core.ui.printserviceform import PrintServiceForm |
762 | from openlp.core.ui.servicemanager import ServiceManager |
763 | from openlp.core.ui.settingsform import SettingsForm |
764 | from openlp.core.ui.shortcutlistform import ShortcutListForm |
765 | -from openlp.core.ui.slidecontroller import LiveController, PreviewController |
766 | from openlp.core.ui.style import PROGRESSBAR_STYLE, get_library_stylesheet |
767 | from openlp.core.ui.thememanager import ThemeManager |
768 | from openlp.core.version import get_version |
769 | @@ -90,9 +86,6 @@ |
770 | self.control_splitter.setOrientation(QtCore.Qt.Horizontal) |
771 | self.control_splitter.setObjectName('control_splitter') |
772 | self.main_content_layout.addWidget(self.control_splitter) |
773 | - # Create slide controllers |
774 | - PreviewController(self) |
775 | - LiveController(self) |
776 | preview_visible = Settings().value('user interface/preview panel') |
777 | live_visible = Settings().value('user interface/live panel') |
778 | panel_locked = Settings().value('user interface/lock panel') |
779 | @@ -501,16 +494,11 @@ |
780 | self.copy_data = False |
781 | Settings().set_up_default_values() |
782 | self.about_form = AboutForm(self) |
783 | - MediaController() |
784 | self.ws_server = websockets.WebSocketServer() |
785 | self.http_server = server.HttpServer(self) |
786 | SettingsForm(self) |
787 | self.formatting_tag_form = FormattingTagForm(self) |
788 | self.shortcut_form = ShortcutListForm(self) |
789 | - # Set up the path with plugins |
790 | - PluginManager(self) |
791 | - ImageManager() |
792 | - Renderer() |
793 | # Set up the interface |
794 | self.setup_ui(self) |
795 | # Define the media Dock Manager |
796 | @@ -660,22 +648,12 @@ |
797 | self.set_view_mode(False, True, False, False, True, True) |
798 | self.mode_live_item.setChecked(True) |
799 | |
800 | - def app_startup(self): |
801 | - """ |
802 | - Give all the plugins a chance to perform some tasks at startup |
803 | - """ |
804 | - self.application.process_events() |
805 | - for plugin in self.plugin_manager.plugins: |
806 | - if plugin.is_active(): |
807 | - plugin.app_startup() |
808 | - self.application.process_events() |
809 | - |
810 | def first_time(self): |
811 | """ |
812 | Import themes if first time |
813 | """ |
814 | self.application.process_events() |
815 | - for plugin in self.plugin_manager.plugins: |
816 | + for plugin in State().list_plugins(): |
817 | if hasattr(plugin, 'first_time'): |
818 | self.application.process_events() |
819 | plugin.first_time() |
820 | @@ -713,7 +691,7 @@ |
821 | self.projector_manager_dock.setVisible(True) |
822 | else: |
823 | self.projector_manager_dock.setVisible(False) |
824 | - for plugin in self.plugin_manager.plugins: |
825 | + for plugin in State().list_plugins(): |
826 | self.active_plugin = plugin |
827 | old_status = self.active_plugin.status |
828 | self.active_plugin.set_status() |
829 | @@ -880,7 +858,7 @@ |
830 | setting_sections.extend([self.header_section]) |
831 | setting_sections.extend(['crashreport']) |
832 | # Add plugin sections. |
833 | - setting_sections.extend([plugin.name for plugin in self.plugin_manager.plugins]) |
834 | + setting_sections.extend([plugin.name for plugin in State().list_plugins()]) |
835 | # Copy the settings file to the tmp dir, because we do not want to change the original one. |
836 | temp_dir_path = Path(gettempdir(), 'openlp') |
837 | create_paths(temp_dir_path) |
838 | |
839 | === modified file 'openlp/core/ui/media/__init__.py' |
840 | --- openlp/core/ui/media/__init__.py 2018-10-27 01:40:20 +0000 |
841 | +++ openlp/core/ui/media/__init__.py 2019-01-27 20:26:59 +0000 |
842 | @@ -24,10 +24,6 @@ |
843 | """ |
844 | import logging |
845 | |
846 | -from PyQt5 import QtCore |
847 | - |
848 | -from openlp.core.common.settings import Settings |
849 | - |
850 | log = logging.getLogger(__name__ + '.__init__') |
851 | |
852 | |
853 | @@ -54,7 +50,7 @@ |
854 | Folder = 5 |
855 | |
856 | |
857 | -class MediaInfo(object): |
858 | +class ItemMediaInfo(object): |
859 | """ |
860 | This class hold the media related info |
861 | """ |
862 | @@ -73,39 +69,6 @@ |
863 | media_type = MediaType() |
864 | |
865 | |
866 | -def get_media_players(): |
867 | - """ |
868 | - This method extracts the configured media players and overridden player |
869 | - from the settings. |
870 | - """ |
871 | - log.debug('get_media_players') |
872 | - saved_players = Settings().value('media/players') |
873 | - reg_ex = QtCore.QRegExp(r'.*\[(.*)\].*') |
874 | - if Settings().value('media/override player') == QtCore.Qt.Checked: |
875 | - if reg_ex.exactMatch(saved_players): |
876 | - overridden_player = '{text}'.format(text=reg_ex.cap(1)) |
877 | - else: |
878 | - overridden_player = 'auto' |
879 | - else: |
880 | - overridden_player = '' |
881 | - saved_players_list = saved_players.replace('[', '').replace(']', '').split(',') if saved_players else [] |
882 | - return saved_players_list, overridden_player |
883 | - |
884 | - |
885 | -def set_media_players(players_list, overridden_player='auto'): |
886 | - """ |
887 | - This method saves the configured media players and overridden player to the settings |
888 | - |
889 | - :param players_list: A list with all active media players. |
890 | - :param overridden_player: Here an special media player is chosen for all media actions. |
891 | - """ |
892 | - log.debug('set_media_players') |
893 | - players = ','.join(players_list) |
894 | - if Settings().value('media/override player') == QtCore.Qt.Checked and overridden_player != 'auto': |
895 | - players = players.replace(overridden_player, '[{text}]'.format(text=overridden_player)) |
896 | - Settings().setValue('media/players', players) |
897 | - |
898 | - |
899 | def parse_optical_path(input_string): |
900 | """ |
901 | Split the optical path info. |
902 | |
903 | === modified file 'openlp/core/ui/media/mediacontroller.py' |
904 | --- openlp/core/ui/media/mediacontroller.py 2018-10-02 04:39:42 +0000 |
905 | +++ openlp/core/ui/media/mediacontroller.py 2019-01-27 20:26:59 +0000 |
906 | @@ -25,13 +25,19 @@ |
907 | """ |
908 | import datetime |
909 | import logging |
910 | -import os |
911 | - |
912 | + |
913 | +try: |
914 | + from pymediainfo import MediaInfo |
915 | + pymediainfo_available = True |
916 | +except ImportError: |
917 | + pymediainfo_available = False |
918 | + |
919 | +from subprocess import check_output |
920 | from PyQt5 import QtCore, QtWidgets |
921 | |
922 | +from openlp.core.state import State |
923 | from openlp.core.api.http import register_endpoint |
924 | -from openlp.core.common import extension_loader |
925 | -from openlp.core.common.i18n import UiStrings, translate |
926 | +from openlp.core.common.i18n import translate |
927 | from openlp.core.common.mixins import LogMixin, RegistryProperties |
928 | from openlp.core.common.registry import Registry, RegistryBase |
929 | from openlp.core.common.settings import Settings |
930 | @@ -39,11 +45,9 @@ |
931 | from openlp.core.lib.ui import critical_error_message_box |
932 | from openlp.core.ui import DisplayControllerType |
933 | from openlp.core.ui.icons import UiIcons |
934 | -from openlp.core.ui.media import MediaInfo, MediaState, MediaType, get_media_players, parse_optical_path, \ |
935 | - set_media_players |
936 | +from openlp.core.ui.media import MediaState, ItemMediaInfo, MediaType, parse_optical_path |
937 | from openlp.core.ui.media.endpoint import media_endpoint |
938 | -from openlp.core.ui.media.mediaplayer import MediaPlayer |
939 | -from openlp.core.ui.media.vendor.mediainfoWrapper import MediaInfoWrapper |
940 | +from openlp.core.ui.media.vlcplayer import VlcPlayer, get_vlc |
941 | from openlp.core.widgets.toolbar import OpenLPToolbar |
942 | |
943 | |
944 | @@ -63,7 +67,6 @@ |
945 | super(MediaSlider, self).__init__(direction) |
946 | self.manager = manager |
947 | self.controller = controller |
948 | - self.no_matching_player = translate('MediaPlugin.MediaItem', 'File %s not supported using player %s') |
949 | |
950 | def mouseMoveEvent(self, event): |
951 | """ |
952 | @@ -78,7 +81,6 @@ |
953 | def mousePressEvent(self, event): |
954 | """ |
955 | Mouse Press event no new functionality |
956 | - |
957 | :param event: The triggering event |
958 | """ |
959 | QtWidgets.QSlider.mousePressEvent(self, event) |
960 | @@ -111,7 +113,9 @@ |
961 | Constructor |
962 | """ |
963 | super(MediaController, self).__init__(parent) |
964 | - self.media_players = {} |
965 | + |
966 | + def setup(self): |
967 | + self.vlc_player = None |
968 | self.display_controllers = {} |
969 | self.current_media_players = {} |
970 | # Timer for video state |
971 | @@ -135,70 +139,40 @@ |
972 | Registry().register_function('songs_hide', self.media_hide) |
973 | Registry().register_function('songs_blank', self.media_blank) |
974 | Registry().register_function('songs_unblank', self.media_unblank) |
975 | - Registry().register_function('mediaitem_media_rebuild', self._set_active_players) |
976 | Registry().register_function('mediaitem_suffixes', self._generate_extensions_lists) |
977 | register_endpoint(media_endpoint) |
978 | |
979 | - def _set_active_players(self): |
980 | - """ |
981 | - Set the active players and available media files |
982 | - """ |
983 | - saved_players = get_media_players()[0] |
984 | - for player in list(self.media_players.keys()): |
985 | - self.media_players[player].is_active = player in saved_players |
986 | - |
987 | def _generate_extensions_lists(self): |
988 | """ |
989 | Set the active players and available media files |
990 | """ |
991 | suffix_list = [] |
992 | self.audio_extensions_list = [] |
993 | - for player in list(self.media_players.values()): |
994 | - if player.is_active: |
995 | - for item in player.audio_extensions_list: |
996 | - if item not in self.audio_extensions_list: |
997 | - self.audio_extensions_list.append(item) |
998 | - suffix_list.append(item[2:]) |
999 | + if self.vlc_player.is_active: |
1000 | + for item in self.vlc_player.audio_extensions_list: |
1001 | + if item not in self.audio_extensions_list: |
1002 | + self.audio_extensions_list.append(item) |
1003 | + suffix_list.append(item[2:]) |
1004 | self.video_extensions_list = [] |
1005 | - for player in list(self.media_players.values()): |
1006 | - if player.is_active: |
1007 | - for item in player.video_extensions_list: |
1008 | - if item not in self.video_extensions_list: |
1009 | - self.video_extensions_list.append(item) |
1010 | - suffix_list.append(item[2:]) |
1011 | + if self.vlc_player.is_active: |
1012 | + for item in self.vlc_player.video_extensions_list: |
1013 | + if item not in self.video_extensions_list: |
1014 | + self.video_extensions_list.append(item) |
1015 | + suffix_list.append(item[2:]) |
1016 | self.service_manager.supported_suffixes(suffix_list) |
1017 | |
1018 | - def register_players(self, player): |
1019 | - """ |
1020 | - Register each media Player (Webkit, Phonon, etc) and store |
1021 | - for later use |
1022 | - |
1023 | - :param player: Individual player class which has been enabled |
1024 | - """ |
1025 | - self.media_players[player.name] = player |
1026 | - |
1027 | def bootstrap_initialise(self): |
1028 | """ |
1029 | Check to see if we have any media Player's available. |
1030 | """ |
1031 | - controller_dir = os.path.join('core', 'ui', 'media') |
1032 | - # Find all files that do not begin with '.' (lp:#1738047) and end with player.py |
1033 | - glob_pattern = os.path.join(controller_dir, '[!.]*player.py') |
1034 | - extension_loader(glob_pattern, ['mediaplayer.py']) |
1035 | - player_classes = MediaPlayer.__subclasses__() |
1036 | - for player_class in player_classes: |
1037 | - self.register_players(player_class(self)) |
1038 | - if not self.media_players: |
1039 | - return False |
1040 | - saved_players, overridden_player = get_media_players() |
1041 | - invalid_media_players = \ |
1042 | - [media_player for media_player in saved_players if media_player not in self.media_players or |
1043 | - not self.media_players[media_player].check_available()] |
1044 | - if invalid_media_players: |
1045 | - for invalidPlayer in invalid_media_players: |
1046 | - saved_players.remove(invalidPlayer) |
1047 | - set_media_players(saved_players, overridden_player) |
1048 | - self._set_active_players() |
1049 | + self.setup() |
1050 | + self.vlc_player = VlcPlayer(self) |
1051 | + State().add_service("mediacontroller", 0) |
1052 | + if get_vlc() and pymediainfo_available: |
1053 | + State().update_pre_conditions("mediacontroller", True) |
1054 | + else: |
1055 | + State().missing_text("mediacontroller", translate('OpenLP.SlideController', |
1056 | + "VLC or pymediainfo are missing, so you are unable to play any media")) |
1057 | self._generate_extensions_lists() |
1058 | return True |
1059 | |
1060 | @@ -236,36 +210,6 @@ |
1061 | if self.display_controllers[DisplayControllerType.Preview].media_info.can_loop_playback: |
1062 | self.media_play(self.display_controllers[DisplayControllerType.Preview], True) |
1063 | |
1064 | - def get_media_display_css(self): |
1065 | - """ |
1066 | - Add css style sheets to htmlbuilder |
1067 | - """ |
1068 | - css = '' |
1069 | - for player in list(self.media_players.values()): |
1070 | - if player.is_active: |
1071 | - css += player.get_media_display_css() |
1072 | - return css |
1073 | - |
1074 | - def get_media_display_javascript(self): |
1075 | - """ |
1076 | - Add javascript functions to htmlbuilder |
1077 | - """ |
1078 | - js = '' |
1079 | - for player in list(self.media_players.values()): |
1080 | - if player.is_active: |
1081 | - js += player.get_media_display_javascript() |
1082 | - return js |
1083 | - |
1084 | - def get_media_display_html(self): |
1085 | - """ |
1086 | - Add html code to htmlbuilder |
1087 | - """ |
1088 | - html = '' |
1089 | - for player in list(self.media_players.values()): |
1090 | - if player.is_active: |
1091 | - html += player.get_media_display_html() |
1092 | - return html |
1093 | - |
1094 | def register_controller(self, controller): |
1095 | """ |
1096 | Registers media controls where the players will be placed to run. |
1097 | @@ -281,7 +225,7 @@ |
1098 | |
1099 | :param controller: First element is the controller which should be used |
1100 | """ |
1101 | - controller.media_info = MediaInfo() |
1102 | + controller.media_info = ItemMediaInfo() |
1103 | # Build a Media ToolBar |
1104 | controller.mediabar = OpenLPToolbar(controller) |
1105 | controller.mediabar.add_toolbar_action('playbackPlay', text='media_playback_play', |
1106 | @@ -345,16 +289,12 @@ |
1107 | """ |
1108 | # clean up possible running old media files |
1109 | self.finalise() |
1110 | - # update player status |
1111 | - self._set_active_players() |
1112 | display.has_audio = True |
1113 | if display.is_live and preview: |
1114 | return |
1115 | if preview: |
1116 | display.has_audio = False |
1117 | - for player in list(self.media_players.values()): |
1118 | - if player.is_active: |
1119 | - player.setup(display) |
1120 | + self.vlc_player.setup(display) |
1121 | |
1122 | def set_controls_visible(self, controller, value): |
1123 | """ |
1124 | @@ -367,8 +307,7 @@ |
1125 | controller.mediabar.setVisible(value) |
1126 | if controller.is_live and controller.display: |
1127 | if self.current_media_players and value: |
1128 | - if self.current_media_players[controller.controller_type] != self.media_players['webkit']: |
1129 | - controller.display.set_transparency(False) |
1130 | + controller.display.set_transparency(False) |
1131 | |
1132 | @staticmethod |
1133 | def resize(display, player): |
1134 | @@ -389,16 +328,19 @@ |
1135 | :param hidden: The player which is doing the playing |
1136 | :param video_behind_text: Is the video to be played behind text. |
1137 | """ |
1138 | - is_valid = False |
1139 | + is_valid = True |
1140 | controller = self.display_controllers[source] |
1141 | # stop running videos |
1142 | self.media_reset(controller) |
1143 | - controller.media_info = MediaInfo() |
1144 | + controller.media_info = ItemMediaInfo() |
1145 | controller.media_info.volume = controller.volume_slider.value() |
1146 | controller.media_info.is_background = video_behind_text |
1147 | # background will always loop video. |
1148 | controller.media_info.can_loop_playback = video_behind_text |
1149 | - controller.media_info.file_info = QtCore.QFileInfo(service_item.get_frame_path()) |
1150 | + if service_item.is_capable(ItemCapabilities.HasBackgroundAudio): |
1151 | + controller.media_info.file_info = service_item.background_audio |
1152 | + else: |
1153 | + controller.media_info.file_info = [service_item.get_frame_path()] |
1154 | display = self._define_display(controller) |
1155 | if controller.is_live: |
1156 | # if this is an optical device use special handling |
1157 | @@ -411,7 +353,7 @@ |
1158 | else: |
1159 | log.debug('video is not optical and live') |
1160 | controller.media_info.length = service_item.media_length |
1161 | - is_valid = self._check_file_type(controller, display, service_item) |
1162 | + is_valid = self._check_file_type(controller, display) |
1163 | display.override['theme'] = '' |
1164 | display.override['video'] = True |
1165 | if controller.media_info.is_background: |
1166 | @@ -431,7 +373,7 @@ |
1167 | else: |
1168 | log.debug('video is not optical and preview') |
1169 | controller.media_info.length = service_item.media_length |
1170 | - is_valid = self._check_file_type(controller, display, service_item) |
1171 | + is_valid = self._check_file_type(controller, display) |
1172 | if not is_valid: |
1173 | # Media could not be loaded correctly |
1174 | critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'), |
1175 | @@ -462,19 +404,21 @@ |
1176 | return True |
1177 | |
1178 | @staticmethod |
1179 | - def media_length(service_item): |
1180 | + def media_length(media_path): |
1181 | """ |
1182 | Uses Media Info to obtain the media length |
1183 | |
1184 | - :param service_item: The ServiceItem containing the details to be played. |
1185 | + :param media_path: The file path to be checked.. |
1186 | """ |
1187 | - media_info = MediaInfo() |
1188 | - media_info.volume = 0 |
1189 | - media_info.file_info = QtCore.QFileInfo(service_item.get_frame_path()) |
1190 | - media_data = MediaInfoWrapper.parse(service_item.get_frame_path()) |
1191 | + if MediaInfo.can_parse(): |
1192 | + media_data = MediaInfo.parse(media_path) |
1193 | + else: |
1194 | + xml = check_output(['mediainfo', '-f', '--Output=XML', '--Inform=OLDXML', media_path]) |
1195 | + if not xml.startswith(b'<?xml'): |
1196 | + xml = check_output(['mediainfo', '-f', '--Output=XML', media_path]) |
1197 | + media_data = MediaInfo(xml.decode("utf-8")) |
1198 | # duration returns in milli seconds |
1199 | - service_item.set_media_length(media_data.tracks[0].duration) |
1200 | - return True |
1201 | + return media_data.tracks[0].duration |
1202 | |
1203 | def media_setup_optical(self, filename, title, audio_track, subtitle_track, start, end, display, controller): |
1204 | """ |
1205 | @@ -493,7 +437,7 @@ |
1206 | # stop running videos |
1207 | self.media_reset(controller) |
1208 | # Setup media info |
1209 | - controller.media_info = MediaInfo() |
1210 | + controller.media_info = ItemMediaInfo() |
1211 | controller.media_info.file_info = QtCore.QFileInfo(filename) |
1212 | if audio_track == -1 and subtitle_track == -1: |
1213 | controller.media_info.media_type = MediaType.CD |
1214 | @@ -508,86 +452,49 @@ |
1215 | # When called from mediaitem display is None |
1216 | if display is None: |
1217 | display = controller.preview_display |
1218 | - # Find vlc player |
1219 | - used_players = get_media_players()[0] |
1220 | - vlc_player = None |
1221 | - for title in used_players: |
1222 | - player = self.media_players[title] |
1223 | - if player.name == 'vlc': |
1224 | - vlc_player = player |
1225 | - if vlc_player is None: |
1226 | - critical_error_message_box(translate('MediaPlugin.MediaItem', 'VLC player required'), |
1227 | - translate('MediaPlugin.MediaItem', |
1228 | - 'VLC player required for playback of optical devices')) |
1229 | - return False |
1230 | - vlc_player.load(display) |
1231 | - self.resize(display, vlc_player) |
1232 | - self.current_media_players[controller.controller_type] = vlc_player |
1233 | + self.vlc_player.load(display) |
1234 | + self.resize(display, self.vlc_player) |
1235 | + self.current_media_players[controller.controller_type] = self.vlc_player |
1236 | if audio_track == -1 and subtitle_track == -1: |
1237 | controller.media_info.media_type = MediaType.CD |
1238 | else: |
1239 | controller.media_info.media_type = MediaType.DVD |
1240 | return True |
1241 | |
1242 | - @staticmethod |
1243 | - def _get_used_players(service_item): |
1244 | - """ |
1245 | - Find the player for a given service item |
1246 | - |
1247 | - :param service_item: where the information is about the media and required player |
1248 | - :return: player description |
1249 | - """ |
1250 | - used_players = get_media_players()[0] |
1251 | - # If no player, we can't play |
1252 | - if not used_players: |
1253 | - return False |
1254 | - default_player = [used_players[0]] |
1255 | - if service_item.processor and service_item.processor != UiStrings().Automatic: |
1256 | - # check to see if the player is usable else use the default one. |
1257 | - if service_item.processor.lower() not in used_players: |
1258 | - used_players = default_player |
1259 | - else: |
1260 | - used_players = [service_item.processor.lower()] |
1261 | - return used_players |
1262 | - |
1263 | - def _check_file_type(self, controller, display, service_item): |
1264 | + def _check_file_type(self, controller, display): |
1265 | """ |
1266 | Select the correct media Player type from the prioritized Player list |
1267 | |
1268 | :param controller: First element is the controller which should be used |
1269 | :param display: Which display to use |
1270 | - :param service_item: The ServiceItem containing the details to be played. |
1271 | """ |
1272 | - used_players = self._get_used_players(service_item) |
1273 | - if controller.media_info.file_info.isFile(): |
1274 | - suffix = '*.%s' % controller.media_info.file_info.suffix().lower() |
1275 | - for title in used_players: |
1276 | - if not title: |
1277 | - continue |
1278 | - player = self.media_players[title] |
1279 | + for file in controller.media_info.file_info: |
1280 | + if file.is_file: |
1281 | + suffix = '*%s' % file.suffix.lower() |
1282 | + player = self.vlc_player |
1283 | + file = str(file) |
1284 | if suffix in player.video_extensions_list: |
1285 | if not controller.media_info.is_background or controller.media_info.is_background and \ |
1286 | player.can_background: |
1287 | self.resize(display, player) |
1288 | - if player.load(display): |
1289 | + if player.load(display, file): |
1290 | self.current_media_players[controller.controller_type] = player |
1291 | controller.media_info.media_type = MediaType.Video |
1292 | return True |
1293 | if suffix in player.audio_extensions_list: |
1294 | - if player.load(display): |
1295 | + if player.load(display, file): |
1296 | self.current_media_players[controller.controller_type] = player |
1297 | controller.media_info.media_type = MediaType.Audio |
1298 | return True |
1299 | - else: |
1300 | - for title in used_players: |
1301 | - player = self.media_players[title] |
1302 | + else: |
1303 | + player = self.vlc_player |
1304 | + file = str(file) |
1305 | if player.can_folder: |
1306 | self.resize(display, player) |
1307 | - if player.load(display): |
1308 | + if player.load(display, file): |
1309 | self.current_media_players[controller.controller_type] = player |
1310 | controller.media_info.media_type = MediaType.Video |
1311 | return True |
1312 | - # no valid player found |
1313 | return False |
1314 | |
1315 | def media_play_msg(self, msg, status=True): |
1316 | |
1317 | === modified file 'openlp/core/ui/media/mediaplayer.py' |
1318 | --- openlp/core/ui/media/mediaplayer.py 2017-12-29 09:15:48 +0000 |
1319 | +++ openlp/core/ui/media/mediaplayer.py 2019-01-27 20:26:59 +0000 |
1320 | @@ -60,11 +60,12 @@ |
1321 | """ |
1322 | pass |
1323 | |
1324 | - def load(self, display): |
1325 | + def load(self, display, file): |
1326 | """ |
1327 | Load a new media file and check if it is valid |
1328 | |
1329 | :param display: The display to be updated. |
1330 | + :param file: The file to be loaded |
1331 | """ |
1332 | return True |
1333 | |
1334 | |
1335 | === modified file 'openlp/core/ui/media/playertab.py' |
1336 | --- openlp/core/ui/media/playertab.py 2018-09-12 05:43:27 +0000 |
1337 | +++ openlp/core/ui/media/playertab.py 2019-01-27 20:26:59 +0000 |
1338 | @@ -32,7 +32,6 @@ |
1339 | from openlp.core.lib.settingstab import SettingsTab |
1340 | from openlp.core.lib.ui import create_button |
1341 | from openlp.core.ui.icons import UiIcons |
1342 | -from openlp.core.ui.media import get_media_players, set_media_players |
1343 | from openlp.core.widgets.buttons import ColorButton |
1344 | |
1345 | |
1346 | @@ -55,7 +54,7 @@ |
1347 | """ |
1348 | Constructor |
1349 | """ |
1350 | - self.media_players = Registry().get('media_controller').media_players |
1351 | + # self.media_players = Registry().get('media_controller').media_players |
1352 | self.saved_used_players = None |
1353 | self.icon_path = UiIcons().player |
1354 | player_translated = translate('OpenLP.PlayerTab', 'Players') |
1355 | @@ -202,7 +201,7 @@ |
1356 | """ |
1357 | if self.saved_used_players: |
1358 | self.used_players = self.saved_used_players |
1359 | - self.used_players = get_media_players()[0] |
1360 | + # self.used_players = get_media_players()[0] |
1361 | self.saved_used_players = self.used_players |
1362 | settings = Settings() |
1363 | settings.beginGroup(self.settings_section) |
1364 | @@ -220,13 +219,13 @@ |
1365 | settings.beginGroup(self.settings_section) |
1366 | settings.setValue('background color', self.background_color) |
1367 | settings.endGroup() |
1368 | - old_players, override_player = get_media_players() |
1369 | - if self.used_players != old_players: |
1370 | - # clean old Media stuff |
1371 | - set_media_players(self.used_players, override_player) |
1372 | - self.settings_form.register_post_process('mediaitem_suffix_reset') |
1373 | - self.settings_form.register_post_process('mediaitem_media_rebuild') |
1374 | - self.settings_form.register_post_process('config_screen_changed') |
1375 | + # old_players, override_player = get_media_players() |
1376 | + # if self.used_players != old_players: |
1377 | + # # clean old Media stuff |
1378 | + # set_media_players(self.used_players, override_player) |
1379 | + # self.settings_form.register_post_process('mediaitem_suffix_reset') |
1380 | + # self.settings_form.register_post_process('mediaitem_media_rebuild') |
1381 | + # self.settings_form.register_post_process('config_screen_changed') |
1382 | |
1383 | def post_set_up(self, post_update=False): |
1384 | """ |
1385 | |
1386 | === removed file 'openlp/core/ui/media/vendor/mediainfoWrapper.py' |
1387 | --- openlp/core/ui/media/vendor/mediainfoWrapper.py 2018-10-30 19:46:55 +0000 |
1388 | +++ openlp/core/ui/media/vendor/mediainfoWrapper.py 1970-01-01 00:00:00 +0000 |
1389 | @@ -1,129 +0,0 @@ |
1390 | -# -*- coding: utf-8 -*- |
1391 | -# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 |
1392 | - |
1393 | -############################################################################### |
1394 | -# OpenLP - Open Source Lyrics Projection # |
1395 | -# --------------------------------------------------------------------------- # |
1396 | -# Copyright (c) 2008-2018 OpenLP Developers # |
1397 | -# --------------------------------------------------------------------------- # |
1398 | -# This program is free software; you can redistribute it and/or modify it # |
1399 | -# under the terms of the GNU General Public License as published by the Free # |
1400 | -# Software Foundation; version 2 of the License. # |
1401 | -# # |
1402 | -# This program is distributed in the hope that it will be useful, but WITHOUT # |
1403 | -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # |
1404 | -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # |
1405 | -# more details. # |
1406 | -# # |
1407 | -# You should have received a copy of the GNU General Public License along # |
1408 | -# with this program; if not, write to the Free Software Foundation, Inc., 59 # |
1409 | -# Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
1410 | -############################################################################### |
1411 | -""" |
1412 | -The :mod:`~openlp.core.ui.media.mediainfo` module contains code to run mediainfo on a media file and obtain |
1413 | -information related to the rwquested media. |
1414 | -""" |
1415 | -import json |
1416 | -import os |
1417 | -from subprocess import check_output |
1418 | - |
1419 | -from bs4 import BeautifulSoup, NavigableString |
1420 | - |
1421 | - |
1422 | -ENV_DICT = os.environ |
1423 | - |
1424 | - |
1425 | -class Track(object): |
1426 | - |
1427 | - def __getattribute__(self, name): |
1428 | - try: |
1429 | - return object.__getattribute__(self, name) |
1430 | - except Exception: |
1431 | - pass |
1432 | - return None |
1433 | - |
1434 | - def __init__(self, xml_dom_fragment): |
1435 | - self.xml_dom_fragment = xml_dom_fragment |
1436 | - self.track_type = xml_dom_fragment.attrs['type'] |
1437 | - for el in self.xml_dom_fragment.children: |
1438 | - if not isinstance(el, NavigableString): |
1439 | - node_name = el.name.lower().strip().strip('_') |
1440 | - if node_name == 'id': |
1441 | - node_name = 'track_id' |
1442 | - node_value = el.string |
1443 | - other_node_name = "other_%s" % node_name |
1444 | - if getattr(self, node_name) is None: |
1445 | - setattr(self, node_name, node_value) |
1446 | - else: |
1447 | - if getattr(self, other_node_name) is None: |
1448 | - setattr(self, other_node_name, [node_value, ]) |
1449 | - else: |
1450 | - getattr(self, other_node_name).append(node_value) |
1451 | - |
1452 | - for o in [d for d in self.__dict__.keys() if d.startswith('other_')]: |
1453 | - try: |
1454 | - primary = o.replace('other_', '') |
1455 | - setattr(self, primary, int(getattr(self, primary))) |
1456 | - except Exception: |
1457 | - for v in getattr(self, o): |
1458 | - try: |
1459 | - current = getattr(self, primary) |
1460 | - setattr(self, primary, int(v)) |
1461 | - getattr(self, o).append(current) |
1462 | - break |
1463 | - except Exception: |
1464 | - pass |
1465 | - |
1466 | - def __repr__(self): |
1467 | - return "<Track track_id='{0}', track_type='{1}'>".format(self.track_id, self.track_type) |
1468 | - |
1469 | - def to_data(self): |
1470 | - data = {} |
1471 | - for k, v in self.__dict__.items(): |
1472 | - if k != 'xml_dom_fragment': |
1473 | - data[k] = v |
1474 | - return data |
1475 | - |
1476 | - |
1477 | -class MediaInfoWrapper(object): |
1478 | - |
1479 | - def __init__(self, xml): |
1480 | - self.xml_dom = xml |
1481 | - xml_types = (str,) # no unicode type in python3 |
1482 | - if isinstance(xml, xml_types): |
1483 | - self.xml_dom = MediaInfoWrapper.parse_xml_data_into_dom(xml) |
1484 | - |
1485 | - @staticmethod |
1486 | - def parse_xml_data_into_dom(xml_data): |
1487 | - return BeautifulSoup(xml_data, "xml") |
1488 | - |
1489 | - @staticmethod |
1490 | - def parse(filename, environment=ENV_DICT): |
1491 | - xml = check_output(['mediainfo', '-f', '--Output=XML', '--Inform=OLDXML', filename]) |
1492 | - if not xml.startswith(b'<?xml'): |
1493 | - xml = check_output(['mediainfo', '-f', '--Output=XML', filename]) |
1494 | - xml_dom = MediaInfoWrapper.parse_xml_data_into_dom(xml) |
1495 | - return MediaInfoWrapper(xml_dom) |
1496 | - |
1497 | - def _populate_tracks(self): |
1498 | - if self.xml_dom is None: |
1499 | - return |
1500 | - for xml_track in self.xml_dom.Mediainfo.File.find_all("track"): |
1501 | - self._tracks.append(Track(xml_track)) |
1502 | - |
1503 | - @property |
1504 | - def tracks(self): |
1505 | - if not hasattr(self, "_tracks"): |
1506 | - self._tracks = [] |
1507 | - if len(self._tracks) == 0: |
1508 | - self._populate_tracks() |
1509 | - return self._tracks |
1510 | - |
1511 | - def to_data(self): |
1512 | - data = {'tracks': []} |
1513 | - for track in self.tracks: |
1514 | - data['tracks'].append(track.to_data()) |
1515 | - return data |
1516 | - |
1517 | - def to_json(self): |
1518 | - return json.dumps(self.to_data()) |
1519 | |
1520 | === modified file 'openlp/core/ui/media/vendor/vlc.py' |
1521 | --- openlp/core/ui/media/vendor/vlc.py 2018-10-02 04:39:42 +0000 |
1522 | +++ openlp/core/ui/media/vendor/vlc.py 2019-01-27 20:26:59 +0000 |
1523 | @@ -1,8 +1,9 @@ |
1524 | #! /usr/bin/python |
1525 | +# -*- coding: utf-8 -*- |
1526 | |
1527 | # Python ctypes bindings for VLC |
1528 | # |
1529 | -# Copyright (C) 2009-2012 the VideoLAN team |
1530 | +# Copyright (C) 2009-2017 the VideoLAN team |
1531 | # $Id: $ |
1532 | # |
1533 | # Authors: Olivier Aubert <contact at olivieraubert.net> |
1534 | @@ -27,7 +28,7 @@ |
1535 | U{http://wiki.videolan.org/LibVLC}. |
1536 | |
1537 | You can find the documentation and a README file with some examples |
1538 | -at U{http://www.advene.org/download/python-ctypes/}. |
1539 | +at U{http://www.olivieraubert.net/vlc/python-ctypes/}. |
1540 | |
1541 | Basically, the most important class is L{Instance}, which is used |
1542 | to create a libvlc instance. From this instance, you then create |
1543 | @@ -40,16 +41,22 @@ |
1544 | """ |
1545 | |
1546 | import ctypes |
1547 | -import functools |
1548 | +from ctypes.util import find_library |
1549 | import os |
1550 | import sys |
1551 | -from ctypes.util import find_library |
1552 | +import functools |
1553 | + |
1554 | # Used by EventManager in override.py |
1555 | from inspect import getargspec |
1556 | |
1557 | - |
1558 | -__version__ = "N/A" |
1559 | -build_date = "Mon Jan 25 19:40:05 2016" |
1560 | +import logging |
1561 | + |
1562 | +logger = logging.getLogger(__name__) |
1563 | + |
1564 | +__version__ = "3.0.3104" |
1565 | +__libvlc_version__ = "3.0.3" |
1566 | +__generator_version__ = "1.4" |
1567 | +build_date = "Fri Jul 13 15:18:27 2018 3.0.3" |
1568 | |
1569 | # The libvlc doc states that filenames are expected to be in UTF8, do |
1570 | # not rely on sys.getfilesystemencoding() which will be confused, |
1571 | @@ -62,6 +69,8 @@ |
1572 | bytes = bytes |
1573 | basestring = (str, bytes) |
1574 | PYTHON3 = True |
1575 | + |
1576 | + |
1577 | def str_to_bytes(s): |
1578 | """Translate string or bytes to bytes. |
1579 | """ |
1580 | @@ -70,6 +79,7 @@ |
1581 | else: |
1582 | return s |
1583 | |
1584 | + |
1585 | def bytes_to_str(b): |
1586 | """Translate bytes to string. |
1587 | """ |
1588 | @@ -83,6 +93,8 @@ |
1589 | bytes = str |
1590 | basestring = basestring |
1591 | PYTHON3 = False |
1592 | + |
1593 | + |
1594 | def str_to_bytes(s): |
1595 | """Translate string or bytes to bytes. |
1596 | """ |
1597 | @@ -91,6 +103,7 @@ |
1598 | else: |
1599 | return s |
1600 | |
1601 | + |
1602 | def bytes_to_str(b): |
1603 | """Translate bytes to unicode string. |
1604 | """ |
1605 | @@ -103,9 +116,22 @@ |
1606 | # instanciated. |
1607 | _internal_guard = object() |
1608 | |
1609 | + |
1610 | def find_lib(): |
1611 | dll = None |
1612 | - plugin_path = None |
1613 | + plugin_path = os.environ.get('PYTHON_VLC_MODULE_PATH', None) |
1614 | + if 'PYTHON_VLC_LIB_PATH' in os.environ: |
1615 | + try: |
1616 | + dll = ctypes.CDLL(os.environ['PYTHON_VLC_LIB_PATH']) |
1617 | + except OSError: |
1618 | + logger.error("Cannot load lib specified by PYTHON_VLC_LIB_PATH env. variable") |
1619 | + sys.exit(1) |
1620 | + if plugin_path and not os.path.isdir(plugin_path): |
1621 | + logger.error("Invalid PYTHON_VLC_MODULE_PATH specified. Please fix.") |
1622 | + sys.exit(1) |
1623 | + if dll is not None: |
1624 | + return dll, plugin_path |
1625 | + |
1626 | if sys.platform.startswith('linux'): |
1627 | p = find_library('vlc') |
1628 | try: |
1629 | @@ -113,7 +139,8 @@ |
1630 | except OSError: # may fail |
1631 | dll = ctypes.CDLL('libvlc.so.5') |
1632 | elif sys.platform.startswith('win'): |
1633 | - p = find_library('libvlc.dll') |
1634 | + libname = 'libvlc.dll' |
1635 | + p = find_library(libname) |
1636 | if p is None: |
1637 | try: # some registry settings |
1638 | # leaner than win32api, win32con |
1639 | @@ -132,22 +159,26 @@ |
1640 | except ImportError: # no PyWin32 |
1641 | pass |
1642 | if plugin_path is None: |
1643 | - # try some standard locations. |
1644 | - for p in ('Program Files\\VideoLan\\', 'VideoLan\\', |
1645 | - 'Program Files\\', ''): |
1646 | - p = 'C:\\' + p + 'VLC\\libvlc.dll' |
1647 | + # try some standard locations. |
1648 | + programfiles = os.environ["ProgramFiles"] |
1649 | + homedir = os.environ["HOMEDRIVE"] |
1650 | + for p in ('{programfiles}\\VideoLan{libname}', '{homedir}:\\VideoLan{libname}', |
1651 | + '{programfiles}{libname}', '{homedir}:{libname}'): |
1652 | + p = p.format(homedir=homedir, |
1653 | + programfiles=programfiles, |
1654 | + libname='\\VLC\\' + libname) |
1655 | if os.path.exists(p): |
1656 | plugin_path = os.path.dirname(p) |
1657 | break |
1658 | if plugin_path is not None: # try loading |
1659 | p = os.getcwd() |
1660 | os.chdir(plugin_path) |
1661 | - # if chdir failed, this will raise an exception |
1662 | - dll = ctypes.CDLL('libvlc.dll') |
1663 | - # restore cwd after dll has been loaded |
1664 | + # if chdir failed, this will raise an exception |
1665 | + dll = ctypes.CDLL(libname) |
1666 | + # restore cwd after dll has been loaded |
1667 | os.chdir(p) |
1668 | else: # may fail |
1669 | - dll = ctypes.CDLL('libvlc.dll') |
1670 | + dll = ctypes.CDLL(libname) |
1671 | else: |
1672 | plugin_path = os.path.dirname(p) |
1673 | dll = ctypes.CDLL(p) |
1674 | @@ -155,13 +186,20 @@ |
1675 | elif sys.platform.startswith('darwin'): |
1676 | # FIXME: should find a means to configure path |
1677 | d = '/Applications/VLC.app/Contents/MacOS/' |
1678 | + c = d + 'lib/libvlccore.dylib' |
1679 | p = d + 'lib/libvlc.dylib' |
1680 | - if os.path.exists(p): |
1681 | + if os.path.exists(p) and os.path.exists(c): |
1682 | + # pre-load libvlccore VLC 2.2.8+ |
1683 | + ctypes.CDLL(c) |
1684 | dll = ctypes.CDLL(p) |
1685 | - d += 'modules' |
1686 | - if os.path.isdir(d): |
1687 | - plugin_path = d |
1688 | - else: # hope, some PATH is set... |
1689 | + for p in ('modules', 'plugins'): |
1690 | + p = d + p |
1691 | + if os.path.isdir(p): |
1692 | + plugin_path = p |
1693 | + break |
1694 | + else: # hope, some [DY]LD_LIBRARY_PATH is set... |
1695 | + # pre-load libvlccore VLC 2.2.8+ |
1696 | + ctypes.CDLL('libvlccore.dylib') |
1697 | dll = ctypes.CDLL('libvlc.dylib') |
1698 | |
1699 | else: |
1700 | @@ -169,20 +207,24 @@ |
1701 | |
1702 | return (dll, plugin_path) |
1703 | |
1704 | + |
1705 | # plugin_path used on win32 and MacOS in override.py |
1706 | -dll, plugin_path = find_lib() |
1707 | +dll, plugin_path = find_lib() |
1708 | + |
1709 | |
1710 | class VLCException(Exception): |
1711 | """Exception raised by libvlc methods. |
1712 | """ |
1713 | pass |
1714 | |
1715 | + |
1716 | try: |
1717 | _Ints = (int, long) |
1718 | except NameError: # no long in Python 3+ |
1719 | - _Ints = int |
1720 | + _Ints = int |
1721 | _Seqs = (list, tuple) |
1722 | |
1723 | + |
1724 | # Used for handling *event_manager() methods. |
1725 | class memoize_parameterless(object): |
1726 | """Decorator. Caches a parameterless method's return value each time it is called. |
1727 | @@ -191,6 +233,7 @@ |
1728 | (not reevaluated). |
1729 | Adapted from https://wiki.python.org/moin/PythonDecoratorLibrary |
1730 | """ |
1731 | + |
1732 | def __init__(self, func): |
1733 | self.func = func |
1734 | self._cache = {} |
1735 | @@ -208,14 +251,16 @@ |
1736 | return self.func.__doc__ |
1737 | |
1738 | def __get__(self, obj, objtype): |
1739 | - """Support instance methods. |
1740 | - """ |
1741 | - return functools.partial(self.__call__, obj) |
1742 | + """Support instance methods. |
1743 | + """ |
1744 | + return functools.partial(self.__call__, obj) |
1745 | + |
1746 | |
1747 | # Default instance. It is used to instanciate classes directly in the |
1748 | # OO-wrapper. |
1749 | _default_instance = None |
1750 | |
1751 | + |
1752 | def get_default_instance(): |
1753 | """Return the default VLC.Instance. |
1754 | """ |
1755 | @@ -224,9 +269,11 @@ |
1756 | _default_instance = Instance() |
1757 | return _default_instance |
1758 | |
1759 | + |
1760 | _Cfunctions = {} # from LibVLC __version__ |
1761 | _Globals = globals() # sys.modules[__name__].__dict__ |
1762 | |
1763 | + |
1764 | def _Cfunction(name, flags, errcheck, *types): |
1765 | """(INTERNAL) New ctypes function binding. |
1766 | """ |
1767 | @@ -245,6 +292,7 @@ |
1768 | return f |
1769 | raise NameError('no function %r' % (name,)) |
1770 | |
1771 | + |
1772 | def _Cobject(cls, ctype): |
1773 | """(INTERNAL) New instance from ctypes. |
1774 | """ |
1775 | @@ -252,15 +300,18 @@ |
1776 | o._as_parameter_ = ctype |
1777 | return o |
1778 | |
1779 | + |
1780 | def _Constructor(cls, ptr=_internal_guard): |
1781 | """(INTERNAL) New wrapper from ctypes. |
1782 | """ |
1783 | if ptr == _internal_guard: |
1784 | - raise VLCException("(INTERNAL) ctypes class. You should get references for this class through methods of the LibVLC API.") |
1785 | + raise VLCException( |
1786 | + "(INTERNAL) ctypes class. You should get references for this class through methods of the LibVLC API.") |
1787 | if ptr is None or ptr == 0: |
1788 | return None |
1789 | return _Cobject(cls, ctypes.c_void_p(ptr)) |
1790 | |
1791 | + |
1792 | class _Cstruct(ctypes.Structure): |
1793 | """(INTERNAL) Base class for ctypes structures. |
1794 | """ |
1795 | @@ -273,9 +324,11 @@ |
1796 | def __repr__(self): |
1797 | return '%s.%s' % (self.__class__.__module__, self) |
1798 | |
1799 | + |
1800 | class _Ctype(object): |
1801 | """(INTERNAL) Base class for ctypes. |
1802 | """ |
1803 | + |
1804 | @staticmethod |
1805 | def from_param(this): # not self |
1806 | """(INTERNAL) ctypes parameter conversion method. |
1807 | @@ -284,15 +337,20 @@ |
1808 | return None |
1809 | return this._as_parameter_ |
1810 | |
1811 | + |
1812 | class ListPOINTER(object): |
1813 | """Just like a POINTER but accept a list of ctype as an argument. |
1814 | """ |
1815 | + |
1816 | def __init__(self, etype): |
1817 | self.etype = etype |
1818 | |
1819 | def from_param(self, param): |
1820 | if isinstance(param, _Seqs): |
1821 | return (self.etype * len(param))(*param) |
1822 | + else: |
1823 | + return ctypes.POINTER(param) |
1824 | + |
1825 | |
1826 | # errcheck functions for some native functions. |
1827 | def string_result(result, func, arguments): |
1828 | @@ -308,24 +366,33 @@ |
1829 | return s |
1830 | return None |
1831 | |
1832 | + |
1833 | def class_result(classname): |
1834 | """Errcheck function. Returns a function that creates the specified class. |
1835 | """ |
1836 | + |
1837 | def wrap_errcheck(result, func, arguments): |
1838 | if result is None: |
1839 | return None |
1840 | return classname(result) |
1841 | + |
1842 | return wrap_errcheck |
1843 | |
1844 | + |
1845 | # Wrapper for the opaque struct libvlc_log_t |
1846 | class Log(ctypes.Structure): |
1847 | pass |
1848 | + |
1849 | + |
1850 | Log_ptr = ctypes.POINTER(Log) |
1851 | |
1852 | + |
1853 | # FILE* ctypes wrapper, copied from |
1854 | # http://svn.python.org/projects/ctypes/trunk/ctypeslib/ctypeslib/contrib/pythonhdr.py |
1855 | class FILE(ctypes.Structure): |
1856 | pass |
1857 | + |
1858 | + |
1859 | FILE_ptr = ctypes.POINTER(FILE) |
1860 | |
1861 | if PYTHON3: |
1862 | @@ -338,7 +405,7 @@ |
1863 | ctypes.c_char_p, |
1864 | ctypes.c_char_p, |
1865 | ctypes.c_char_p, |
1866 | - ctypes.c_int ] |
1867 | + ctypes.c_int] |
1868 | |
1869 | PyFile_AsFd = ctypes.pythonapi.PyObject_AsFileDescriptor |
1870 | PyFile_AsFd.restype = ctypes.c_int |
1871 | @@ -355,7 +422,8 @@ |
1872 | PyFile_AsFile.restype = FILE_ptr |
1873 | PyFile_AsFile.argtypes = [ctypes.py_object] |
1874 | |
1875 | - # Generated enum types # |
1876 | + |
1877 | +# Generated enum types # |
1878 | |
1879 | class _Enum(ctypes.c_uint): |
1880 | '''(INTERNAL) Base class |
1881 | @@ -373,12 +441,13 @@ |
1882 | return '.'.join((self.__class__.__module__, self.__str__())) |
1883 | |
1884 | def __eq__(self, other): |
1885 | - return ( (isinstance(other, _Enum) and self.value == other.value) |
1886 | - or (isinstance(other, _Ints) and self.value == other) ) |
1887 | + return ((isinstance(other, _Enum) and self.value == other.value) |
1888 | + or (isinstance(other, _Ints) and self.value == other)) |
1889 | |
1890 | def __ne__(self, other): |
1891 | return not self.__eq__(other) |
1892 | |
1893 | + |
1894 | class LogLevel(_Enum): |
1895 | '''Logging messages level. |
1896 | \note future libvlc versions may define new levels. |
1897 | @@ -389,11 +458,51 @@ |
1898 | 3: 'WARNING', |
1899 | 4: 'ERROR', |
1900 | } |
1901 | -LogLevel.DEBUG = LogLevel(0) |
1902 | -LogLevel.ERROR = LogLevel(4) |
1903 | -LogLevel.NOTICE = LogLevel(2) |
1904 | + |
1905 | + |
1906 | +LogLevel.DEBUG = LogLevel(0) |
1907 | +LogLevel.ERROR = LogLevel(4) |
1908 | +LogLevel.NOTICE = LogLevel(2) |
1909 | LogLevel.WARNING = LogLevel(3) |
1910 | |
1911 | + |
1912 | +class MediaDiscovererCategory(_Enum): |
1913 | + '''Category of a media discoverer |
1914 | +See libvlc_media_discoverer_list_get(). |
1915 | + ''' |
1916 | + _enum_names_ = { |
1917 | + 0: 'devices', |
1918 | + 1: 'lan', |
1919 | + 2: 'podcasts', |
1920 | + 3: 'localdirs', |
1921 | + } |
1922 | + |
1923 | + |
1924 | +MediaDiscovererCategory.devices = MediaDiscovererCategory(0) |
1925 | +MediaDiscovererCategory.lan = MediaDiscovererCategory(1) |
1926 | +MediaDiscovererCategory.localdirs = MediaDiscovererCategory(3) |
1927 | +MediaDiscovererCategory.podcasts = MediaDiscovererCategory(2) |
1928 | + |
1929 | + |
1930 | +class DialogQuestionType(_Enum): |
1931 | + '''@defgroup libvlc_dialog libvlc dialog |
1932 | +@ingroup libvlc |
1933 | +@{ |
1934 | +@file |
1935 | +libvlc dialog external api. |
1936 | + ''' |
1937 | + _enum_names_ = { |
1938 | + 0: 'NORMAL', |
1939 | + 1: 'WARNING', |
1940 | + 2: 'CRITICAL', |
1941 | + } |
1942 | + |
1943 | + |
1944 | +DialogQuestionType.CRITICAL = DialogQuestionType(2) |
1945 | +DialogQuestionType.NORMAL = DialogQuestionType(0) |
1946 | +DialogQuestionType.WARNING = DialogQuestionType(1) |
1947 | + |
1948 | + |
1949 | class EventType(_Enum): |
1950 | '''Event types. |
1951 | ''' |
1952 | @@ -425,10 +534,21 @@ |
1953 | 273: 'MediaPlayerLengthChanged', |
1954 | 274: 'MediaPlayerVout', |
1955 | 275: 'MediaPlayerScrambledChanged', |
1956 | + 276: 'MediaPlayerESAdded', |
1957 | + 277: 'MediaPlayerESDeleted', |
1958 | + 278: 'MediaPlayerESSelected', |
1959 | + 279: 'MediaPlayerCorked', |
1960 | + 280: 'MediaPlayerUncorked', |
1961 | + 281: 'MediaPlayerMuted', |
1962 | + 282: 'MediaPlayerUnmuted', |
1963 | + 283: 'MediaPlayerAudioVolume', |
1964 | + 284: 'MediaPlayerAudioDevice', |
1965 | + 285: 'MediaPlayerChapterChanged', |
1966 | 0x200: 'MediaListItemAdded', |
1967 | 513: 'MediaListWillAddItem', |
1968 | 514: 'MediaListItemDeleted', |
1969 | 515: 'MediaListWillDeleteItem', |
1970 | + 516: 'MediaListEndReached', |
1971 | 0x300: 'MediaListViewItemAdded', |
1972 | 769: 'MediaListViewWillAddItem', |
1973 | 770: 'MediaListViewItemDeleted', |
1974 | @@ -438,6 +558,8 @@ |
1975 | 1026: 'MediaListPlayerStopped', |
1976 | 0x500: 'MediaDiscovererStarted', |
1977 | 1281: 'MediaDiscovererEnded', |
1978 | + 1282: 'RendererDiscovererItemAdded', |
1979 | + 1283: 'RendererDiscovererItemDeleted', |
1980 | 0x600: 'VlmMediaAdded', |
1981 | 1537: 'VlmMediaRemoved', |
1982 | 1538: 'VlmMediaChanged', |
1983 | @@ -450,57 +572,73 @@ |
1984 | 1545: 'VlmMediaInstanceStatusEnd', |
1985 | 1546: 'VlmMediaInstanceStatusError', |
1986 | } |
1987 | -EventType.MediaDiscovererEnded = EventType(1281) |
1988 | -EventType.MediaDiscovererStarted = EventType(0x500) |
1989 | -EventType.MediaDurationChanged = EventType(2) |
1990 | -EventType.MediaFreed = EventType(4) |
1991 | -EventType.MediaListItemAdded = EventType(0x200) |
1992 | -EventType.MediaListItemDeleted = EventType(514) |
1993 | -EventType.MediaListPlayerNextItemSet = EventType(1025) |
1994 | -EventType.MediaListPlayerPlayed = EventType(0x400) |
1995 | -EventType.MediaListPlayerStopped = EventType(1026) |
1996 | -EventType.MediaListViewItemAdded = EventType(0x300) |
1997 | -EventType.MediaListViewItemDeleted = EventType(770) |
1998 | -EventType.MediaListViewWillAddItem = EventType(769) |
1999 | -EventType.MediaListViewWillDeleteItem = EventType(771) |
2000 | -EventType.MediaListWillAddItem = EventType(513) |
2001 | -EventType.MediaListWillDeleteItem = EventType(515) |
2002 | -EventType.MediaMetaChanged = EventType(0) |
2003 | -EventType.MediaParsedChanged = EventType(3) |
2004 | -EventType.MediaPlayerBackward = EventType(264) |
2005 | -EventType.MediaPlayerBuffering = EventType(259) |
2006 | -EventType.MediaPlayerEncounteredError = EventType(266) |
2007 | -EventType.MediaPlayerEndReached = EventType(265) |
2008 | -EventType.MediaPlayerForward = EventType(263) |
2009 | -EventType.MediaPlayerLengthChanged = EventType(273) |
2010 | -EventType.MediaPlayerMediaChanged = EventType(0x100) |
2011 | -EventType.MediaPlayerNothingSpecial = EventType(257) |
2012 | -EventType.MediaPlayerOpening = EventType(258) |
2013 | -EventType.MediaPlayerPausableChanged = EventType(270) |
2014 | -EventType.MediaPlayerPaused = EventType(261) |
2015 | -EventType.MediaPlayerPlaying = EventType(260) |
2016 | -EventType.MediaPlayerPositionChanged = EventType(268) |
2017 | -EventType.MediaPlayerScrambledChanged = EventType(275) |
2018 | -EventType.MediaPlayerSeekableChanged = EventType(269) |
2019 | -EventType.MediaPlayerSnapshotTaken = EventType(272) |
2020 | -EventType.MediaPlayerStopped = EventType(262) |
2021 | -EventType.MediaPlayerTimeChanged = EventType(267) |
2022 | -EventType.MediaPlayerTitleChanged = EventType(271) |
2023 | -EventType.MediaPlayerVout = EventType(274) |
2024 | -EventType.MediaStateChanged = EventType(5) |
2025 | -EventType.MediaSubItemAdded = EventType(1) |
2026 | -EventType.MediaSubItemTreeAdded = EventType(6) |
2027 | -EventType.VlmMediaAdded = EventType(0x600) |
2028 | -EventType.VlmMediaChanged = EventType(1538) |
2029 | -EventType.VlmMediaInstanceStarted = EventType(1539) |
2030 | -EventType.VlmMediaInstanceStatusEnd = EventType(1545) |
2031 | -EventType.VlmMediaInstanceStatusError = EventType(1546) |
2032 | -EventType.VlmMediaInstanceStatusInit = EventType(1541) |
2033 | + |
2034 | + |
2035 | +EventType.MediaDiscovererEnded = EventType(1281) |
2036 | +EventType.MediaDiscovererStarted = EventType(0x500) |
2037 | +EventType.MediaDurationChanged = EventType(2) |
2038 | +EventType.MediaFreed = EventType(4) |
2039 | +EventType.MediaListEndReached = EventType(516) |
2040 | +EventType.MediaListItemAdded = EventType(0x200) |
2041 | +EventType.MediaListItemDeleted = EventType(514) |
2042 | +EventType.MediaListPlayerNextItemSet = EventType(1025) |
2043 | +EventType.MediaListPlayerPlayed = EventType(0x400) |
2044 | +EventType.MediaListPlayerStopped = EventType(1026) |
2045 | +EventType.MediaListViewItemAdded = EventType(0x300) |
2046 | +EventType.MediaListViewItemDeleted = EventType(770) |
2047 | +EventType.MediaListViewWillAddItem = EventType(769) |
2048 | +EventType.MediaListViewWillDeleteItem = EventType(771) |
2049 | +EventType.MediaListWillAddItem = EventType(513) |
2050 | +EventType.MediaListWillDeleteItem = EventType(515) |
2051 | +EventType.MediaMetaChanged = EventType(0) |
2052 | +EventType.MediaParsedChanged = EventType(3) |
2053 | +EventType.MediaPlayerAudioDevice = EventType(284) |
2054 | +EventType.MediaPlayerAudioVolume = EventType(283) |
2055 | +EventType.MediaPlayerBackward = EventType(264) |
2056 | +EventType.MediaPlayerBuffering = EventType(259) |
2057 | +EventType.MediaPlayerChapterChanged = EventType(285) |
2058 | +EventType.MediaPlayerCorked = EventType(279) |
2059 | +EventType.MediaPlayerESAdded = EventType(276) |
2060 | +EventType.MediaPlayerESDeleted = EventType(277) |
2061 | +EventType.MediaPlayerESSelected = EventType(278) |
2062 | +EventType.MediaPlayerEncounteredError = EventType(266) |
2063 | +EventType.MediaPlayerEndReached = EventType(265) |
2064 | +EventType.MediaPlayerForward = EventType(263) |
2065 | +EventType.MediaPlayerLengthChanged = EventType(273) |
2066 | +EventType.MediaPlayerMediaChanged = EventType(0x100) |
2067 | +EventType.MediaPlayerMuted = EventType(281) |
2068 | +EventType.MediaPlayerNothingSpecial = EventType(257) |
2069 | +EventType.MediaPlayerOpening = EventType(258) |
2070 | +EventType.MediaPlayerPausableChanged = EventType(270) |
2071 | +EventType.MediaPlayerPaused = EventType(261) |
2072 | +EventType.MediaPlayerPlaying = EventType(260) |
2073 | +EventType.MediaPlayerPositionChanged = EventType(268) |
2074 | +EventType.MediaPlayerScrambledChanged = EventType(275) |
2075 | +EventType.MediaPlayerSeekableChanged = EventType(269) |
2076 | +EventType.MediaPlayerSnapshotTaken = EventType(272) |
2077 | +EventType.MediaPlayerStopped = EventType(262) |
2078 | +EventType.MediaPlayerTimeChanged = EventType(267) |
2079 | +EventType.MediaPlayerTitleChanged = EventType(271) |
2080 | +EventType.MediaPlayerUncorked = EventType(280) |
2081 | +EventType.MediaPlayerUnmuted = EventType(282) |
2082 | +EventType.MediaPlayerVout = EventType(274) |
2083 | +EventType.MediaStateChanged = EventType(5) |
2084 | +EventType.MediaSubItemAdded = EventType(1) |
2085 | +EventType.MediaSubItemTreeAdded = EventType(6) |
2086 | +EventType.RendererDiscovererItemAdded = EventType(1282) |
2087 | +EventType.RendererDiscovererItemDeleted = EventType(1283) |
2088 | +EventType.VlmMediaAdded = EventType(0x600) |
2089 | +EventType.VlmMediaChanged = EventType(1538) |
2090 | +EventType.VlmMediaInstanceStarted = EventType(1539) |
2091 | +EventType.VlmMediaInstanceStatusEnd = EventType(1545) |
2092 | +EventType.VlmMediaInstanceStatusError = EventType(1546) |
2093 | +EventType.VlmMediaInstanceStatusInit = EventType(1541) |
2094 | EventType.VlmMediaInstanceStatusOpening = EventType(1542) |
2095 | -EventType.VlmMediaInstanceStatusPause = EventType(1544) |
2096 | +EventType.VlmMediaInstanceStatusPause = EventType(1544) |
2097 | EventType.VlmMediaInstanceStatusPlaying = EventType(1543) |
2098 | -EventType.VlmMediaInstanceStopped = EventType(1540) |
2099 | -EventType.VlmMediaRemoved = EventType(1537) |
2100 | +EventType.VlmMediaInstanceStopped = EventType(1540) |
2101 | +EventType.VlmMediaRemoved = EventType(1537) |
2102 | + |
2103 | |
2104 | class Meta(_Enum): |
2105 | '''Meta data types. |
2106 | @@ -529,37 +667,46 @@ |
2107 | 20: 'Episode', |
2108 | 21: 'ShowName', |
2109 | 22: 'Actors', |
2110 | + 23: 'AlbumArtist', |
2111 | + 24: 'DiscNumber', |
2112 | + 25: 'DiscTotal', |
2113 | } |
2114 | -Meta.Actors = Meta(22) |
2115 | -Meta.Album = Meta(4) |
2116 | -Meta.Artist = Meta(1) |
2117 | -Meta.ArtworkURL = Meta(15) |
2118 | -Meta.Copyright = Meta(3) |
2119 | -Meta.Date = Meta(8) |
2120 | + |
2121 | + |
2122 | +Meta.Actors = Meta(22) |
2123 | +Meta.Album = Meta(4) |
2124 | +Meta.AlbumArtist = Meta(23) |
2125 | +Meta.Artist = Meta(1) |
2126 | +Meta.ArtworkURL = Meta(15) |
2127 | +Meta.Copyright = Meta(3) |
2128 | +Meta.Date = Meta(8) |
2129 | Meta.Description = Meta(6) |
2130 | -Meta.Director = Meta(18) |
2131 | -Meta.EncodedBy = Meta(14) |
2132 | -Meta.Episode = Meta(20) |
2133 | -Meta.Genre = Meta(2) |
2134 | -Meta.Language = Meta(11) |
2135 | -Meta.NowPlaying = Meta(12) |
2136 | -Meta.Publisher = Meta(13) |
2137 | -Meta.Rating = Meta(7) |
2138 | -Meta.Season = Meta(19) |
2139 | -Meta.Setting = Meta(9) |
2140 | -Meta.ShowName = Meta(21) |
2141 | -Meta.Title = Meta(0) |
2142 | -Meta.TrackID = Meta(16) |
2143 | +Meta.Director = Meta(18) |
2144 | +Meta.DiscNumber = Meta(24) |
2145 | +Meta.DiscTotal = Meta(25) |
2146 | +Meta.EncodedBy = Meta(14) |
2147 | +Meta.Episode = Meta(20) |
2148 | +Meta.Genre = Meta(2) |
2149 | +Meta.Language = Meta(11) |
2150 | +Meta.NowPlaying = Meta(12) |
2151 | +Meta.Publisher = Meta(13) |
2152 | +Meta.Rating = Meta(7) |
2153 | +Meta.Season = Meta(19) |
2154 | +Meta.Setting = Meta(9) |
2155 | +Meta.ShowName = Meta(21) |
2156 | +Meta.Title = Meta(0) |
2157 | +Meta.TrackID = Meta(16) |
2158 | Meta.TrackNumber = Meta(5) |
2159 | -Meta.TrackTotal = Meta(17) |
2160 | -Meta.URL = Meta(10) |
2161 | +Meta.TrackTotal = Meta(17) |
2162 | +Meta.URL = Meta(10) |
2163 | + |
2164 | |
2165 | class State(_Enum): |
2166 | '''Note the order of libvlc_state_t enum must match exactly the order of |
2167 | See mediacontrol_playerstatus, See input_state_e enums, |
2168 | and videolan.libvlc.state (at bindings/cil/src/media.cs). |
2169 | expected states by web plugins are: |
2170 | -idle/close=0, opening=1, buffering=2, playing=3, paused=4, |
2171 | +idle/close=0, opening=1, playing=3, paused=4, |
2172 | stopping=5, ended=6, error=7. |
2173 | ''' |
2174 | _enum_names_ = { |
2175 | @@ -572,14 +719,17 @@ |
2176 | 6: 'Ended', |
2177 | 7: 'Error', |
2178 | } |
2179 | -State.Buffering = State(2) |
2180 | -State.Ended = State(6) |
2181 | -State.Error = State(7) |
2182 | + |
2183 | + |
2184 | +State.Buffering = State(2) |
2185 | +State.Ended = State(6) |
2186 | +State.Error = State(7) |
2187 | State.NothingSpecial = State(0) |
2188 | -State.Opening = State(1) |
2189 | -State.Paused = State(4) |
2190 | -State.Playing = State(3) |
2191 | -State.Stopped = State(5) |
2192 | +State.Opening = State(1) |
2193 | +State.Paused = State(4) |
2194 | +State.Playing = State(3) |
2195 | +State.Stopped = State(5) |
2196 | + |
2197 | |
2198 | class TrackType(_Enum): |
2199 | '''N/A |
2200 | @@ -590,22 +740,128 @@ |
2201 | 1: 'video', |
2202 | 2: 'text', |
2203 | } |
2204 | -TrackType.audio = TrackType(0) |
2205 | -TrackType.text = TrackType(2) |
2206 | + |
2207 | + |
2208 | +TrackType.audio = TrackType(0) |
2209 | +TrackType.text = TrackType(2) |
2210 | TrackType.unknown = TrackType(-1) |
2211 | -TrackType.video = TrackType(1) |
2212 | - |
2213 | -class PlaybackMode(_Enum): |
2214 | - '''Defines playback modes for playlist. |
2215 | - ''' |
2216 | - _enum_names_ = { |
2217 | - 0: 'default', |
2218 | - 1: 'loop', |
2219 | - 2: 'repeat', |
2220 | - } |
2221 | -PlaybackMode.default = PlaybackMode(0) |
2222 | -PlaybackMode.loop = PlaybackMode(1) |
2223 | -PlaybackMode.repeat = PlaybackMode(2) |
2224 | +TrackType.video = TrackType(1) |
2225 | + |
2226 | + |
2227 | +class VideoOrient(_Enum): |
2228 | + '''N/A |
2229 | + ''' |
2230 | + _enum_names_ = { |
2231 | + 0: 'left', |
2232 | + 1: 'right', |
2233 | + 2: 'left', |
2234 | + 3: 'right', |
2235 | + 4: 'top', |
2236 | + 5: 'bottom', |
2237 | + 6: 'top', |
2238 | + 7: 'bottom', |
2239 | + } |
2240 | + |
2241 | + |
2242 | +VideoOrient.bottom = VideoOrient(5) |
2243 | +VideoOrient.bottom = VideoOrient(7) |
2244 | +VideoOrient.left = VideoOrient(0) |
2245 | +VideoOrient.left = VideoOrient(2) |
2246 | +VideoOrient.right = VideoOrient(1) |
2247 | +VideoOrient.right = VideoOrient(3) |
2248 | +VideoOrient.top = VideoOrient(4) |
2249 | +VideoOrient.top = VideoOrient(6) |
2250 | + |
2251 | + |
2252 | +class VideoProjection(_Enum): |
2253 | + '''N/A |
2254 | + ''' |
2255 | + _enum_names_ = { |
2256 | + 0: 'rectangular', |
2257 | + 1: 'equirectangular', |
2258 | + 0x100: 'standard', |
2259 | + } |
2260 | + |
2261 | + |
2262 | +VideoProjection.equirectangular = VideoProjection(1) |
2263 | +VideoProjection.rectangular = VideoProjection(0) |
2264 | +VideoProjection.standard = VideoProjection(0x100) |
2265 | + |
2266 | + |
2267 | +class MediaType(_Enum): |
2268 | + '''Media type |
2269 | +See libvlc_media_get_type. |
2270 | + ''' |
2271 | + _enum_names_ = { |
2272 | + 0: 'unknown', |
2273 | + 1: 'file', |
2274 | + 2: 'directory', |
2275 | + 3: 'disc', |
2276 | + 4: 'stream', |
2277 | + 5: 'playlist', |
2278 | + } |
2279 | + |
2280 | + |
2281 | +MediaType.directory = MediaType(2) |
2282 | +MediaType.disc = MediaType(3) |
2283 | +MediaType.file = MediaType(1) |
2284 | +MediaType.playlist = MediaType(5) |
2285 | +MediaType.stream = MediaType(4) |
2286 | +MediaType.unknown = MediaType(0) |
2287 | + |
2288 | + |
2289 | +class MediaParseFlag(_Enum): |
2290 | + '''Parse flags used by libvlc_media_parse_with_options() |
2291 | +See libvlc_media_parse_with_options. |
2292 | + ''' |
2293 | + _enum_names_ = { |
2294 | + 0x0: 'local', |
2295 | + 0x1: 'network', |
2296 | + 0x2: 'local', |
2297 | + 0x4: 'network', |
2298 | + 0x8: 'interact', |
2299 | + } |
2300 | + |
2301 | + |
2302 | +MediaParseFlag.interact = MediaParseFlag(0x8) |
2303 | +MediaParseFlag.local = MediaParseFlag(0x0) |
2304 | +MediaParseFlag.local = MediaParseFlag(0x2) |
2305 | +MediaParseFlag.network = MediaParseFlag(0x1) |
2306 | +MediaParseFlag.network = MediaParseFlag(0x4) |
2307 | + |
2308 | + |
2309 | +class MediaParsedStatus(_Enum): |
2310 | + '''Parse status used sent by libvlc_media_parse_with_options() or returned by |
2311 | +libvlc_media_get_parsed_status() |
2312 | +See libvlc_media_parse_with_options |
2313 | +See libvlc_media_get_parsed_status. |
2314 | + ''' |
2315 | + _enum_names_ = { |
2316 | + 1: 'skipped', |
2317 | + 2: 'failed', |
2318 | + 3: 'timeout', |
2319 | + 4: 'done', |
2320 | + } |
2321 | + |
2322 | + |
2323 | +MediaParsedStatus.done = MediaParsedStatus(4) |
2324 | +MediaParsedStatus.failed = MediaParsedStatus(2) |
2325 | +MediaParsedStatus.skipped = MediaParsedStatus(1) |
2326 | +MediaParsedStatus.timeout = MediaParsedStatus(3) |
2327 | + |
2328 | + |
2329 | +class MediaSlaveType(_Enum): |
2330 | + '''Type of a media slave: subtitle or audio. |
2331 | + ''' |
2332 | + _enum_names_ = { |
2333 | + 0: 'subtitle', |
2334 | + 1: 'audio', |
2335 | + } |
2336 | + |
2337 | + |
2338 | +MediaSlaveType.audio = MediaSlaveType(1) |
2339 | +MediaSlaveType.subtitle = MediaSlaveType(0) |
2340 | + |
2341 | |
2342 | class VideoMarqueeOption(_Enum): |
2343 | '''Marq options definition. |
2344 | @@ -622,17 +878,20 @@ |
2345 | 8: 'marquee_X', |
2346 | 9: 'marquee_Y', |
2347 | } |
2348 | -VideoMarqueeOption.Color = VideoMarqueeOption(2) |
2349 | -VideoMarqueeOption.Enable = VideoMarqueeOption(0) |
2350 | -VideoMarqueeOption.Opacity = VideoMarqueeOption(3) |
2351 | -VideoMarqueeOption.Position = VideoMarqueeOption(4) |
2352 | -VideoMarqueeOption.Refresh = VideoMarqueeOption(5) |
2353 | -VideoMarqueeOption.Size = VideoMarqueeOption(6) |
2354 | -VideoMarqueeOption.Text = VideoMarqueeOption(1) |
2355 | -VideoMarqueeOption.Timeout = VideoMarqueeOption(7) |
2356 | + |
2357 | + |
2358 | +VideoMarqueeOption.Color = VideoMarqueeOption(2) |
2359 | +VideoMarqueeOption.Enable = VideoMarqueeOption(0) |
2360 | +VideoMarqueeOption.Opacity = VideoMarqueeOption(3) |
2361 | +VideoMarqueeOption.Position = VideoMarqueeOption(4) |
2362 | +VideoMarqueeOption.Refresh = VideoMarqueeOption(5) |
2363 | +VideoMarqueeOption.Size = VideoMarqueeOption(6) |
2364 | +VideoMarqueeOption.Text = VideoMarqueeOption(1) |
2365 | +VideoMarqueeOption.Timeout = VideoMarqueeOption(7) |
2366 | VideoMarqueeOption.marquee_X = VideoMarqueeOption(8) |
2367 | VideoMarqueeOption.marquee_Y = VideoMarqueeOption(9) |
2368 | |
2369 | + |
2370 | class NavigateMode(_Enum): |
2371 | '''Navigation mode. |
2372 | ''' |
2373 | @@ -642,12 +901,17 @@ |
2374 | 2: 'down', |
2375 | 3: 'left', |
2376 | 4: 'right', |
2377 | + 5: 'popup', |
2378 | } |
2379 | + |
2380 | + |
2381 | NavigateMode.activate = NavigateMode(0) |
2382 | -NavigateMode.down = NavigateMode(2) |
2383 | -NavigateMode.left = NavigateMode(3) |
2384 | -NavigateMode.right = NavigateMode(4) |
2385 | -NavigateMode.up = NavigateMode(1) |
2386 | +NavigateMode.down = NavigateMode(2) |
2387 | +NavigateMode.left = NavigateMode(3) |
2388 | +NavigateMode.popup = NavigateMode(5) |
2389 | +NavigateMode.right = NavigateMode(4) |
2390 | +NavigateMode.up = NavigateMode(1) |
2391 | + |
2392 | |
2393 | class Position(_Enum): |
2394 | '''Enumeration of values used to set position (e.g. of video title). |
2395 | @@ -664,16 +928,39 @@ |
2396 | 7: 'left', |
2397 | 8: 'right', |
2398 | } |
2399 | -Position.bottom = Position(6) |
2400 | -Position.center = Position(0) |
2401 | + |
2402 | + |
2403 | +Position.bottom = Position(6) |
2404 | +Position.center = Position(0) |
2405 | Position.disable = Position(-1) |
2406 | -Position.left = Position(1) |
2407 | -Position.left = Position(4) |
2408 | -Position.left = Position(7) |
2409 | -Position.right = Position(2) |
2410 | -Position.right = Position(5) |
2411 | -Position.right = Position(8) |
2412 | -Position.top = Position(3) |
2413 | +Position.left = Position(1) |
2414 | +Position.left = Position(4) |
2415 | +Position.left = Position(7) |
2416 | +Position.right = Position(2) |
2417 | +Position.right = Position(5) |
2418 | +Position.right = Position(8) |
2419 | +Position.top = Position(3) |
2420 | + |
2421 | + |
2422 | +class TeletextKey(_Enum): |
2423 | + '''Enumeration of teletext keys than can be passed via |
2424 | +libvlc_video_set_teletext(). |
2425 | + ''' |
2426 | + _enum_names_ = { |
2427 | + 7471104: 'red', |
2428 | + 6750208: 'green', |
2429 | + 7929856: 'yellow', |
2430 | + 6422528: 'blue', |
2431 | + 6881280: 'index', |
2432 | + } |
2433 | + |
2434 | + |
2435 | +TeletextKey.blue = TeletextKey(6422528) |
2436 | +TeletextKey.green = TeletextKey(6750208) |
2437 | +TeletextKey.index = TeletextKey(6881280) |
2438 | +TeletextKey.red = TeletextKey(7471104) |
2439 | +TeletextKey.yellow = TeletextKey(7929856) |
2440 | + |
2441 | |
2442 | class VideoLogoOption(_Enum): |
2443 | '''Option values for libvlc_video_{get,set}_logo_{int,string}. |
2444 | @@ -688,14 +975,17 @@ |
2445 | 6: 'opacity', |
2446 | 7: 'position', |
2447 | } |
2448 | -VideoLogoOption.delay = VideoLogoOption(4) |
2449 | -VideoLogoOption.enable = VideoLogoOption(0) |
2450 | -VideoLogoOption.file = VideoLogoOption(1) |
2451 | -VideoLogoOption.logo_x = VideoLogoOption(2) |
2452 | -VideoLogoOption.logo_y = VideoLogoOption(3) |
2453 | -VideoLogoOption.opacity = VideoLogoOption(6) |
2454 | + |
2455 | + |
2456 | +VideoLogoOption.delay = VideoLogoOption(4) |
2457 | +VideoLogoOption.enable = VideoLogoOption(0) |
2458 | +VideoLogoOption.file = VideoLogoOption(1) |
2459 | +VideoLogoOption.logo_x = VideoLogoOption(2) |
2460 | +VideoLogoOption.logo_y = VideoLogoOption(3) |
2461 | +VideoLogoOption.opacity = VideoLogoOption(6) |
2462 | VideoLogoOption.position = VideoLogoOption(7) |
2463 | -VideoLogoOption.repeat = VideoLogoOption(5) |
2464 | +VideoLogoOption.repeat = VideoLogoOption(5) |
2465 | + |
2466 | |
2467 | class VideoAdjustOption(_Enum): |
2468 | '''Option values for libvlc_video_{get,set}_adjust_{int,float,bool}. |
2469 | @@ -708,13 +998,16 @@ |
2470 | 4: 'Saturation', |
2471 | 5: 'Gamma', |
2472 | } |
2473 | + |
2474 | + |
2475 | VideoAdjustOption.Brightness = VideoAdjustOption(2) |
2476 | -VideoAdjustOption.Contrast = VideoAdjustOption(1) |
2477 | -VideoAdjustOption.Enable = VideoAdjustOption(0) |
2478 | -VideoAdjustOption.Gamma = VideoAdjustOption(5) |
2479 | -VideoAdjustOption.Hue = VideoAdjustOption(3) |
2480 | +VideoAdjustOption.Contrast = VideoAdjustOption(1) |
2481 | +VideoAdjustOption.Enable = VideoAdjustOption(0) |
2482 | +VideoAdjustOption.Gamma = VideoAdjustOption(5) |
2483 | +VideoAdjustOption.Hue = VideoAdjustOption(3) |
2484 | VideoAdjustOption.Saturation = VideoAdjustOption(4) |
2485 | |
2486 | + |
2487 | class AudioOutputDeviceTypes(_Enum): |
2488 | '''Audio device types. |
2489 | ''' |
2490 | @@ -729,15 +1022,18 @@ |
2491 | 8: '_7_1', |
2492 | 10: 'SPDIF', |
2493 | } |
2494 | -AudioOutputDeviceTypes.Error = AudioOutputDeviceTypes(-1) |
2495 | -AudioOutputDeviceTypes.Mono = AudioOutputDeviceTypes(1) |
2496 | -AudioOutputDeviceTypes.SPDIF = AudioOutputDeviceTypes(10) |
2497 | + |
2498 | + |
2499 | +AudioOutputDeviceTypes.Error = AudioOutputDeviceTypes(-1) |
2500 | +AudioOutputDeviceTypes.Mono = AudioOutputDeviceTypes(1) |
2501 | +AudioOutputDeviceTypes.SPDIF = AudioOutputDeviceTypes(10) |
2502 | AudioOutputDeviceTypes.Stereo = AudioOutputDeviceTypes(2) |
2503 | -AudioOutputDeviceTypes._2F2R = AudioOutputDeviceTypes(4) |
2504 | -AudioOutputDeviceTypes._3F2R = AudioOutputDeviceTypes(5) |
2505 | -AudioOutputDeviceTypes._5_1 = AudioOutputDeviceTypes(6) |
2506 | -AudioOutputDeviceTypes._6_1 = AudioOutputDeviceTypes(7) |
2507 | -AudioOutputDeviceTypes._7_1 = AudioOutputDeviceTypes(8) |
2508 | +AudioOutputDeviceTypes._2F2R = AudioOutputDeviceTypes(4) |
2509 | +AudioOutputDeviceTypes._3F2R = AudioOutputDeviceTypes(5) |
2510 | +AudioOutputDeviceTypes._5_1 = AudioOutputDeviceTypes(6) |
2511 | +AudioOutputDeviceTypes._6_1 = AudioOutputDeviceTypes(7) |
2512 | +AudioOutputDeviceTypes._7_1 = AudioOutputDeviceTypes(8) |
2513 | + |
2514 | |
2515 | class AudioOutputChannel(_Enum): |
2516 | '''Audio channels. |
2517 | @@ -750,308 +1046,455 @@ |
2518 | 4: 'Right', |
2519 | 5: 'Dolbys', |
2520 | } |
2521 | -AudioOutputChannel.Dolbys = AudioOutputChannel(5) |
2522 | -AudioOutputChannel.Error = AudioOutputChannel(-1) |
2523 | -AudioOutputChannel.Left = AudioOutputChannel(3) |
2524 | + |
2525 | + |
2526 | +AudioOutputChannel.Dolbys = AudioOutputChannel(5) |
2527 | +AudioOutputChannel.Error = AudioOutputChannel(-1) |
2528 | +AudioOutputChannel.Left = AudioOutputChannel(3) |
2529 | AudioOutputChannel.RStereo = AudioOutputChannel(2) |
2530 | -AudioOutputChannel.Right = AudioOutputChannel(4) |
2531 | -AudioOutputChannel.Stereo = AudioOutputChannel(1) |
2532 | +AudioOutputChannel.Right = AudioOutputChannel(4) |
2533 | +AudioOutputChannel.Stereo = AudioOutputChannel(1) |
2534 | + |
2535 | + |
2536 | +class MediaPlayerRole(_Enum): |
2537 | + '''Media player roles. |
2538 | +\version libvlc 3.0.0 and later. |
2539 | +see \ref libvlc_media_player_set_role(). |
2540 | + ''' |
2541 | + _enum_names_ = { |
2542 | + 0: '_None', |
2543 | + 1: 'Music', |
2544 | + 2: 'Video', |
2545 | + 3: 'Communication', |
2546 | + 4: 'Game', |
2547 | + 5: 'Notification', |
2548 | + 6: 'Animation', |
2549 | + 7: 'Production', |
2550 | + 8: 'Accessibility', |
2551 | + 9: 'Test', |
2552 | + } |
2553 | + |
2554 | + |
2555 | +MediaPlayerRole.Accessibility = MediaPlayerRole(8) |
2556 | +MediaPlayerRole.Animation = MediaPlayerRole(6) |
2557 | +MediaPlayerRole.Communication = MediaPlayerRole(3) |
2558 | +MediaPlayerRole.Game = MediaPlayerRole(4) |
2559 | +MediaPlayerRole.Music = MediaPlayerRole(1) |
2560 | +MediaPlayerRole.Notification = MediaPlayerRole(5) |
2561 | +MediaPlayerRole.Production = MediaPlayerRole(7) |
2562 | +MediaPlayerRole.Test = MediaPlayerRole(9) |
2563 | +MediaPlayerRole.Video = MediaPlayerRole(2) |
2564 | +MediaPlayerRole._None = MediaPlayerRole(0) |
2565 | + |
2566 | + |
2567 | +class PlaybackMode(_Enum): |
2568 | + '''Defines playback modes for playlist. |
2569 | + ''' |
2570 | + _enum_names_ = { |
2571 | + 0: 'default', |
2572 | + 1: 'loop', |
2573 | + 2: 'repeat', |
2574 | + } |
2575 | + |
2576 | + |
2577 | +PlaybackMode.default = PlaybackMode(0) |
2578 | +PlaybackMode.loop = PlaybackMode(1) |
2579 | +PlaybackMode.repeat = PlaybackMode(2) |
2580 | + |
2581 | |
2582 | class Callback(ctypes.c_void_p): |
2583 | - """Callback function notification |
2584 | -\param p_event the event triggering the callback |
2585 | + """Callback function notification. |
2586 | + @param p_event: the event triggering the callback. |
2587 | """ |
2588 | pass |
2589 | + |
2590 | + |
2591 | class LogCb(ctypes.c_void_p): |
2592 | """Callback prototype for LibVLC log message handler. |
2593 | -\param data data pointer as given to L{libvlc_log_set}() |
2594 | -\param level message level (@ref enum libvlc_log_level) |
2595 | -\param ctx message context (meta-information about the message) |
2596 | -\param fmt printf() format string (as defined by ISO C11) |
2597 | -\param args variable argument list for the format |
2598 | -\note Log message handlers <b>must</b> be thread-safe. |
2599 | -\warning The message context pointer, the format string parameters and the |
2600 | - variable arguments are only valid until the callback returns. |
2601 | - """ |
2602 | - pass |
2603 | + @param data: data pointer as given to L{libvlc_log_set}(). |
2604 | + @param level: message level (@ref L{LogLevel}). |
2605 | + @param ctx: message context (meta-information about the message). |
2606 | + @param fmt: printf() format string (as defined by ISO C11). |
2607 | + @param args: variable argument list for the format @note Log message handlers B{must} be thread-safe. @warning The message context pointer, the format string parameters and the variable arguments are only valid until the callback returns. |
2608 | + """ |
2609 | + pass |
2610 | + |
2611 | + |
2612 | +class MediaOpenCb(ctypes.c_void_p): |
2613 | + """Callback prototype to open a custom bitstream input media. |
2614 | + The same media item can be opened multiple times. Each time, this callback |
2615 | + is invoked. It should allocate and initialize any instance-specific |
2616 | + resources, then store them in *datap. The instance resources can be freed |
2617 | + in the @ref libvlc_media_close_cb callback. |
2618 | + @param opaque: private pointer as passed to L{libvlc_media_new_callbacks}(). |
2619 | + @return: datap storage space for a private data pointer, sizep byte length of the bitstream or UINT64_MAX if unknown. |
2620 | + """ |
2621 | + pass |
2622 | + |
2623 | + |
2624 | +class MediaReadCb(ctypes.c_void_p): |
2625 | + """Callback prototype to read data from a custom bitstream input media. |
2626 | + @param opaque: private pointer as set by the @ref libvlc_media_open_cb callback. |
2627 | + @param buf: start address of the buffer to read data into. |
2628 | + @param len: bytes length of the buffer. |
2629 | + @return: strictly positive number of bytes read, 0 on end-of-stream, or -1 on non-recoverable error @note If no data is immediately available, then the callback should sleep. @warning The application is responsible for avoiding deadlock situations. In particular, the callback should return an error if playback is stopped; if it does not return, then L{libvlc_media_player_stop}() will never return. |
2630 | + """ |
2631 | + pass |
2632 | + |
2633 | + |
2634 | +class MediaSeekCb(ctypes.c_void_p): |
2635 | + """Callback prototype to seek a custom bitstream input media. |
2636 | + @param opaque: private pointer as set by the @ref libvlc_media_open_cb callback. |
2637 | + @param offset: absolute byte offset to seek to. |
2638 | + @return: 0 on success, -1 on error. |
2639 | + """ |
2640 | + pass |
2641 | + |
2642 | + |
2643 | +class MediaCloseCb(ctypes.c_void_p): |
2644 | + """Callback prototype to close a custom bitstream input media. |
2645 | + @param opaque: private pointer as set by the @ref libvlc_media_open_cb callback. |
2646 | + """ |
2647 | + pass |
2648 | + |
2649 | + |
2650 | class VideoLockCb(ctypes.c_void_p): |
2651 | """Callback prototype to allocate and lock a picture buffer. |
2652 | -Whenever a new video frame needs to be decoded, the lock callback is |
2653 | -invoked. Depending on the video chroma, one or three pixel planes of |
2654 | -adequate dimensions must be returned via the second parameter. Those |
2655 | -planes must be aligned on 32-bytes boundaries. |
2656 | -\param opaque private pointer as passed to L{libvlc_video_set_callbacks}() [IN] |
2657 | -\param planes start address of the pixel planes (LibVLC allocates the array |
2658 | - of void pointers, this callback must initialize the array) [OUT] |
2659 | -\return a private pointer for the display and unlock callbacks to identify |
2660 | - the picture buffers |
2661 | + Whenever a new video frame needs to be decoded, the lock callback is |
2662 | + invoked. Depending on the video chroma, one or three pixel planes of |
2663 | + adequate dimensions must be returned via the second parameter. Those |
2664 | + planes must be aligned on 32-bytes boundaries. |
2665 | + @param opaque: private pointer as passed to L{libvlc_video_set_callbacks}() [IN]. |
2666 | + @param planes: start address of the pixel planes (LibVLC allocates the array of void pointers, this callback must initialize the array) [OUT]. |
2667 | + @return: a private pointer for the display and unlock callbacks to identify the picture buffers. |
2668 | """ |
2669 | pass |
2670 | + |
2671 | + |
2672 | class VideoUnlockCb(ctypes.c_void_p): |
2673 | """Callback prototype to unlock a picture buffer. |
2674 | -When the video frame decoding is complete, the unlock callback is invoked. |
2675 | -This callback might not be needed at all. It is only an indication that the |
2676 | -application can now read the pixel values if it needs to. |
2677 | -\warning A picture buffer is unlocked after the picture is decoded, |
2678 | -but before the picture is displayed. |
2679 | -\param opaque private pointer as passed to L{libvlc_video_set_callbacks}() [IN] |
2680 | -\param picture private pointer returned from the @ref libvlc_video_lock_cb |
2681 | - callback [IN] |
2682 | -\param planes pixel planes as defined by the @ref libvlc_video_lock_cb |
2683 | - callback (this parameter is only for convenience) [IN] |
2684 | + When the video frame decoding is complete, the unlock callback is invoked. |
2685 | + This callback might not be needed at all. It is only an indication that the |
2686 | + application can now read the pixel values if it needs to. |
2687 | + @note: A picture buffer is unlocked after the picture is decoded, |
2688 | + but before the picture is displayed. |
2689 | + @param opaque: private pointer as passed to L{libvlc_video_set_callbacks}() [IN]. |
2690 | + @param picture: private pointer returned from the @ref libvlc_video_lock_cb callback [IN]. |
2691 | + @param planes: pixel planes as defined by the @ref libvlc_video_lock_cb callback (this parameter is only for convenience) [IN]. |
2692 | """ |
2693 | pass |
2694 | + |
2695 | + |
2696 | class VideoDisplayCb(ctypes.c_void_p): |
2697 | """Callback prototype to display a picture. |
2698 | -When the video frame needs to be shown, as determined by the media playback |
2699 | -clock, the display callback is invoked. |
2700 | -\param opaque private pointer as passed to L{libvlc_video_set_callbacks}() [IN] |
2701 | -\param picture private pointer returned from the @ref libvlc_video_lock_cb |
2702 | - callback [IN] |
2703 | + When the video frame needs to be shown, as determined by the media playback |
2704 | + clock, the display callback is invoked. |
2705 | + @param opaque: private pointer as passed to L{libvlc_video_set_callbacks}() [IN]. |
2706 | + @param picture: private pointer returned from the @ref libvlc_video_lock_cb callback [IN]. |
2707 | """ |
2708 | pass |
2709 | + |
2710 | + |
2711 | class VideoFormatCb(ctypes.c_void_p): |
2712 | """Callback prototype to configure picture buffers format. |
2713 | -This callback gets the format of the video as output by the video decoder |
2714 | -and the chain of video filters (if any). It can opt to change any parameter |
2715 | -as it needs. In that case, LibVLC will attempt to convert the video format |
2716 | -(rescaling and chroma conversion) but these operations can be CPU intensive. |
2717 | -\param opaque pointer to the private pointer passed to |
2718 | - L{libvlc_video_set_callbacks}() [IN/OUT] |
2719 | -\param chroma pointer to the 4 bytes video format identifier [IN/OUT] |
2720 | -\param width pointer to the pixel width [IN/OUT] |
2721 | -\param height pointer to the pixel height [IN/OUT] |
2722 | -\param pitches table of scanline pitches in bytes for each pixel plane |
2723 | - (the table is allocated by LibVLC) [OUT] |
2724 | -\param lines table of scanlines count for each plane [OUT] |
2725 | -\return the number of picture buffers allocated, 0 indicates failure |
2726 | -\note |
2727 | -For each pixels plane, the scanline pitch must be bigger than or equal to |
2728 | -the number of bytes per pixel multiplied by the pixel width. |
2729 | -Similarly, the number of scanlines must be bigger than of equal to |
2730 | -the pixel height. |
2731 | -Furthermore, we recommend that pitches and lines be multiple of 32 |
2732 | -to not break assumption that might be made by various optimizations |
2733 | -in the video decoders, video filters and/or video converters. |
2734 | + This callback gets the format of the video as output by the video decoder |
2735 | + and the chain of video filters (if any). It can opt to change any parameter |
2736 | + as it needs. In that case, LibVLC will attempt to convert the video format |
2737 | + (rescaling and chroma conversion) but these operations can be CPU intensive. |
2738 | + @param opaque: pointer to the private pointer passed to L{libvlc_video_set_callbacks}() [IN/OUT]. |
2739 | + @param chroma: pointer to the 4 bytes video format identifier [IN/OUT]. |
2740 | + @param width: pointer to the pixel width [IN/OUT]. |
2741 | + @param height: pointer to the pixel height [IN/OUT]. |
2742 | + @param pitches: table of scanline pitches in bytes for each pixel plane (the table is allocated by LibVLC) [OUT]. |
2743 | + @return: lines table of scanlines count for each plane. |
2744 | """ |
2745 | pass |
2746 | + |
2747 | + |
2748 | class VideoCleanupCb(ctypes.c_void_p): |
2749 | """Callback prototype to configure picture buffers format. |
2750 | -\param opaque private pointer as passed to L{libvlc_video_set_callbacks}() |
2751 | - (and possibly modified by @ref libvlc_video_format_cb) [IN] |
2752 | + @param opaque: private pointer as passed to L{libvlc_video_set_callbacks}() (and possibly modified by @ref libvlc_video_format_cb) [IN]. |
2753 | """ |
2754 | pass |
2755 | + |
2756 | + |
2757 | class AudioPlayCb(ctypes.c_void_p): |
2758 | """Callback prototype for audio playback. |
2759 | -\param data data pointer as passed to L{libvlc_audio_set_callbacks}() [IN] |
2760 | -\param samples pointer to the first audio sample to play back [IN] |
2761 | -\param count number of audio samples to play back |
2762 | -\param pts expected play time stamp (see libvlc_delay()) |
2763 | + The LibVLC media player decodes and post-processes the audio signal |
2764 | + asynchronously (in an internal thread). Whenever audio samples are ready |
2765 | + to be queued to the output, this callback is invoked. |
2766 | + The number of samples provided per invocation may depend on the file format, |
2767 | + the audio coding algorithm, the decoder plug-in, the post-processing |
2768 | + filters and timing. Application must not assume a certain number of samples. |
2769 | + The exact format of audio samples is determined by L{libvlc_audio_set_format}() |
2770 | + or L{libvlc_audio_set_format_callbacks}() as is the channels layout. |
2771 | + Note that the number of samples is per channel. For instance, if the audio |
2772 | + track sampling rate is 48000 Hz, then 1200 samples represent 25 milliseconds |
2773 | + of audio signal - regardless of the number of audio channels. |
2774 | + @param data: data pointer as passed to L{libvlc_audio_set_callbacks}() [IN]. |
2775 | + @param samples: pointer to a table of audio samples to play back [IN]. |
2776 | + @param count: number of audio samples to play back. |
2777 | + @param pts: expected play time stamp (see libvlc_delay()). |
2778 | """ |
2779 | pass |
2780 | + |
2781 | + |
2782 | class AudioPauseCb(ctypes.c_void_p): |
2783 | """Callback prototype for audio pause. |
2784 | -\note The pause callback is never called if the audio is already paused. |
2785 | -\param data data pointer as passed to L{libvlc_audio_set_callbacks}() [IN] |
2786 | -\param pts time stamp of the pause request (should be elapsed already) |
2787 | + LibVLC invokes this callback to pause audio playback. |
2788 | + @note: The pause callback is never called if the audio is already paused. |
2789 | + @param data: data pointer as passed to L{libvlc_audio_set_callbacks}() [IN]. |
2790 | + @param pts: time stamp of the pause request (should be elapsed already). |
2791 | """ |
2792 | pass |
2793 | + |
2794 | + |
2795 | class AudioResumeCb(ctypes.c_void_p): |
2796 | - """Callback prototype for audio resumption (i.e. restart from pause). |
2797 | -\note The resume callback is never called if the audio is not paused. |
2798 | -\param data data pointer as passed to L{libvlc_audio_set_callbacks}() [IN] |
2799 | -\param pts time stamp of the resumption request (should be elapsed already) |
2800 | + """Callback prototype for audio resumption. |
2801 | + LibVLC invokes this callback to resume audio playback after it was |
2802 | + previously paused. |
2803 | + @note: The resume callback is never called if the audio is not paused. |
2804 | + @param data: data pointer as passed to L{libvlc_audio_set_callbacks}() [IN]. |
2805 | + @param pts: time stamp of the resumption request (should be elapsed already). |
2806 | """ |
2807 | pass |
2808 | + |
2809 | + |
2810 | class AudioFlushCb(ctypes.c_void_p): |
2811 | - """Callback prototype for audio buffer flush |
2812 | -(i.e. discard all pending buffers and stop playback as soon as possible). |
2813 | -\param data data pointer as passed to L{libvlc_audio_set_callbacks}() [IN] |
2814 | + """Callback prototype for audio buffer flush. |
2815 | + LibVLC invokes this callback if it needs to discard all pending buffers and |
2816 | + stop playback as soon as possible. This typically occurs when the media is |
2817 | + stopped. |
2818 | + @param data: data pointer as passed to L{libvlc_audio_set_callbacks}() [IN]. |
2819 | """ |
2820 | pass |
2821 | + |
2822 | + |
2823 | class AudioDrainCb(ctypes.c_void_p): |
2824 | - """Callback prototype for audio buffer drain |
2825 | -(i.e. wait for pending buffers to be played). |
2826 | -\param data data pointer as passed to L{libvlc_audio_set_callbacks}() [IN] |
2827 | + """Callback prototype for audio buffer drain. |
2828 | + LibVLC may invoke this callback when the decoded audio track is ending. |
2829 | + There will be no further decoded samples for the track, but playback should |
2830 | + nevertheless continue until all already pending buffers are rendered. |
2831 | + @param data: data pointer as passed to L{libvlc_audio_set_callbacks}() [IN]. |
2832 | """ |
2833 | pass |
2834 | + |
2835 | + |
2836 | class AudioSetVolumeCb(ctypes.c_void_p): |
2837 | """Callback prototype for audio volume change. |
2838 | -\param data data pointer as passed to L{libvlc_audio_set_callbacks}() [IN] |
2839 | -\param volume software volume (1. = nominal, 0. = mute) |
2840 | -\param mute muted flag |
2841 | + @param data: data pointer as passed to L{libvlc_audio_set_callbacks}() [IN]. |
2842 | + @param volume: software volume (1. = nominal, 0. = mute). |
2843 | + @param mute: muted flag. |
2844 | """ |
2845 | pass |
2846 | + |
2847 | + |
2848 | class AudioSetupCb(ctypes.c_void_p): |
2849 | """Callback prototype to setup the audio playback. |
2850 | -This is called when the media player needs to create a new audio output. |
2851 | -\param opaque pointer to the data pointer passed to |
2852 | - L{libvlc_audio_set_callbacks}() [IN/OUT] |
2853 | -\param format 4 bytes sample format [IN/OUT] |
2854 | -\param rate sample rate [IN/OUT] |
2855 | -\param channels channels count [IN/OUT] |
2856 | -\return 0 on success, anything else to skip audio playback |
2857 | + This is called when the media player needs to create a new audio output. |
2858 | + @param opaque: pointer to the data pointer passed to L{libvlc_audio_set_callbacks}() [IN/OUT]. |
2859 | + @param format: 4 bytes sample format [IN/OUT]. |
2860 | + @param rate: sample rate [IN/OUT]. |
2861 | + @param channels: channels count [IN/OUT]. |
2862 | + @return: 0 on success, anything else to skip audio playback. |
2863 | """ |
2864 | pass |
2865 | + |
2866 | + |
2867 | class AudioCleanupCb(ctypes.c_void_p): |
2868 | """Callback prototype for audio playback cleanup. |
2869 | -This is called when the media player no longer needs an audio output. |
2870 | -\param opaque data pointer as passed to L{libvlc_audio_set_callbacks}() [IN] |
2871 | + This is called when the media player no longer needs an audio output. |
2872 | + @param opaque: data pointer as passed to L{libvlc_audio_set_callbacks}() [IN]. |
2873 | """ |
2874 | pass |
2875 | + |
2876 | + |
2877 | class CallbackDecorators(object): |
2878 | "Class holding various method decorators for callback functions." |
2879 | Callback = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) |
2880 | - Callback.__doc__ = '''Callback function notification |
2881 | -\param p_event the event triggering the callback |
2882 | - ''' |
2883 | + Callback.__doc__ = '''Callback function notification. |
2884 | + @param p_event: the event triggering the callback. |
2885 | + ''' |
2886 | LogCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, Log_ptr, ctypes.c_char_p, ctypes.c_void_p) |
2887 | LogCb.__doc__ = '''Callback prototype for LibVLC log message handler. |
2888 | -\param data data pointer as given to L{libvlc_log_set}() |
2889 | -\param level message level (@ref enum libvlc_log_level) |
2890 | -\param ctx message context (meta-information about the message) |
2891 | -\param fmt printf() format string (as defined by ISO C11) |
2892 | -\param args variable argument list for the format |
2893 | -\note Log message handlers <b>must</b> be thread-safe. |
2894 | -\warning The message context pointer, the format string parameters and the |
2895 | - variable arguments are only valid until the callback returns. |
2896 | - ''' |
2897 | - VideoLockCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ListPOINTER(ctypes.c_void_p)) |
2898 | + @param data: data pointer as given to L{libvlc_log_set}(). |
2899 | + @param level: message level (@ref L{LogLevel}). |
2900 | + @param ctx: message context (meta-information about the message). |
2901 | + @param fmt: printf() format string (as defined by ISO C11). |
2902 | + @param args: variable argument list for the format @note Log message handlers B{must} be thread-safe. @warning The message context pointer, the format string parameters and the variable arguments are only valid until the callback returns. |
2903 | + ''' |
2904 | + MediaOpenCb = ctypes.CFUNCTYPE(ctypes.POINTER(ctypes.c_int), ctypes.c_void_p, ctypes.POINTER(ctypes.c_void_p), |
2905 | + ctypes.POINTER(ctypes.c_uint64)) |
2906 | + MediaOpenCb.__doc__ = '''Callback prototype to open a custom bitstream input media. |
2907 | + The same media item can be opened multiple times. Each time, this callback |
2908 | + is invoked. It should allocate and initialize any instance-specific |
2909 | + resources, then store them in *datap. The instance resources can be freed |
2910 | + in the @ref libvlc_media_close_cb callback. |
2911 | + @param opaque: private pointer as passed to L{libvlc_media_new_callbacks}(). |
2912 | + @return: datap storage space for a private data pointer, sizep byte length of the bitstream or UINT64_MAX if unknown. |
2913 | + ''' |
2914 | + MediaReadCb = ctypes.CFUNCTYPE(ctypes.POINTER(ctypes.c_ssize_t), ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t) |
2915 | + MediaReadCb.__doc__ = '''Callback prototype to read data from a custom bitstream input media. |
2916 | + @param opaque: private pointer as set by the @ref libvlc_media_open_cb callback. |
2917 | + @param buf: start address of the buffer to read data into. |
2918 | + @param len: bytes length of the buffer. |
2919 | + @return: strictly positive number of bytes read, 0 on end-of-stream, or -1 on non-recoverable error @note If no data is immediately available, then the callback should sleep. @warning The application is responsible for avoiding deadlock situations. In particular, the callback should return an error if playback is stopped; if it does not return, then L{libvlc_media_player_stop}() will never return. |
2920 | + ''' |
2921 | + MediaSeekCb = ctypes.CFUNCTYPE(ctypes.POINTER(ctypes.c_int), ctypes.c_void_p, ctypes.c_uint64) |
2922 | + MediaSeekCb.__doc__ = '''Callback prototype to seek a custom bitstream input media. |
2923 | + @param opaque: private pointer as set by the @ref libvlc_media_open_cb callback. |
2924 | + @param offset: absolute byte offset to seek to. |
2925 | + @return: 0 on success, -1 on error. |
2926 | + ''' |
2927 | + MediaCloseCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p) |
2928 | + MediaCloseCb.__doc__ = '''Callback prototype to close a custom bitstream input media. |
2929 | + @param opaque: private pointer as set by the @ref libvlc_media_open_cb callback. |
2930 | + ''' |
2931 | + VideoLockCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.POINTER(ctypes.c_void_p)) |
2932 | VideoLockCb.__doc__ = '''Callback prototype to allocate and lock a picture buffer. |
2933 | -Whenever a new video frame needs to be decoded, the lock callback is |
2934 | -invoked. Depending on the video chroma, one or three pixel planes of |
2935 | -adequate dimensions must be returned via the second parameter. Those |
2936 | -planes must be aligned on 32-bytes boundaries. |
2937 | -\param opaque private pointer as passed to L{libvlc_video_set_callbacks}() [IN] |
2938 | -\param planes start address of the pixel planes (LibVLC allocates the array |
2939 | - of void pointers, this callback must initialize the array) [OUT] |
2940 | -\return a private pointer for the display and unlock callbacks to identify |
2941 | - the picture buffers |
2942 | - ''' |
2943 | - VideoUnlockCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ListPOINTER(ctypes.c_void_p)) |
2944 | + Whenever a new video frame needs to be decoded, the lock callback is |
2945 | + invoked. Depending on the video chroma, one or three pixel planes of |
2946 | + adequate dimensions must be returned via the second parameter. Those |
2947 | + planes must be aligned on 32-bytes boundaries. |
2948 | + @param opaque: private pointer as passed to L{libvlc_video_set_callbacks}() [IN]. |
2949 | + @param planes: start address of the pixel planes (LibVLC allocates the array of void pointers, this callback must initialize the array) [OUT]. |
2950 | + @return: a private pointer for the display and unlock callbacks to identify the picture buffers. |
2951 | + ''' |
2952 | + VideoUnlockCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.POINTER(ctypes.c_void_p)) |
2953 | VideoUnlockCb.__doc__ = '''Callback prototype to unlock a picture buffer. |
2954 | -When the video frame decoding is complete, the unlock callback is invoked. |
2955 | -This callback might not be needed at all. It is only an indication that the |
2956 | -application can now read the pixel values if it needs to. |
2957 | -\warning A picture buffer is unlocked after the picture is decoded, |
2958 | -but before the picture is displayed. |
2959 | -\param opaque private pointer as passed to L{libvlc_video_set_callbacks}() [IN] |
2960 | -\param picture private pointer returned from the @ref libvlc_video_lock_cb |
2961 | - callback [IN] |
2962 | -\param planes pixel planes as defined by the @ref libvlc_video_lock_cb |
2963 | - callback (this parameter is only for convenience) [IN] |
2964 | - ''' |
2965 | + When the video frame decoding is complete, the unlock callback is invoked. |
2966 | + This callback might not be needed at all. It is only an indication that the |
2967 | + application can now read the pixel values if it needs to. |
2968 | + @note: A picture buffer is unlocked after the picture is decoded, |
2969 | + but before the picture is displayed. |
2970 | + @param opaque: private pointer as passed to L{libvlc_video_set_callbacks}() [IN]. |
2971 | + @param picture: private pointer returned from the @ref libvlc_video_lock_cb callback [IN]. |
2972 | + @param planes: pixel planes as defined by the @ref libvlc_video_lock_cb callback (this parameter is only for convenience) [IN]. |
2973 | + ''' |
2974 | VideoDisplayCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) |
2975 | VideoDisplayCb.__doc__ = '''Callback prototype to display a picture. |
2976 | -When the video frame needs to be shown, as determined by the media playback |
2977 | -clock, the display callback is invoked. |
2978 | -\param opaque private pointer as passed to L{libvlc_video_set_callbacks}() [IN] |
2979 | -\param picture private pointer returned from the @ref libvlc_video_lock_cb |
2980 | - callback [IN] |
2981 | - ''' |
2982 | - VideoFormatCb = ctypes.CFUNCTYPE(ctypes.POINTER(ctypes.c_uint), ListPOINTER(ctypes.c_void_p), ctypes.c_char_p, ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_uint)) |
2983 | + When the video frame needs to be shown, as determined by the media playback |
2984 | + clock, the display callback is invoked. |
2985 | + @param opaque: private pointer as passed to L{libvlc_video_set_callbacks}() [IN]. |
2986 | + @param picture: private pointer returned from the @ref libvlc_video_lock_cb callback [IN]. |
2987 | + ''' |
2988 | + VideoFormatCb = ctypes.CFUNCTYPE(ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_void_p), ctypes.c_char_p, |
2989 | + ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_uint), |
2990 | + ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_uint)) |
2991 | VideoFormatCb.__doc__ = '''Callback prototype to configure picture buffers format. |
2992 | -This callback gets the format of the video as output by the video decoder |
2993 | -and the chain of video filters (if any). It can opt to change any parameter |
2994 | -as it needs. In that case, LibVLC will attempt to convert the video format |
2995 | -(rescaling and chroma conversion) but these operations can be CPU intensive. |
2996 | -\param opaque pointer to the private pointer passed to |
2997 | - L{libvlc_video_set_callbacks}() [IN/OUT] |
2998 | -\param chroma pointer to the 4 bytes video format identifier [IN/OUT] |
2999 | -\param width pointer to the pixel width [IN/OUT] |
3000 | -\param height pointer to the pixel height [IN/OUT] |
3001 | -\param pitches table of scanline pitches in bytes for each pixel plane |
3002 | - (the table is allocated by LibVLC) [OUT] |
3003 | -\param lines table of scanlines count for each plane [OUT] |
3004 | -\return the number of picture buffers allocated, 0 indicates failure |
3005 | -\note |
3006 | -For each pixels plane, the scanline pitch must be bigger than or equal to |
3007 | -the number of bytes per pixel multiplied by the pixel width. |
3008 | -Similarly, the number of scanlines must be bigger than of equal to |
3009 | -the pixel height. |
3010 | -Furthermore, we recommend that pitches and lines be multiple of 32 |
3011 | -to not break assumption that might be made by various optimizations |
3012 | -in the video decoders, video filters and/or video converters. |
3013 | - ''' |
3014 | + This callback gets the format of the video as output by the video decoder |
3015 | + and the chain of video filters (if any). It can opt to change any parameter |
3016 | + as it needs. In that case, LibVLC will attempt to convert the video format |
3017 | + (rescaling and chroma conversion) but these operations can be CPU intensive. |
3018 | + @param opaque: pointer to the private pointer passed to L{libvlc_video_set_callbacks}() [IN/OUT]. |
3019 | + @param chroma: pointer to the 4 bytes video format identifier [IN/OUT]. |
3020 | + @param width: pointer to the pixel width [IN/OUT]. |
3021 | + @param height: pointer to the pixel height [IN/OUT]. |
3022 | + @param pitches: table of scanline pitches in bytes for each pixel plane (the table is allocated by LibVLC) [OUT]. |
3023 | + @return: lines table of scanlines count for each plane. |
3024 | + ''' |
3025 | VideoCleanupCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p) |
3026 | VideoCleanupCb.__doc__ = '''Callback prototype to configure picture buffers format. |
3027 | -\param opaque private pointer as passed to L{libvlc_video_set_callbacks}() |
3028 | - (and possibly modified by @ref libvlc_video_format_cb) [IN] |
3029 | - ''' |
3030 | + @param opaque: private pointer as passed to L{libvlc_video_set_callbacks}() (and possibly modified by @ref libvlc_video_format_cb) [IN]. |
3031 | + ''' |
3032 | AudioPlayCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint, ctypes.c_int64) |
3033 | AudioPlayCb.__doc__ = '''Callback prototype for audio playback. |
3034 | -\param data data pointer as passed to L{libvlc_audio_set_callbacks}() [IN] |
3035 | -\param samples pointer to the first audio sample to play back [IN] |
3036 | -\param count number of audio samples to play back |
3037 | -\param pts expected play time stamp (see libvlc_delay()) |
3038 | - ''' |
3039 | + The LibVLC media player decodes and post-processes the audio signal |
3040 | + asynchronously (in an internal thread). Whenever audio samples are ready |
3041 | + to be queued to the output, this callback is invoked. |
3042 | + The number of samples provided per invocation may depend on the file format, |
3043 | + the audio coding algorithm, the decoder plug-in, the post-processing |
3044 | + filters and timing. Application must not assume a certain number of samples. |
3045 | + The exact format of audio samples is determined by L{libvlc_audio_set_format}() |
3046 | + or L{libvlc_audio_set_format_callbacks}() as is the channels layout. |
3047 | + Note that the number of samples is per channel. For instance, if the audio |
3048 | + track sampling rate is 48000 Hz, then 1200 samples represent 25 milliseconds |
3049 | + of audio signal - regardless of the number of audio channels. |
3050 | + @param data: data pointer as passed to L{libvlc_audio_set_callbacks}() [IN]. |
3051 | + @param samples: pointer to a table of audio samples to play back [IN]. |
3052 | + @param count: number of audio samples to play back. |
3053 | + @param pts: expected play time stamp (see libvlc_delay()). |
3054 | + ''' |
3055 | AudioPauseCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int64) |
3056 | AudioPauseCb.__doc__ = '''Callback prototype for audio pause. |
3057 | -\note The pause callback is never called if the audio is already paused. |
3058 | -\param data data pointer as passed to L{libvlc_audio_set_callbacks}() [IN] |
3059 | -\param pts time stamp of the pause request (should be elapsed already) |
3060 | - ''' |
3061 | + LibVLC invokes this callback to pause audio playback. |
3062 | + @note: The pause callback is never called if the audio is already paused. |
3063 | + @param data: data pointer as passed to L{libvlc_audio_set_callbacks}() [IN]. |
3064 | + @param pts: time stamp of the pause request (should be elapsed already). |
3065 | + ''' |
3066 | AudioResumeCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int64) |
3067 | - AudioResumeCb.__doc__ = '''Callback prototype for audio resumption (i.e. restart from pause). |
3068 | -\note The resume callback is never called if the audio is not paused. |
3069 | -\param data data pointer as passed to L{libvlc_audio_set_callbacks}() [IN] |
3070 | -\param pts time stamp of the resumption request (should be elapsed already) |
3071 | - ''' |
3072 | + AudioResumeCb.__doc__ = '''Callback prototype for audio resumption. |
3073 | + LibVLC invokes this callback to resume audio playback after it was |
3074 | + previously paused. |
3075 | + @note: The resume callback is never called if the audio is not paused. |
3076 | + @param data: data pointer as passed to L{libvlc_audio_set_callbacks}() [IN]. |
3077 | + @param pts: time stamp of the resumption request (should be elapsed already). |
3078 | + ''' |
3079 | AudioFlushCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int64) |
3080 | - AudioFlushCb.__doc__ = '''Callback prototype for audio buffer flush |
3081 | -(i.e. discard all pending buffers and stop playback as soon as possible). |
3082 | -\param data data pointer as passed to L{libvlc_audio_set_callbacks}() [IN] |
3083 | - ''' |
3084 | + AudioFlushCb.__doc__ = '''Callback prototype for audio buffer flush. |
3085 | + LibVLC invokes this callback if it needs to discard all pending buffers and |
3086 | + stop playback as soon as possible. This typically occurs when the media is |
3087 | + stopped. |
3088 | + @param data: data pointer as passed to L{libvlc_audio_set_callbacks}() [IN]. |
3089 | + ''' |
3090 | AudioDrainCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p) |
3091 | - AudioDrainCb.__doc__ = '''Callback prototype for audio buffer drain |
3092 | -(i.e. wait for pending buffers to be played). |
3093 | -\param data data pointer as passed to L{libvlc_audio_set_callbacks}() [IN] |
3094 | - ''' |
3095 | + AudioDrainCb.__doc__ = '''Callback prototype for audio buffer drain. |
3096 | + LibVLC may invoke this callback when the decoded audio track is ending. |
3097 | + There will be no further decoded samples for the track, but playback should |
3098 | + nevertheless continue until all already pending buffers are rendered. |
3099 | + @param data: data pointer as passed to L{libvlc_audio_set_callbacks}() [IN]. |
3100 | + ''' |
3101 | AudioSetVolumeCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_float, ctypes.c_bool) |
3102 | AudioSetVolumeCb.__doc__ = '''Callback prototype for audio volume change. |
3103 | -\param data data pointer as passed to L{libvlc_audio_set_callbacks}() [IN] |
3104 | -\param volume software volume (1. = nominal, 0. = mute) |
3105 | -\param mute muted flag |
3106 | - ''' |
3107 | - AudioSetupCb = ctypes.CFUNCTYPE(ctypes.POINTER(ctypes.c_int), ListPOINTER(ctypes.c_void_p), ctypes.c_char_p, ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_uint)) |
3108 | + @param data: data pointer as passed to L{libvlc_audio_set_callbacks}() [IN]. |
3109 | + @param volume: software volume (1. = nominal, 0. = mute). |
3110 | + @param mute: muted flag. |
3111 | + ''' |
3112 | + AudioSetupCb = ctypes.CFUNCTYPE(ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_void_p), ctypes.c_char_p, |
3113 | + ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_uint)) |
3114 | AudioSetupCb.__doc__ = '''Callback prototype to setup the audio playback. |
3115 | -This is called when the media player needs to create a new audio output. |
3116 | -\param opaque pointer to the data pointer passed to |
3117 | - L{libvlc_audio_set_callbacks}() [IN/OUT] |
3118 | -\param format 4 bytes sample format [IN/OUT] |
3119 | -\param rate sample rate [IN/OUT] |
3120 | -\param channels channels count [IN/OUT] |
3121 | -\return 0 on success, anything else to skip audio playback |
3122 | - ''' |
3123 | + This is called when the media player needs to create a new audio output. |
3124 | + @param opaque: pointer to the data pointer passed to L{libvlc_audio_set_callbacks}() [IN/OUT]. |
3125 | + @param format: 4 bytes sample format [IN/OUT]. |
3126 | + @param rate: sample rate [IN/OUT]. |
3127 | + @param channels: channels count [IN/OUT]. |
3128 | + @return: 0 on success, anything else to skip audio playback. |
3129 | + ''' |
3130 | AudioCleanupCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p) |
3131 | AudioCleanupCb.__doc__ = '''Callback prototype for audio playback cleanup. |
3132 | -This is called when the media player no longer needs an audio output. |
3133 | -\param opaque data pointer as passed to L{libvlc_audio_set_callbacks}() [IN] |
3134 | - ''' |
3135 | + This is called when the media player no longer needs an audio output. |
3136 | + @param opaque: data pointer as passed to L{libvlc_audio_set_callbacks}() [IN]. |
3137 | + ''' |
3138 | + |
3139 | + |
3140 | cb = CallbackDecorators |
3141 | - # End of generated enum types # |
3142 | - |
3143 | - # From libvlc_structures.h |
3144 | + |
3145 | + |
3146 | +# End of generated enum types # |
3147 | + |
3148 | +# From libvlc_structures.h |
3149 | |
3150 | class AudioOutput(_Cstruct): |
3151 | |
3152 | def __str__(self): |
3153 | return '%s(%s:%s)' % (self.__class__.__name__, self.name, self.description) |
3154 | |
3155 | + |
3156 | AudioOutput._fields_ = [ # recursive struct |
3157 | - ('name', ctypes.c_char_p), |
3158 | + ('name', ctypes.c_char_p), |
3159 | ('description', ctypes.c_char_p), |
3160 | - ('next', ctypes.POINTER(AudioOutput)), |
3161 | - ] |
3162 | + ('next', ctypes.POINTER(AudioOutput)), |
3163 | +] |
3164 | + |
3165 | |
3166 | class LogMessage(_Cstruct): |
3167 | _fields_ = [ |
3168 | - ('size', ctypes.c_uint ), |
3169 | - ('severity', ctypes.c_int ), |
3170 | - ('type', ctypes.c_char_p), |
3171 | - ('name', ctypes.c_char_p), |
3172 | - ('header', ctypes.c_char_p), |
3173 | - ('message', ctypes.c_char_p), |
3174 | + ('size', ctypes.c_uint), |
3175 | + ('severity', ctypes.c_int), |
3176 | + ('type', ctypes.c_char_p), |
3177 | + ('name', ctypes.c_char_p), |
3178 | + ('header', ctypes.c_char_p), |
3179 | + ('message', ctypes.c_char_p), |
3180 | ] |
3181 | |
3182 | def __init__(self): |
3183 | @@ -1061,47 +1504,52 @@ |
3184 | def __str__(self): |
3185 | return '%s(%d:%s): %s' % (self.__class__.__name__, self.severity, self.type, self.message) |
3186 | |
3187 | + |
3188 | class MediaEvent(_Cstruct): |
3189 | _fields_ = [ |
3190 | - ('media_name', ctypes.c_char_p), |
3191 | + ('media_name', ctypes.c_char_p), |
3192 | ('instance_name', ctypes.c_char_p), |
3193 | ] |
3194 | |
3195 | + |
3196 | class MediaStats(_Cstruct): |
3197 | _fields_ = [ |
3198 | - ('read_bytes', ctypes.c_int ), |
3199 | - ('input_bitrate', ctypes.c_float), |
3200 | - ('demux_read_bytes', ctypes.c_int ), |
3201 | - ('demux_bitrate', ctypes.c_float), |
3202 | - ('demux_corrupted', ctypes.c_int ), |
3203 | - ('demux_discontinuity', ctypes.c_int ), |
3204 | - ('decoded_video', ctypes.c_int ), |
3205 | - ('decoded_audio', ctypes.c_int ), |
3206 | - ('displayed_pictures', ctypes.c_int ), |
3207 | - ('lost_pictures', ctypes.c_int ), |
3208 | - ('played_abuffers', ctypes.c_int ), |
3209 | - ('lost_abuffers', ctypes.c_int ), |
3210 | - ('sent_packets', ctypes.c_int ), |
3211 | - ('sent_bytes', ctypes.c_int ), |
3212 | - ('send_bitrate', ctypes.c_float), |
3213 | + ('read_bytes', ctypes.c_int), |
3214 | + ('input_bitrate', ctypes.c_float), |
3215 | + ('demux_read_bytes', ctypes.c_int), |
3216 | + ('demux_bitrate', ctypes.c_float), |
3217 | + ('demux_corrupted', ctypes.c_int), |
3218 | + ('demux_discontinuity', ctypes.c_int), |
3219 | + ('decoded_video', ctypes.c_int), |
3220 | + ('decoded_audio', ctypes.c_int), |
3221 | + ('displayed_pictures', ctypes.c_int), |
3222 | + ('lost_pictures', ctypes.c_int), |
3223 | + ('played_abuffers', ctypes.c_int), |
3224 | + ('lost_abuffers', ctypes.c_int), |
3225 | + ('sent_packets', ctypes.c_int), |
3226 | + ('sent_bytes', ctypes.c_int), |
3227 | + ('send_bitrate', ctypes.c_float), |
3228 | ] |
3229 | |
3230 | + |
3231 | class MediaTrackInfo(_Cstruct): |
3232 | _fields_ = [ |
3233 | - ('codec', ctypes.c_uint32), |
3234 | - ('id', ctypes.c_int ), |
3235 | - ('type', TrackType ), |
3236 | - ('profile', ctypes.c_int ), |
3237 | - ('level', ctypes.c_int ), |
3238 | - ('channels_or_height', ctypes.c_uint ), |
3239 | - ('rate_or_width', ctypes.c_uint ), |
3240 | + ('codec', ctypes.c_uint32), |
3241 | + ('id', ctypes.c_int), |
3242 | + ('type', TrackType), |
3243 | + ('profile', ctypes.c_int), |
3244 | + ('level', ctypes.c_int), |
3245 | + ('channels_or_height', ctypes.c_uint), |
3246 | + ('rate_or_width', ctypes.c_uint), |
3247 | ] |
3248 | |
3249 | + |
3250 | class AudioTrack(_Cstruct): |
3251 | _fields_ = [ |
3252 | ('channels', ctypes.c_uint), |
3253 | ('rate', ctypes.c_uint), |
3254 | - ] |
3255 | + ] |
3256 | + |
3257 | |
3258 | class VideoTrack(_Cstruct): |
3259 | _fields_ = [ |
3260 | @@ -1111,87 +1559,98 @@ |
3261 | ('sar_den', ctypes.c_uint), |
3262 | ('frame_rate_num', ctypes.c_uint), |
3263 | ('frame_rate_den', ctypes.c_uint), |
3264 | - ] |
3265 | + ] |
3266 | + |
3267 | |
3268 | class SubtitleTrack(_Cstruct): |
3269 | _fields_ = [ |
3270 | ('encoding', ctypes.c_char_p), |
3271 | - ] |
3272 | + ] |
3273 | + |
3274 | |
3275 | class MediaTrackTracks(ctypes.Union): |
3276 | _fields_ = [ |
3277 | ('audio', ctypes.POINTER(AudioTrack)), |
3278 | ('video', ctypes.POINTER(VideoTrack)), |
3279 | ('subtitle', ctypes.POINTER(SubtitleTrack)), |
3280 | - ] |
3281 | + ] |
3282 | + |
3283 | |
3284 | class MediaTrack(_Cstruct): |
3285 | _anonymous_ = ("u",) |
3286 | _fields_ = [ |
3287 | - ('codec', ctypes.c_uint32), |
3288 | - ('original_fourcc', ctypes.c_uint32), |
3289 | - ('id', ctypes.c_int ), |
3290 | - ('type', TrackType ), |
3291 | - ('profile', ctypes.c_int ), |
3292 | - ('level', ctypes.c_int ), |
3293 | - |
3294 | - ('u', MediaTrackTracks), |
3295 | - ('bitrate', ctypes.c_uint), |
3296 | - ('language', ctypes.c_char_p), |
3297 | - ('description', ctypes.c_char_p), |
3298 | - ] |
3299 | + ('codec', ctypes.c_uint32), |
3300 | + ('original_fourcc', ctypes.c_uint32), |
3301 | + ('id', ctypes.c_int), |
3302 | + ('type', TrackType), |
3303 | + ('profile', ctypes.c_int), |
3304 | + ('level', ctypes.c_int), |
3305 | + |
3306 | + ('u', MediaTrackTracks), |
3307 | + ('bitrate', ctypes.c_uint), |
3308 | + ('language', ctypes.c_char_p), |
3309 | + ('description', ctypes.c_char_p), |
3310 | + ] |
3311 | + |
3312 | |
3313 | class PlaylistItem(_Cstruct): |
3314 | _fields_ = [ |
3315 | - ('id', ctypes.c_int ), |
3316 | - ('uri', ctypes.c_char_p), |
3317 | + ('id', ctypes.c_int), |
3318 | + ('uri', ctypes.c_char_p), |
3319 | ('name', ctypes.c_char_p), |
3320 | ] |
3321 | |
3322 | def __str__(self): |
3323 | return '%s #%d %s (uri %s)' % (self.__class__.__name__, self.id, self.name, self.uri) |
3324 | |
3325 | + |
3326 | class Position(object): |
3327 | """Enum-like, immutable window position constants. |
3328 | |
3329 | See e.g. VideoMarqueeOption.Position. |
3330 | """ |
3331 | - Center = 0 |
3332 | - Left = 1 |
3333 | - CenterLeft = 1 |
3334 | - Right = 2 |
3335 | - CenterRight = 2 |
3336 | - Top = 4 |
3337 | - TopCenter = 4 |
3338 | - TopLeft = 5 |
3339 | - TopRight = 6 |
3340 | - Bottom = 8 |
3341 | + Center = 0 |
3342 | + Left = 1 |
3343 | + CenterLeft = 1 |
3344 | + Right = 2 |
3345 | + CenterRight = 2 |
3346 | + Top = 4 |
3347 | + TopCenter = 4 |
3348 | + TopLeft = 5 |
3349 | + TopRight = 6 |
3350 | + Bottom = 8 |
3351 | BottomCenter = 8 |
3352 | - BottomLeft = 9 |
3353 | - BottomRight = 10 |
3354 | + BottomLeft = 9 |
3355 | + BottomRight = 10 |
3356 | + |
3357 | def __init__(self, *unused): |
3358 | raise TypeError('constants only') |
3359 | - def __setattr__(self, *unused): #PYCHOK expected |
3360 | + |
3361 | + def __setattr__(self, *unused): # PYCHOK expected |
3362 | raise TypeError('immutable constants') |
3363 | |
3364 | + |
3365 | class Rectangle(_Cstruct): |
3366 | _fields_ = [ |
3367 | - ('top', ctypes.c_int), |
3368 | - ('left', ctypes.c_int), |
3369 | + ('top', ctypes.c_int), |
3370 | + ('left', ctypes.c_int), |
3371 | ('bottom', ctypes.c_int), |
3372 | - ('right', ctypes.c_int), |
3373 | + ('right', ctypes.c_int), |
3374 | ] |
3375 | |
3376 | + |
3377 | class TrackDescription(_Cstruct): |
3378 | |
3379 | def __str__(self): |
3380 | return '%s(%d:%s)' % (self.__class__.__name__, self.id, self.name) |
3381 | |
3382 | + |
3383 | TrackDescription._fields_ = [ # recursive struct |
3384 | - ('id', ctypes.c_int ), |
3385 | + ('id', ctypes.c_int), |
3386 | ('name', ctypes.c_char_p), |
3387 | ('next', ctypes.POINTER(TrackDescription)), |
3388 | - ] |
3389 | +] |
3390 | + |
3391 | |
3392 | def track_description_list(head): |
3393 | """Convert a TrackDescription linked list to a Python list (and release the former). |
3394 | @@ -1210,48 +1669,53 @@ |
3395 | |
3396 | return r |
3397 | |
3398 | + |
3399 | class EventUnion(ctypes.Union): |
3400 | _fields_ = [ |
3401 | - ('meta_type', ctypes.c_uint ), |
3402 | - ('new_child', ctypes.c_uint ), |
3403 | + ('meta_type', ctypes.c_uint), |
3404 | + ('new_child', ctypes.c_uint), |
3405 | ('new_duration', ctypes.c_longlong), |
3406 | - ('new_status', ctypes.c_int ), |
3407 | - ('media', ctypes.c_void_p ), |
3408 | - ('new_state', ctypes.c_uint ), |
3409 | + ('new_status', ctypes.c_int), |
3410 | + ('media', ctypes.c_void_p), |
3411 | + ('new_state', ctypes.c_uint), |
3412 | # FIXME: Media instance |
3413 | - ('new_cache', ctypes.c_float ), |
3414 | - ('new_position', ctypes.c_float ), |
3415 | - ('new_time', ctypes.c_longlong), |
3416 | - ('new_title', ctypes.c_int ), |
3417 | + ('new_cache', ctypes.c_float), |
3418 | + ('new_position', ctypes.c_float), |
3419 | + ('new_time', ctypes.c_longlong), |
3420 | + ('new_title', ctypes.c_int), |
3421 | ('new_seekable', ctypes.c_longlong), |
3422 | ('new_pausable', ctypes.c_longlong), |
3423 | ('new_scrambled', ctypes.c_longlong), |
3424 | ('new_count', ctypes.c_longlong), |
3425 | # FIXME: Skipped MediaList and MediaListView... |
3426 | - ('filename', ctypes.c_char_p ), |
3427 | - ('new_length', ctypes.c_longlong), |
3428 | - ('media_event', MediaEvent ), |
3429 | + ('filename', ctypes.c_char_p), |
3430 | + ('new_length', ctypes.c_longlong), |
3431 | + ('media_event', MediaEvent), |
3432 | ] |
3433 | |
3434 | + |
3435 | class Event(_Cstruct): |
3436 | _fields_ = [ |
3437 | - ('type', EventType ), |
3438 | + ('type', EventType), |
3439 | ('object', ctypes.c_void_p), |
3440 | - ('u', EventUnion ), |
3441 | + ('u', EventUnion), |
3442 | ] |
3443 | |
3444 | + |
3445 | class ModuleDescription(_Cstruct): |
3446 | |
3447 | def __str__(self): |
3448 | return '%s %s (%s)' % (self.__class__.__name__, self.shortname, self.name) |
3449 | |
3450 | + |
3451 | ModuleDescription._fields_ = [ # recursive struct |
3452 | - ('name', ctypes.c_char_p), |
3453 | + ('name', ctypes.c_char_p), |
3454 | ('shortname', ctypes.c_char_p), |
3455 | - ('longname', ctypes.c_char_p), |
3456 | - ('help', ctypes.c_char_p), |
3457 | - ('next', ctypes.POINTER(ModuleDescription)), |
3458 | - ] |
3459 | + ('longname', ctypes.c_char_p), |
3460 | + ('help', ctypes.c_char_p), |
3461 | + ('next', ctypes.POINTER(ModuleDescription)), |
3462 | +] |
3463 | + |
3464 | |
3465 | def module_description_list(head): |
3466 | """Convert a ModuleDescription linked list to a Python list (and release the former). |
3467 | @@ -1266,33 +1730,75 @@ |
3468 | libvlc_module_description_list_release(head) |
3469 | return r |
3470 | |
3471 | + |
3472 | class AudioOutputDevice(_Cstruct): |
3473 | |
3474 | def __str__(self): |
3475 | return '%s(%d:%s)' % (self.__class__.__name__, self.id, self.name) |
3476 | |
3477 | + |
3478 | AudioOutputDevice._fields_ = [ # recursive struct |
3479 | ('next', ctypes.POINTER(AudioOutputDevice)), |
3480 | - ('device', ctypes.c_char_p ), |
3481 | + ('device', ctypes.c_char_p), |
3482 | ('description', ctypes.c_char_p), |
3483 | - ] |
3484 | +] |
3485 | + |
3486 | |
3487 | class TitleDescription(_Cstruct): |
3488 | - _fields = [ |
3489 | + _fields_ = [ |
3490 | ('duration', ctypes.c_longlong), |
3491 | ('name', ctypes.c_char_p), |
3492 | ('menu', ctypes.c_bool), |
3493 | ] |
3494 | |
3495 | + |
3496 | class ChapterDescription(_Cstruct): |
3497 | - _fields = [ |
3498 | + _fields_ = [ |
3499 | ('time_offset', ctypes.c_longlong), |
3500 | ('duration', ctypes.c_longlong), |
3501 | ('name', ctypes.c_char_p), |
3502 | ] |
3503 | |
3504 | - # End of header.py # |
3505 | - |
3506 | + |
3507 | +class VideoViewpoint(_Cstruct): |
3508 | + _fields_ = [ |
3509 | + ('yaw', ctypes.c_float), |
3510 | + ('pitch', ctypes.c_float), |
3511 | + ('roll', ctypes.c_float), |
3512 | + ('field_of_view', ctypes.c_float), |
3513 | + ] |
3514 | + |
3515 | + |
3516 | +class MediaDiscovererDescription(_Cstruct): |
3517 | + _fields_ = [ |
3518 | + ('name', ctypes.c_char_p), |
3519 | + ('longname', ctypes.c_char_p), |
3520 | + ('cat', MediaDiscovererCategory), |
3521 | + ] |
3522 | + |
3523 | + def __str__(self): |
3524 | + return '%s %s (%d) - %s' % (self.__class__.__name__, self.name, self.cat, self.longname) |
3525 | + |
3526 | + |
3527 | +# This struct depends on the MediaSlaveType enum that is defined only |
3528 | +# in > 2.2 |
3529 | +if 'MediaSlaveType' in locals(): |
3530 | + class MediaSlave(_Cstruct): |
3531 | + _fields_ = [ |
3532 | + ('psz_uri', ctypes.c_char_p), |
3533 | + ('i_type', MediaSlaveType), |
3534 | + ('i_priority', ctypes.c_uint) |
3535 | + ] |
3536 | + |
3537 | + |
3538 | +class RDDescription(_Cstruct): |
3539 | + _fields_ = [ |
3540 | + ('name', ctypes.c_char_p), |
3541 | + ('longname', ctypes.c_char_p) |
3542 | + ] |
3543 | + |
3544 | + |
3545 | +# End of header.py # |
3546 | class EventManager(_Ctype): |
3547 | '''Create an event manager with callback handler. |
3548 | |
3549 | @@ -1308,7 +1814,7 @@ |
3550 | |
3551 | @note: Only a single notification can be registered |
3552 | for each event type in an EventManager instance. |
3553 | - |
3554 | + |
3555 | ''' |
3556 | |
3557 | _callback_handler = None |
3558 | @@ -1316,7 +1822,8 @@ |
3559 | |
3560 | def __new__(cls, ptr=_internal_guard): |
3561 | if ptr == _internal_guard: |
3562 | - raise VLCException("(INTERNAL) ctypes class.\nYou should get a reference to EventManager through the MediaPlayer.event_manager() method.") |
3563 | + raise VLCException( |
3564 | + "(INTERNAL) ctypes class.\nYou should get a reference to EventManager through the MediaPlayer.event_manager() method.") |
3565 | return _Constructor(cls, ptr) |
3566 | |
3567 | def event_attach(self, eventtype, callback, *args, **kwds): |
3568 | @@ -1336,12 +1843,13 @@ |
3569 | raise VLCException("%s required: %r" % ('EventType', eventtype)) |
3570 | if not hasattr(callback, '__call__'): # callable() |
3571 | raise VLCException("%s required: %r" % ('callable', callback)) |
3572 | - # check that the callback expects arguments |
3573 | + # check that the callback expects arguments |
3574 | if not any(getargspec(callback)[:2]): # list(...) |
3575 | raise VLCException("%s required: %r" % ('argument', callback)) |
3576 | |
3577 | if self._callback_handler is None: |
3578 | _called_from_ctypes = ctypes.CFUNCTYPE(None, ctypes.POINTER(Event), ctypes.c_void_p) |
3579 | + |
3580 | @_called_from_ctypes |
3581 | def _callback_handler(event, k): |
3582 | """(INTERNAL) handle callback call from ctypes. |
3583 | @@ -1350,12 +1858,13 @@ |
3584 | method since ctypes does not prepend self as the |
3585 | first parameter, hence this closure. |
3586 | """ |
3587 | - try: # retrieve Python callback and arguments |
3588 | + try: # retrieve Python callback and arguments |
3589 | call, args, kwds = self._callbacks[k] |
3590 | - # deref event.contents to simplify callback code |
3591 | + # deref event.contents to simplify callback code |
3592 | call(event.contents, *args, **kwds) |
3593 | except KeyError: # detached? |
3594 | pass |
3595 | + |
3596 | self._callback_handler = _callback_handler |
3597 | self._callbacks = {} |
3598 | |
3599 | @@ -1375,9 +1884,10 @@ |
3600 | |
3601 | k = eventtype.value |
3602 | if k in self._callbacks: |
3603 | - del self._callbacks[k] # remove, regardless of libvlc return value |
3604 | + del self._callbacks[k] # remove, regardless of libvlc return value |
3605 | libvlc_event_detach(self, k, self._callback_handler, k) |
3606 | |
3607 | + |
3608 | class Instance(_Ctype): |
3609 | '''Create a new Instance instance. |
3610 | |
3611 | @@ -1385,7 +1895,7 @@ |
3612 | - a string |
3613 | - a list of strings as first parameters |
3614 | - the parameters given as the constructor parameters (must be strings) |
3615 | - |
3616 | + |
3617 | ''' |
3618 | |
3619 | def __new__(cls, *args): |
3620 | @@ -1398,16 +1908,24 @@ |
3621 | elif isinstance(i, basestring): |
3622 | args = i.strip().split() |
3623 | elif isinstance(i, _Seqs): |
3624 | - args = i |
3625 | + args = list(i) |
3626 | else: |
3627 | raise VLCException('Instance %r' % (args,)) |
3628 | - |
3629 | - if not args and plugin_path is not None: |
3630 | - # no parameters passed, for win32 and MacOS, |
3631 | - # specify the plugin_path if detected earlier |
3632 | - args = ['vlc', '--plugin-path=' + plugin_path] |
3633 | + else: |
3634 | + args = list(args) |
3635 | + |
3636 | + if not args: # no parameters passed |
3637 | + args = ['vlc'] |
3638 | + elif args[0] != 'vlc': |
3639 | + args.insert(0, 'vlc') |
3640 | + |
3641 | + if plugin_path is not None: |
3642 | + # set plugin_path if detected, win32 and MacOS, |
3643 | + # if the user did not specify it itself. |
3644 | + os.environ.setdefault('VLC_PLUGIN_PATH', plugin_path) |
3645 | + |
3646 | if PYTHON3: |
3647 | - args = [ str_to_bytes(a) for a in args ] |
3648 | + args = [str_to_bytes(a) for a in args] |
3649 | return libvlc_new(len(args), args) |
3650 | |
3651 | def media_player_new(self, uri=None): |
3652 | @@ -1482,9 +2000,9 @@ |
3653 | i = head |
3654 | while i: |
3655 | i = i.contents |
3656 | - d = [{'id': libvlc_audio_output_device_id (self, i.name, d), |
3657 | + d = [{'id': libvlc_audio_output_device_id(self, i.name, d), |
3658 | 'longname': libvlc_audio_output_device_longname(self, i.name, d)} |
3659 | - for d in range(libvlc_audio_output_device_count (self, i.name))] |
3660 | + for d in range(libvlc_audio_output_device_count(self, i.name))] |
3661 | r.append({'name': i.name, 'description': i.description, 'devices': d}) |
3662 | i = i.next |
3663 | libvlc_audio_output_list_release(head) |
3664 | @@ -1502,22 +2020,18 @@ |
3665 | """ |
3666 | return module_description_list(libvlc_video_filter_list_get(self)) |
3667 | |
3668 | - |
3669 | - |
3670 | def release(self): |
3671 | '''Decrement the reference count of a libvlc instance, and destroy it |
3672 | if it reaches zero. |
3673 | ''' |
3674 | return libvlc_release(self) |
3675 | |
3676 | - |
3677 | def retain(self): |
3678 | '''Increments the reference count of a libvlc instance. |
3679 | The initial reference count is 1 after L{new}() returns. |
3680 | ''' |
3681 | return libvlc_retain(self) |
3682 | |
3683 | - |
3684 | def add_intf(self, name): |
3685 | '''Try to start a user interface for the libvlc instance. |
3686 | @param name: interface name, or None for default. |
3687 | @@ -1525,7 +2039,6 @@ |
3688 | ''' |
3689 | return libvlc_add_intf(self, str_to_bytes(name)) |
3690 | |
3691 | - |
3692 | def set_user_agent(self, name, http): |
3693 | '''Sets the application name. LibVLC passes this as the user agent string |
3694 | when a protocol requires it. |
3695 | @@ -1535,7 +2048,6 @@ |
3696 | ''' |
3697 | return libvlc_set_user_agent(self, str_to_bytes(name), str_to_bytes(http)) |
3698 | |
3699 | - |
3700 | def set_app_id(self, id, version, icon): |
3701 | '''Sets some meta-information about the application. |
3702 | See also L{set_user_agent}(). |
3703 | @@ -1546,18 +2058,18 @@ |
3704 | ''' |
3705 | return libvlc_set_app_id(self, str_to_bytes(id), str_to_bytes(version), str_to_bytes(icon)) |
3706 | |
3707 | - |
3708 | def log_unset(self): |
3709 | - '''Unsets the logging callback for a LibVLC instance. This is rarely needed: |
3710 | - the callback is implicitly unset when the instance is destroyed. |
3711 | - This function will wait for any pending callbacks invocation to complete |
3712 | - (causing a deadlock if called from within the callback). |
3713 | + '''Unsets the logging callback. |
3714 | + This function deregisters the logging callback for a LibVLC instance. |
3715 | + This is rarely needed as the callback is implicitly unset when the instance |
3716 | + is destroyed. |
3717 | + @note: This function will wait for any pending callbacks invocation to |
3718 | + complete (causing a deadlock if called from within the callback). |
3719 | @version: LibVLC 2.1.0 or later. |
3720 | ''' |
3721 | return libvlc_log_unset(self) |
3722 | |
3723 | - |
3724 | - def log_set(self, data, p_instance): |
3725 | + def log_set(self, cb, data): |
3726 | '''Sets the logging callback for a LibVLC instance. |
3727 | This function is thread-safe: it will wait for any pending callbacks |
3728 | invocation to complete. |
3729 | @@ -1565,9 +2077,8 @@ |
3730 | @param p_instance: libvlc instance. |
3731 | @version: LibVLC 2.1.0 or later. |
3732 | ''' |
3733 | - return libvlc_log_set(self, data, p_instance) |
3734 | + return libvlc_log_set(self, cb, data) |
3735 | |
3736 | - |
3737 | def log_set_file(self, stream): |
3738 | '''Sets up logging to a file. |
3739 | @param stream: FILE pointer opened for writing (the FILE pointer must remain valid until L{log_unset}()). |
3740 | @@ -1575,105 +2086,41 @@ |
3741 | ''' |
3742 | return libvlc_log_set_file(self, stream) |
3743 | |
3744 | - |
3745 | - def media_new_location(self, psz_mrl): |
3746 | - '''Create a media with a certain given media resource location, |
3747 | - for instance a valid URL. |
3748 | - @note: To refer to a local file with this function, |
3749 | - the file://... URI syntax B{must} be used (see IETF RFC3986). |
3750 | - We recommend using L{media_new_path}() instead when dealing with |
3751 | - local files. |
3752 | - See L{media_release}. |
3753 | - @param psz_mrl: the media location. |
3754 | - @return: the newly created media or None on error. |
3755 | - ''' |
3756 | - return libvlc_media_new_location(self, str_to_bytes(psz_mrl)) |
3757 | - |
3758 | - |
3759 | - def media_new_path(self, path): |
3760 | - '''Create a media for a certain file path. |
3761 | - See L{media_release}. |
3762 | - @param path: local filesystem path. |
3763 | - @return: the newly created media or None on error. |
3764 | - ''' |
3765 | - return libvlc_media_new_path(self, str_to_bytes(path)) |
3766 | - |
3767 | - |
3768 | - def media_new_fd(self, fd): |
3769 | - '''Create a media for an already open file descriptor. |
3770 | - The file descriptor shall be open for reading (or reading and writing). |
3771 | - Regular file descriptors, pipe read descriptors and character device |
3772 | - descriptors (including TTYs) are supported on all platforms. |
3773 | - Block device descriptors are supported where available. |
3774 | - Directory descriptors are supported on systems that provide fdopendir(). |
3775 | - Sockets are supported on all platforms where they are file descriptors, |
3776 | - i.e. all except Windows. |
3777 | - @note: This library will B{not} automatically close the file descriptor |
3778 | - under any circumstance. Nevertheless, a file descriptor can usually only be |
3779 | - rendered once in a media player. To render it a second time, the file |
3780 | - descriptor should probably be rewound to the beginning with lseek(). |
3781 | - See L{media_release}. |
3782 | - @param fd: open file descriptor. |
3783 | - @return: the newly created media or None on error. |
3784 | - @version: LibVLC 1.1.5 and later. |
3785 | - ''' |
3786 | - return libvlc_media_new_fd(self, fd) |
3787 | - |
3788 | - |
3789 | - def media_new_as_node(self, psz_name): |
3790 | - '''Create a media as an empty node with a given name. |
3791 | - See L{media_release}. |
3792 | - @param psz_name: the name of the node. |
3793 | - @return: the new empty media or None on error. |
3794 | - ''' |
3795 | - return libvlc_media_new_as_node(self, str_to_bytes(psz_name)) |
3796 | - |
3797 | - |
3798 | - def media_discoverer_new_from_name(self, psz_name): |
3799 | - '''Discover media service by name. |
3800 | - @param psz_name: service name. |
3801 | + def media_discoverer_new(self, psz_name): |
3802 | + '''Create a media discoverer object by name. |
3803 | + After this object is created, you should attach to media_list events in |
3804 | + order to be notified of new items discovered. |
3805 | + You need to call L{media_discoverer_start}() in order to start the |
3806 | + discovery. |
3807 | + See L{media_discoverer_media_list} |
3808 | + See L{media_discoverer_event_manager} |
3809 | + See L{media_discoverer_start}. |
3810 | + @param psz_name: service name; use L{media_discoverer_list_get}() to get a list of the discoverer names available in this libVLC instance. |
3811 | @return: media discover object or None in case of error. |
3812 | - ''' |
3813 | - return libvlc_media_discoverer_new_from_name(self, str_to_bytes(psz_name)) |
3814 | - |
3815 | - |
3816 | + @version: LibVLC 3.0.0 or later. |
3817 | + ''' |
3818 | + return libvlc_media_discoverer_new(self, str_to_bytes(psz_name)) |
3819 | + |
3820 | + def media_discoverer_list_get(self, i_cat, ppp_services): |
3821 | + '''Get media discoverer services by category. |
3822 | + @param i_cat: category of services to fetch. |
3823 | + @param ppp_services: address to store an allocated array of media discoverer services (must be freed with L{media_discoverer_list_release}() by the caller) [OUT]. |
3824 | + @return: the number of media discoverer services (0 on error). |
3825 | + @version: LibVLC 3.0.0 and later. |
3826 | + ''' |
3827 | + return libvlc_media_discoverer_list_get(self, i_cat, ppp_services) |
3828 | + |
3829 | def media_library_new(self): |
3830 | '''Create an new Media Library object. |
3831 | @return: a new object or None on error. |
3832 | ''' |
3833 | return libvlc_media_library_new(self) |
3834 | |
3835 | - |
3836 | - def audio_output_list_get(self): |
3837 | - '''Gets the list of available audio output modules. |
3838 | - @return: list of available audio outputs. It must be freed it with In case of error, None is returned. |
3839 | - ''' |
3840 | - return libvlc_audio_output_list_get(self) |
3841 | - |
3842 | - |
3843 | - def audio_output_device_list_get(self, aout): |
3844 | - '''Gets a list of audio output devices for a given audio output module, |
3845 | - See L{audio_output_device_set}(). |
3846 | - @note: Not all audio outputs support this. In particular, an empty (None) |
3847 | - list of devices does B{not} imply that the specified audio output does |
3848 | - not work. |
3849 | - @note: The list might not be exhaustive. |
3850 | - @warning: Some audio output devices in the list might not actually work in |
3851 | - some circumstances. By default, it is recommended to not specify any |
3852 | - explicit audio device. |
3853 | - @param psz_aout: audio output name (as returned by L{audio_output_list_get}()). |
3854 | - @return: A None-terminated linked list of potential audio output devices. It must be freed it with L{audio_output_device_list_release}(). |
3855 | - @version: LibVLC 2.1.0 or later. |
3856 | - ''' |
3857 | - return libvlc_audio_output_device_list_get(self, str_to_bytes(aout)) |
3858 | - |
3859 | - |
3860 | def vlm_release(self): |
3861 | '''Release the vlm instance related to the given L{Instance}. |
3862 | ''' |
3863 | return libvlc_vlm_release(self) |
3864 | |
3865 | - |
3866 | def vlm_add_broadcast(self, psz_name, psz_input, psz_output, i_options, ppsz_options, b_enabled, b_loop): |
3867 | '''Add a broadcast, with one input. |
3868 | @param psz_name: the name of the new broadcast. |
3869 | @@ -1685,9 +2132,9 @@ |
3870 | @param b_loop: Should this broadcast be played in loop ? |
3871 | @return: 0 on success, -1 on error. |
3872 | ''' |
3873 | - return libvlc_vlm_add_broadcast(self, str_to_bytes(psz_name), str_to_bytes(psz_input), str_to_bytes(psz_output), i_options, ppsz_options, b_enabled, b_loop) |
3874 | + return libvlc_vlm_add_broadcast(self, str_to_bytes(psz_name), str_to_bytes(psz_input), str_to_bytes(psz_output), |
3875 | + i_options, ppsz_options, b_enabled, b_loop) |
3876 | |
3877 | - |
3878 | def vlm_add_vod(self, psz_name, psz_input, i_options, ppsz_options, b_enabled, psz_mux): |
3879 | '''Add a vod, with one input. |
3880 | @param psz_name: the name of the new vod media. |
3881 | @@ -1698,9 +2145,9 @@ |
3882 | @param psz_mux: the muxer of the vod media. |
3883 | @return: 0 on success, -1 on error. |
3884 | ''' |
3885 | - return libvlc_vlm_add_vod(self, str_to_bytes(psz_name), str_to_bytes(psz_input), i_options, ppsz_options, b_enabled, str_to_bytes(psz_mux)) |
3886 | + return libvlc_vlm_add_vod(self, str_to_bytes(psz_name), str_to_bytes(psz_input), i_options, ppsz_options, |
3887 | + b_enabled, str_to_bytes(psz_mux)) |
3888 | |
3889 | - |
3890 | def vlm_del_media(self, psz_name): |
3891 | '''Delete a media (VOD or broadcast). |
3892 | @param psz_name: the media to delete. |
3893 | @@ -1708,7 +2155,6 @@ |
3894 | ''' |
3895 | return libvlc_vlm_del_media(self, str_to_bytes(psz_name)) |
3896 | |
3897 | - |
3898 | def vlm_set_enabled(self, psz_name, b_enabled): |
3899 | '''Enable or disable a media (VOD or broadcast). |
3900 | @param psz_name: the media to work on. |
3901 | @@ -1717,7 +2163,6 @@ |
3902 | ''' |
3903 | return libvlc_vlm_set_enabled(self, str_to_bytes(psz_name), b_enabled) |
3904 | |
3905 | - |
3906 | def vlm_set_output(self, psz_name, psz_output): |
3907 | '''Set the output for a media. |
3908 | @param psz_name: the media to work on. |
3909 | @@ -1726,7 +2171,6 @@ |
3910 | ''' |
3911 | return libvlc_vlm_set_output(self, str_to_bytes(psz_name), str_to_bytes(psz_output)) |
3912 | |
3913 | - |
3914 | def vlm_set_input(self, psz_name, psz_input): |
3915 | '''Set a media's input MRL. This will delete all existing inputs and |
3916 | add the specified one. |
3917 | @@ -1736,7 +2180,6 @@ |
3918 | ''' |
3919 | return libvlc_vlm_set_input(self, str_to_bytes(psz_name), str_to_bytes(psz_input)) |
3920 | |
3921 | - |
3922 | def vlm_add_input(self, psz_name, psz_input): |
3923 | '''Add a media's input MRL. This will add the specified one. |
3924 | @param psz_name: the media to work on. |
3925 | @@ -1745,7 +2188,6 @@ |
3926 | ''' |
3927 | return libvlc_vlm_add_input(self, str_to_bytes(psz_name), str_to_bytes(psz_input)) |
3928 | |
3929 | - |
3930 | def vlm_set_loop(self, psz_name, b_loop): |
3931 | '''Set a media's loop status. |
3932 | @param psz_name: the media to work on. |
3933 | @@ -1754,7 +2196,6 @@ |
3934 | ''' |
3935 | return libvlc_vlm_set_loop(self, str_to_bytes(psz_name), b_loop) |
3936 | |
3937 | - |
3938 | def vlm_set_mux(self, psz_name, psz_mux): |
3939 | '''Set a media's vod muxer. |
3940 | @param psz_name: the media to work on. |
3941 | @@ -1763,7 +2204,6 @@ |
3942 | ''' |
3943 | return libvlc_vlm_set_mux(self, str_to_bytes(psz_name), str_to_bytes(psz_mux)) |
3944 | |
3945 | - |
3946 | def vlm_change_media(self, psz_name, psz_input, psz_output, i_options, ppsz_options, b_enabled, b_loop): |
3947 | '''Edit the parameters of a media. This will delete all existing inputs and |
3948 | add the specified one. |
3949 | @@ -1776,9 +2216,9 @@ |
3950 | @param b_loop: Should this broadcast be played in loop ? |
3951 | @return: 0 on success, -1 on error. |
3952 | ''' |
3953 | - return libvlc_vlm_change_media(self, str_to_bytes(psz_name), str_to_bytes(psz_input), str_to_bytes(psz_output), i_options, ppsz_options, b_enabled, b_loop) |
3954 | + return libvlc_vlm_change_media(self, str_to_bytes(psz_name), str_to_bytes(psz_input), str_to_bytes(psz_output), |
3955 | + i_options, ppsz_options, b_enabled, b_loop) |
3956 | |
3957 | - |
3958 | def vlm_play_media(self, psz_name): |
3959 | '''Play the named broadcast. |
3960 | @param psz_name: the name of the broadcast. |
3961 | @@ -1786,7 +2226,6 @@ |
3962 | ''' |
3963 | return libvlc_vlm_play_media(self, str_to_bytes(psz_name)) |
3964 | |
3965 | - |
3966 | def vlm_stop_media(self, psz_name): |
3967 | '''Stop the named broadcast. |
3968 | @param psz_name: the name of the broadcast. |
3969 | @@ -1794,7 +2233,6 @@ |
3970 | ''' |
3971 | return libvlc_vlm_stop_media(self, str_to_bytes(psz_name)) |
3972 | |
3973 | - |
3974 | def vlm_pause_media(self, psz_name): |
3975 | '''Pause the named broadcast. |
3976 | @param psz_name: the name of the broadcast. |
3977 | @@ -1802,7 +2240,6 @@ |
3978 | ''' |
3979 | return libvlc_vlm_pause_media(self, str_to_bytes(psz_name)) |
3980 | |
3981 | - |
3982 | def vlm_seek_media(self, psz_name, f_percentage): |
3983 | '''Seek in the named broadcast. |
3984 | @param psz_name: the name of the broadcast. |
3985 | @@ -1811,7 +2248,6 @@ |
3986 | ''' |
3987 | return libvlc_vlm_seek_media(self, str_to_bytes(psz_name), f_percentage) |
3988 | |
3989 | - |
3990 | def vlm_show_media(self, psz_name): |
3991 | '''Return information about the named media as a JSON |
3992 | string representation. |
3993 | @@ -1826,7 +2262,6 @@ |
3994 | ''' |
3995 | return libvlc_vlm_show_media(self, str_to_bytes(psz_name)) |
3996 | |
3997 | - |
3998 | def vlm_get_media_instance_position(self, psz_name, i_instance): |
3999 | '''Get vlm_media instance position by name or instance id. |
4000 | @param psz_name: name of vlm media instance. |
4001 | @@ -1835,7 +2270,6 @@ |
4002 | ''' |
4003 | return libvlc_vlm_get_media_instance_position(self, str_to_bytes(psz_name), i_instance) |
4004 | |
4005 | - |
4006 | def vlm_get_media_instance_time(self, psz_name, i_instance): |
4007 | '''Get vlm_media instance time by name or instance id. |
4008 | @param psz_name: name of vlm media instance. |
4009 | @@ -1844,7 +2278,6 @@ |
4010 | ''' |
4011 | return libvlc_vlm_get_media_instance_time(self, str_to_bytes(psz_name), i_instance) |
4012 | |
4013 | - |
4014 | def vlm_get_media_instance_length(self, psz_name, i_instance): |
4015 | '''Get vlm_media instance length by name or instance id. |
4016 | @param psz_name: name of vlm media instance. |
4017 | @@ -1853,7 +2286,6 @@ |
4018 | ''' |
4019 | return libvlc_vlm_get_media_instance_length(self, str_to_bytes(psz_name), i_instance) |
4020 | |
4021 | - |
4022 | def vlm_get_media_instance_rate(self, psz_name, i_instance): |
4023 | '''Get vlm_media instance playback rate by name or instance id. |
4024 | @param psz_name: name of vlm media instance. |
4025 | @@ -1862,7 +2294,6 @@ |
4026 | ''' |
4027 | return libvlc_vlm_get_media_instance_rate(self, str_to_bytes(psz_name), i_instance) |
4028 | |
4029 | - |
4030 | def vlm_get_media_instance_title(self, psz_name, i_instance): |
4031 | '''Get vlm_media instance title number by name or instance id. |
4032 | @param psz_name: name of vlm media instance. |
4033 | @@ -1872,7 +2303,6 @@ |
4034 | ''' |
4035 | return libvlc_vlm_get_media_instance_title(self, str_to_bytes(psz_name), i_instance) |
4036 | |
4037 | - |
4038 | def vlm_get_media_instance_chapter(self, psz_name, i_instance): |
4039 | '''Get vlm_media instance chapter number by name or instance id. |
4040 | @param psz_name: name of vlm media instance. |
4041 | @@ -1882,7 +2312,6 @@ |
4042 | ''' |
4043 | return libvlc_vlm_get_media_instance_chapter(self, str_to_bytes(psz_name), i_instance) |
4044 | |
4045 | - |
4046 | def vlm_get_media_instance_seekable(self, psz_name, i_instance): |
4047 | '''Is libvlc instance seekable ? |
4048 | @param psz_name: name of vlm media instance. |
4049 | @@ -1900,13 +2329,219 @@ |
4050 | ''' |
4051 | return libvlc_vlm_get_event_manager(self) |
4052 | |
4053 | + def media_new_location(self, psz_mrl): |
4054 | + '''Create a media with a certain given media resource location, |
4055 | + for instance a valid URL. |
4056 | + @note: To refer to a local file with this function, |
4057 | + the file://... URI syntax B{must} be used (see IETF RFC3986). |
4058 | + We recommend using L{media_new_path}() instead when dealing with |
4059 | + local files. |
4060 | + See L{media_release}. |
4061 | + @param psz_mrl: the media location. |
4062 | + @return: the newly created media or None on error. |
4063 | + ''' |
4064 | + return libvlc_media_new_location(self, str_to_bytes(psz_mrl)) |
4065 | + |
4066 | + def media_new_path(self, path): |
4067 | + '''Create a media for a certain file path. |
4068 | + See L{media_release}. |
4069 | + @param path: local filesystem path. |
4070 | + @return: the newly created media or None on error. |
4071 | + ''' |
4072 | + return libvlc_media_new_path(self, str_to_bytes(path)) |
4073 | + |
4074 | + def media_new_fd(self, fd): |
4075 | + '''Create a media for an already open file descriptor. |
4076 | + The file descriptor shall be open for reading (or reading and writing). |
4077 | + Regular file descriptors, pipe read descriptors and character device |
4078 | + descriptors (including TTYs) are supported on all platforms. |
4079 | + Block device descriptors are supported where available. |
4080 | + Directory descriptors are supported on systems that provide fdopendir(). |
4081 | + Sockets are supported on all platforms where they are file descriptors, |
4082 | + i.e. all except Windows. |
4083 | + @note: This library will B{not} automatically close the file descriptor |
4084 | + under any circumstance. Nevertheless, a file descriptor can usually only be |
4085 | + rendered once in a media player. To render it a second time, the file |
4086 | + descriptor should probably be rewound to the beginning with lseek(). |
4087 | + See L{media_release}. |
4088 | + @param fd: open file descriptor. |
4089 | + @return: the newly created media or None on error. |
4090 | + @version: LibVLC 1.1.5 and later. |
4091 | + ''' |
4092 | + return libvlc_media_new_fd(self, fd) |
4093 | + |
4094 | + def media_new_callbacks(self, open_cb, read_cb, seek_cb, close_cb, opaque): |
4095 | + '''Create a media with custom callbacks to read the data from. |
4096 | + @param open_cb: callback to open the custom bitstream input media. |
4097 | + @param read_cb: callback to read data (must not be None). |
4098 | + @param seek_cb: callback to seek, or None if seeking is not supported. |
4099 | + @param close_cb: callback to close the media, or None if unnecessary. |
4100 | + @param opaque: data pointer for the open callback. |
4101 | + @return: the newly created media or None on error @note If open_cb is None, the opaque pointer will be passed to read_cb, seek_cb and close_cb, and the stream size will be treated as unknown. @note The callbacks may be called asynchronously (from another thread). A single stream instance need not be reentrant. However the open_cb needs to be reentrant if the media is used by multiple player instances. @warning The callbacks may be used until all or any player instances that were supplied the media item are stopped. See L{media_release}. |
4102 | + @version: LibVLC 3.0.0 and later. |
4103 | + ''' |
4104 | + return libvlc_media_new_callbacks(self, open_cb, read_cb, seek_cb, close_cb, opaque) |
4105 | + |
4106 | + def media_new_as_node(self, psz_name): |
4107 | + '''Create a media as an empty node with a given name. |
4108 | + See L{media_release}. |
4109 | + @param psz_name: the name of the node. |
4110 | + @return: the new empty media or None on error. |
4111 | + ''' |
4112 | + return libvlc_media_new_as_node(self, str_to_bytes(psz_name)) |
4113 | + |
4114 | + def renderer_discoverer_new(self, psz_name): |
4115 | + '''Create a renderer discoverer object by name |
4116 | + After this object is created, you should attach to events in order to be |
4117 | + notified of the discoverer events. |
4118 | + You need to call L{renderer_discoverer_start}() in order to start the |
4119 | + discovery. |
4120 | + See L{renderer_discoverer_event_manager}() |
4121 | + See L{renderer_discoverer_start}(). |
4122 | + @param psz_name: service name; use L{renderer_discoverer_list_get}() to get a list of the discoverer names available in this libVLC instance. |
4123 | + @return: media discover object or None in case of error. |
4124 | + @version: LibVLC 3.0.0 or later. |
4125 | + ''' |
4126 | + return libvlc_renderer_discoverer_new(self, str_to_bytes(psz_name)) |
4127 | + |
4128 | + def renderer_discoverer_list_get(self, ppp_services): |
4129 | + '''Get media discoverer services |
4130 | + See libvlc_renderer_list_release(). |
4131 | + @param ppp_services: address to store an allocated array of renderer discoverer services (must be freed with libvlc_renderer_list_release() by the caller) [OUT]. |
4132 | + @return: the number of media discoverer services (0 on error). |
4133 | + @version: LibVLC 3.0.0 and later. |
4134 | + ''' |
4135 | + return libvlc_renderer_discoverer_list_get(self, ppp_services) |
4136 | + |
4137 | + def audio_output_device_count(self, psz_audio_output): |
4138 | + '''Backward compatibility stub. Do not use in new code. |
4139 | + \deprecated Use L{audio_output_device_list_get}() instead. |
4140 | + @return: always 0. |
4141 | + ''' |
4142 | + return libvlc_audio_output_device_count(self, str_to_bytes(psz_audio_output)) |
4143 | + |
4144 | + def audio_output_device_longname(self, psz_output, i_device): |
4145 | + '''Backward compatibility stub. Do not use in new code. |
4146 | + \deprecated Use L{audio_output_device_list_get}() instead. |
4147 | + @return: always None. |
4148 | + ''' |
4149 | + return libvlc_audio_output_device_longname(self, str_to_bytes(psz_output), i_device) |
4150 | + |
4151 | + def audio_output_device_id(self, psz_audio_output, i_device): |
4152 | + '''Backward compatibility stub. Do not use in new code. |
4153 | + \deprecated Use L{audio_output_device_list_get}() instead. |
4154 | + @return: always None. |
4155 | + ''' |
4156 | + return libvlc_audio_output_device_id(self, str_to_bytes(psz_audio_output), i_device) |
4157 | + |
4158 | + def media_discoverer_new_from_name(self, psz_name): |
4159 | + '''\deprecated Use L{media_discoverer_new}() and L{media_discoverer_start}(). |
4160 | + ''' |
4161 | + return libvlc_media_discoverer_new_from_name(self, str_to_bytes(psz_name)) |
4162 | + |
4163 | + def wait(self): |
4164 | + '''Waits until an interface causes the instance to exit. |
4165 | + You should start at least one interface first, using L{add_intf}(). |
4166 | + ''' |
4167 | + return libvlc_wait(self) |
4168 | + |
4169 | + def get_log_verbosity(self): |
4170 | + '''Always returns minus one. |
4171 | + This function is only provided for backward compatibility. |
4172 | + @return: always -1. |
4173 | + ''' |
4174 | + return libvlc_get_log_verbosity(self) |
4175 | + |
4176 | + def set_log_verbosity(self, level): |
4177 | + '''This function does nothing. |
4178 | + It is only provided for backward compatibility. |
4179 | + @param level: ignored. |
4180 | + ''' |
4181 | + return libvlc_set_log_verbosity(self, level) |
4182 | + |
4183 | + def log_open(self): |
4184 | + '''This function does nothing useful. |
4185 | + It is only provided for backward compatibility. |
4186 | + @return: an unique pointer or None on error. |
4187 | + ''' |
4188 | + return libvlc_log_open(self) |
4189 | + |
4190 | + def playlist_play(self, i_id, i_options, ppsz_options): |
4191 | + '''Start playing (if there is any item in the playlist). |
4192 | + Additionnal playlist item options can be specified for addition to the |
4193 | + item before it is played. |
4194 | + @param i_id: the item to play. If this is a negative number, the next item will be selected. Otherwise, the item with the given ID will be played. |
4195 | + @param i_options: the number of options to add to the item. |
4196 | + @param ppsz_options: the options to add to the item. |
4197 | + ''' |
4198 | + return libvlc_playlist_play(self, i_id, i_options, ppsz_options) |
4199 | + |
4200 | + def audio_output_list_get(self): |
4201 | + '''Gets the list of available audio output modules. |
4202 | + @return: list of available audio outputs. It must be freed with In case of error, None is returned. |
4203 | + ''' |
4204 | + return libvlc_audio_output_list_get(self) |
4205 | + |
4206 | + def audio_output_device_list_get(self, aout): |
4207 | + '''Gets a list of audio output devices for a given audio output module, |
4208 | + See L{audio_output_device_set}(). |
4209 | + @note: Not all audio outputs support this. In particular, an empty (None) |
4210 | + list of devices does B{not} imply that the specified audio output does |
4211 | + not work. |
4212 | + @note: The list might not be exhaustive. |
4213 | + @warning: Some audio output devices in the list might not actually work in |
4214 | + some circumstances. By default, it is recommended to not specify any |
4215 | + explicit audio device. |
4216 | + @param aout: audio output name (as returned by L{audio_output_list_get}()). |
4217 | + @return: A None-terminated linked list of potential audio output devices. It must be freed with L{audio_output_device_list_release}(). |
4218 | + @version: LibVLC 2.1.0 or later. |
4219 | + ''' |
4220 | + return libvlc_audio_output_device_list_get(self, str_to_bytes(aout)) |
4221 | + |
4222 | + |
4223 | +class LogIterator(_Ctype): |
4224 | + '''Create a new VLC log iterator. |
4225 | + |
4226 | + ''' |
4227 | + |
4228 | + def __new__(cls, ptr=_internal_guard): |
4229 | + '''(INTERNAL) ctypes wrapper constructor. |
4230 | + ''' |
4231 | + return _Constructor(cls, ptr) |
4232 | + |
4233 | + def __iter__(self): |
4234 | + return self |
4235 | + |
4236 | + def next(self): |
4237 | + if self.has_next(): |
4238 | + b = LogMessage() |
4239 | + i = libvlc_log_iterator_next(self, b) |
4240 | + return i.contents |
4241 | + raise StopIteration |
4242 | + |
4243 | + def __next__(self): |
4244 | + return self.next() |
4245 | + |
4246 | + def free(self): |
4247 | + '''Frees memory allocated by L{log_get_iterator}(). |
4248 | + ''' |
4249 | + return libvlc_log_iterator_free(self) |
4250 | + |
4251 | + def has_next(self): |
4252 | + '''Always returns zero. |
4253 | + This function is only provided for backward compatibility. |
4254 | + @return: always zero. |
4255 | + ''' |
4256 | + return libvlc_log_iterator_has_next(self) |
4257 | + |
4258 | + |
4259 | class Media(_Ctype): |
4260 | '''Create a new Media instance. |
4261 | - |
4262 | + |
4263 | Usage: Media(MRL, *options) |
4264 | |
4265 | See vlc.Instance.media_new documentation for details. |
4266 | - |
4267 | + |
4268 | ''' |
4269 | |
4270 | def __new__(cls, *args): |
4271 | @@ -1946,11 +2581,16 @@ |
4272 | """ |
4273 | mediaTrack_pp = ctypes.POINTER(MediaTrack)() |
4274 | n = libvlc_media_tracks_get(self, ctypes.byref(mediaTrack_pp)) |
4275 | - info = ctypes.cast(ctypes.mediaTrack_pp, ctypes.POINTER(ctypes.POINTER(MediaTrack) * n)) |
4276 | - return info |
4277 | - |
4278 | - |
4279 | - |
4280 | + info = ctypes.cast(mediaTrack_pp, ctypes.POINTER(ctypes.POINTER(MediaTrack) * n)) |
4281 | + try: |
4282 | + contents = info.contents |
4283 | + except ValueError: |
4284 | + # Media not parsed, no info. |
4285 | + return None |
4286 | + tracks = (contents[i].contents for i in range(len(contents))) |
4287 | + # libvlc_media_tracks_release(mediaTrack_pp, n) |
4288 | + return tracks |
4289 | + |
4290 | def add_option(self, psz_options): |
4291 | '''Add an option to the media. |
4292 | This option will be used to determine how the media_player will |
4293 | @@ -1967,7 +2607,6 @@ |
4294 | ''' |
4295 | return libvlc_media_add_option(self, str_to_bytes(psz_options)) |
4296 | |
4297 | - |
4298 | def add_option_flag(self, psz_options, i_flags): |
4299 | '''Add an option to the media with configurable flags. |
4300 | This option will be used to determine how the media_player will |
4301 | @@ -1983,15 +2622,13 @@ |
4302 | ''' |
4303 | return libvlc_media_add_option_flag(self, str_to_bytes(psz_options), i_flags) |
4304 | |
4305 | - |
4306 | def retain(self): |
4307 | - '''Retain a reference to a media descriptor object (libvlc_media_t). Use |
4308 | + '''Retain a reference to a media descriptor object (L{Media}). Use |
4309 | L{release}() to decrement the reference count of a |
4310 | media descriptor object. |
4311 | ''' |
4312 | return libvlc_media_retain(self) |
4313 | |
4314 | - |
4315 | def release(self): |
4316 | '''Decrement the reference count of a media descriptor object. If the |
4317 | reference count is 0, then L{release}() will release the |
4318 | @@ -2001,35 +2638,28 @@ |
4319 | ''' |
4320 | return libvlc_media_release(self) |
4321 | |
4322 | - |
4323 | def get_mrl(self): |
4324 | '''Get the media resource locator (mrl) from a media descriptor object. |
4325 | @return: string with mrl of media descriptor object. |
4326 | ''' |
4327 | return libvlc_media_get_mrl(self) |
4328 | |
4329 | - |
4330 | def duplicate(self): |
4331 | '''Duplicate a media descriptor object. |
4332 | ''' |
4333 | return libvlc_media_duplicate(self) |
4334 | |
4335 | - |
4336 | def get_meta(self, e_meta): |
4337 | '''Read the meta of the media. |
4338 | If the media has not yet been parsed this will return None. |
4339 | - This methods automatically calls L{parse_async}(), so after calling |
4340 | - it you may receive a libvlc_MediaMetaChanged event. If you prefer a synchronous |
4341 | - version ensure that you call L{parse}() before get_meta(). |
4342 | See L{parse} |
4343 | - See L{parse_async} |
4344 | + See L{parse_with_options} |
4345 | See libvlc_MediaMetaChanged. |
4346 | @param e_meta: the meta to read. |
4347 | @return: the media's meta. |
4348 | ''' |
4349 | return libvlc_media_get_meta(self, e_meta) |
4350 | |
4351 | - |
4352 | def set_meta(self, e_meta, psz_value): |
4353 | '''Set the meta of the media (this function will not save the meta, call |
4354 | L{save_meta} in order to save the meta). |
4355 | @@ -2038,26 +2668,21 @@ |
4356 | ''' |
4357 | return libvlc_media_set_meta(self, e_meta, str_to_bytes(psz_value)) |
4358 | |
4359 | - |
4360 | def save_meta(self): |
4361 | '''Save the meta previously set. |
4362 | @return: true if the write operation was successful. |
4363 | ''' |
4364 | return libvlc_media_save_meta(self) |
4365 | |
4366 | - |
4367 | def get_state(self): |
4368 | - '''Get current state of media descriptor object. Possible media states |
4369 | - are defined in libvlc_structures.c ( libvlc_NothingSpecial=0, |
4370 | - libvlc_Opening, libvlc_Buffering, libvlc_Playing, libvlc_Paused, |
4371 | - libvlc_Stopped, libvlc_Ended, |
4372 | - libvlc_Error). |
4373 | - See libvlc_state_t. |
4374 | + '''Get current state of media descriptor object. Possible media states are |
4375 | + libvlc_NothingSpecial=0, libvlc_Opening, libvlc_Playing, libvlc_Paused, |
4376 | + libvlc_Stopped, libvlc_Ended, libvlc_Error. |
4377 | + See L{State}. |
4378 | @return: state of media descriptor object. |
4379 | ''' |
4380 | return libvlc_media_get_state(self) |
4381 | |
4382 | - |
4383 | def get_stats(self, p_stats): |
4384 | '''Get the current statistics about the media. |
4385 | @param p_stats:: structure that contain the statistics about the media (this structure must be allocated by the caller). |
4386 | @@ -2065,7 +2690,6 @@ |
4387 | ''' |
4388 | return libvlc_media_get_stats(self, p_stats) |
4389 | |
4390 | - |
4391 | def subitems(self): |
4392 | '''Get subitems of media descriptor object. This will increment |
4393 | the reference count of supplied media descriptor object. Use |
4394 | @@ -2082,71 +2706,164 @@ |
4395 | ''' |
4396 | return libvlc_media_event_manager(self) |
4397 | |
4398 | - |
4399 | def get_duration(self): |
4400 | '''Get duration (in ms) of media descriptor object item. |
4401 | @return: duration of media item or -1 on error. |
4402 | ''' |
4403 | return libvlc_media_get_duration(self) |
4404 | |
4405 | - |
4406 | + def parse_with_options(self, parse_flag, timeout): |
4407 | + '''Parse the media asynchronously with options. |
4408 | + This fetches (local or network) art, meta data and/or tracks information. |
4409 | + This method is the extended version of L{parse_with_options}(). |
4410 | + To track when this is over you can listen to libvlc_MediaParsedChanged |
4411 | + event. However if this functions returns an error, you will not receive any |
4412 | + events. |
4413 | + It uses a flag to specify parse options (see L{MediaParseFlag}). All |
4414 | + these flags can be combined. By default, media is parsed if it's a local |
4415 | + file. |
4416 | + @note: Parsing can be aborted with L{parse_stop}(). |
4417 | + See libvlc_MediaParsedChanged |
4418 | + See L{get_meta} |
4419 | + See L{tracks_get} |
4420 | + See L{get_parsed_status} |
4421 | + See L{MediaParseFlag}. |
4422 | + @param parse_flag: parse options: |
4423 | + @param timeout: maximum time allowed to preparse the media. If -1, the default "preparse-timeout" option will be used as a timeout. If 0, it will wait indefinitely. If > 0, the timeout will be used (in milliseconds). |
4424 | + @return: -1 in case of error, 0 otherwise. |
4425 | + @version: LibVLC 3.0.0 or later. |
4426 | + ''' |
4427 | + return libvlc_media_parse_with_options(self, parse_flag, timeout) |
4428 | + |
4429 | + def parse_stop(self): |
4430 | + '''Stop the parsing of the media |
4431 | + When the media parsing is stopped, the libvlc_MediaParsedChanged event will |
4432 | + be sent with the libvlc_media_parsed_status_timeout status. |
4433 | + See L{parse_with_options}. |
4434 | + @version: LibVLC 3.0.0 or later. |
4435 | + ''' |
4436 | + return libvlc_media_parse_stop(self) |
4437 | + |
4438 | + def get_parsed_status(self): |
4439 | + '''Get Parsed status for media descriptor object. |
4440 | + See libvlc_MediaParsedChanged |
4441 | + See L{MediaParsedStatus}. |
4442 | + @return: a value of the L{MediaParsedStatus} enum. |
4443 | + @version: LibVLC 3.0.0 or later. |
4444 | + ''' |
4445 | + return libvlc_media_get_parsed_status(self) |
4446 | + |
4447 | + def set_user_data(self, p_new_user_data): |
4448 | + '''Sets media descriptor's user_data. user_data is specialized data |
4449 | + accessed by the host application, VLC.framework uses it as a pointer to |
4450 | + an native object that references a L{Media} pointer. |
4451 | + @param p_new_user_data: pointer to user data. |
4452 | + ''' |
4453 | + return libvlc_media_set_user_data(self, p_new_user_data) |
4454 | + |
4455 | + def get_user_data(self): |
4456 | + '''Get media descriptor's user_data. user_data is specialized data |
4457 | + accessed by the host application, VLC.framework uses it as a pointer to |
4458 | + an native object that references a L{Media} pointer. |
4459 | + ''' |
4460 | + return libvlc_media_get_user_data(self) |
4461 | + |
4462 | + def get_type(self): |
4463 | + '''Get the media type of the media descriptor object. |
4464 | + @return: media type. |
4465 | + @version: LibVLC 3.0.0 and later. See L{MediaType}. |
4466 | + ''' |
4467 | + return libvlc_media_get_type(self) |
4468 | + |
4469 | + def slaves_add(self, i_type, i_priority, psz_uri): |
4470 | + '''Add a slave to the current media. |
4471 | + A slave is an external input source that may contains an additional subtitle |
4472 | + track (like a .srt) or an additional audio track (like a .ac3). |
4473 | + @note: This function must be called before the media is parsed (via |
4474 | + L{parse_with_options}()) or before the media is played (via |
4475 | + L{player_play}()). |
4476 | + @param i_type: subtitle or audio. |
4477 | + @param i_priority: from 0 (low priority) to 4 (high priority). |
4478 | + @param psz_uri: Uri of the slave (should contain a valid scheme). |
4479 | + @return: 0 on success, -1 on error. |
4480 | + @version: LibVLC 3.0.0 and later. |
4481 | + ''' |
4482 | + return libvlc_media_slaves_add(self, i_type, i_priority, str_to_bytes(psz_uri)) |
4483 | + |
4484 | + def slaves_clear(self): |
4485 | + '''Clear all slaves previously added by L{slaves_add}() or |
4486 | + internally. |
4487 | + @version: LibVLC 3.0.0 and later. |
4488 | + ''' |
4489 | + return libvlc_media_slaves_clear(self) |
4490 | + |
4491 | + def slaves_get(self, ppp_slaves): |
4492 | + '''Get a media descriptor's slave list |
4493 | + The list will contain slaves parsed by VLC or previously added by |
4494 | + L{slaves_add}(). The typical use case of this function is to save |
4495 | + a list of slave in a database for a later use. |
4496 | + @param ppp_slaves: address to store an allocated array of slaves (must be freed with L{slaves_release}()) [OUT]. |
4497 | + @return: the number of slaves (zero on error). |
4498 | + @version: LibVLC 3.0.0 and later. See L{slaves_add}. |
4499 | + ''' |
4500 | + return libvlc_media_slaves_get(self, ppp_slaves) |
4501 | + |
4502 | def parse(self): |
4503 | '''Parse a media. |
4504 | - This fetches (local) meta data and tracks information. |
4505 | + This fetches (local) art, meta data and tracks information. |
4506 | The method is synchronous. |
4507 | - See L{parse_async} |
4508 | + \deprecated This function could block indefinitely. |
4509 | + Use L{parse_with_options}() instead |
4510 | + See L{parse_with_options} |
4511 | See L{get_meta} |
4512 | - See libvlc_media_get_tracks_info. |
4513 | + See L{get_tracks_info}. |
4514 | ''' |
4515 | return libvlc_media_parse(self) |
4516 | |
4517 | - |
4518 | def parse_async(self): |
4519 | '''Parse a media. |
4520 | - This fetches (local) meta data and tracks information. |
4521 | + This fetches (local) art, meta data and tracks information. |
4522 | The method is the asynchronous of L{parse}(). |
4523 | To track when this is over you can listen to libvlc_MediaParsedChanged |
4524 | event. However if the media was already parsed you will not receive this |
4525 | event. |
4526 | + \deprecated You can't be sure to receive the libvlc_MediaParsedChanged |
4527 | + event (you can wait indefinitely for this event). |
4528 | + Use L{parse_with_options}() instead |
4529 | See L{parse} |
4530 | See libvlc_MediaParsedChanged |
4531 | See L{get_meta} |
4532 | - See libvlc_media_get_tracks_info. |
4533 | + See L{get_tracks_info}. |
4534 | ''' |
4535 | return libvlc_media_parse_async(self) |
4536 | |
4537 | - |
4538 | def is_parsed(self): |
4539 | - '''Get Parsed status for media descriptor object. |
4540 | + '''Return true is the media descriptor object is parsed |
4541 | + \deprecated This can return true in case of failure. |
4542 | + Use L{get_parsed_status}() instead |
4543 | See libvlc_MediaParsedChanged. |
4544 | @return: true if media object has been parsed otherwise it returns false \libvlc_return_bool. |
4545 | ''' |
4546 | return libvlc_media_is_parsed(self) |
4547 | |
4548 | - |
4549 | - def set_user_data(self, p_new_user_data): |
4550 | - '''Sets media descriptor's user_data. user_data is specialized data |
4551 | - accessed by the host application, VLC.framework uses it as a pointer to |
4552 | - an native object that references a L{Media} pointer. |
4553 | - @param p_new_user_data: pointer to user data. |
4554 | - ''' |
4555 | - return libvlc_media_set_user_data(self, p_new_user_data) |
4556 | - |
4557 | - |
4558 | - def get_user_data(self): |
4559 | - '''Get media descriptor's user_data. user_data is specialized data |
4560 | - accessed by the host application, VLC.framework uses it as a pointer to |
4561 | - an native object that references a L{Media} pointer. |
4562 | - ''' |
4563 | - return libvlc_media_get_user_data(self) |
4564 | - |
4565 | - |
4566 | + def get_tracks_info(self): |
4567 | + '''Get media descriptor's elementary streams description |
4568 | + Note, you need to call L{parse}() or play the media at least once |
4569 | + before calling this function. |
4570 | + Not doing this will result in an empty array. |
4571 | + \deprecated Use L{tracks_get}() instead. |
4572 | + @param tracks: address to store an allocated array of Elementary Streams descriptions (must be freed by the caller) [OUT]. |
4573 | + @return: the number of Elementary Streams. |
4574 | + ''' |
4575 | + return libvlc_media_get_tracks_info(self) |
4576 | + |
4577 | def player_new_from_media(self): |
4578 | '''Create a Media Player object from a Media. |
4579 | @return: a new media player object, or None on error. |
4580 | ''' |
4581 | return libvlc_media_player_new_from_media(self) |
4582 | |
4583 | + |
4584 | class MediaDiscoverer(_Ctype): |
4585 | '''N/A |
4586 | ''' |
4587 | @@ -2155,41 +2872,60 @@ |
4588 | '''(INTERNAL) ctypes wrapper constructor. |
4589 | ''' |
4590 | return _Constructor(cls, ptr) |
4591 | - |
4592 | + |
4593 | + def start(self): |
4594 | + '''Start media discovery. |
4595 | + To stop it, call L{stop}() or |
4596 | + L{list_release}() directly. |
4597 | + See L{stop}. |
4598 | + @return: -1 in case of error, 0 otherwise. |
4599 | + @version: LibVLC 3.0.0 or later. |
4600 | + ''' |
4601 | + return libvlc_media_discoverer_start(self) |
4602 | + |
4603 | + def stop(self): |
4604 | + '''Stop media discovery. |
4605 | + See L{start}. |
4606 | + @version: LibVLC 3.0.0 or later. |
4607 | + ''' |
4608 | + return libvlc_media_discoverer_stop(self) |
4609 | + |
4610 | def release(self): |
4611 | '''Release media discover object. If the reference count reaches 0, then |
4612 | the object will be released. |
4613 | ''' |
4614 | return libvlc_media_discoverer_release(self) |
4615 | |
4616 | - |
4617 | - def localized_name(self): |
4618 | - '''Get media service discover object its localized name. |
4619 | - @return: localized name. |
4620 | - ''' |
4621 | - return libvlc_media_discoverer_localized_name(self) |
4622 | - |
4623 | - |
4624 | def media_list(self): |
4625 | '''Get media service discover media list. |
4626 | @return: list of media items. |
4627 | ''' |
4628 | return libvlc_media_discoverer_media_list(self) |
4629 | |
4630 | - @memoize_parameterless |
4631 | - def event_manager(self): |
4632 | - '''Get event manager from media service discover object. |
4633 | - @return: event manager object. |
4634 | - ''' |
4635 | - return libvlc_media_discoverer_event_manager(self) |
4636 | - |
4637 | - |
4638 | def is_running(self): |
4639 | '''Query if media service discover object is running. |
4640 | @return: true if running, false if not \libvlc_return_bool. |
4641 | ''' |
4642 | return libvlc_media_discoverer_is_running(self) |
4643 | |
4644 | + def localized_name(self): |
4645 | + '''Get media service discover object its localized name. |
4646 | + \deprecated Useless, use L{list_get}() to get the |
4647 | + longname of the service discovery. |
4648 | + @return: localized name or None if the media_discoverer is not started. |
4649 | + ''' |
4650 | + return libvlc_media_discoverer_localized_name(self) |
4651 | + |
4652 | + @memoize_parameterless |
4653 | + def event_manager(self): |
4654 | + '''Get event manager from media service discover object. |
4655 | + \deprecated Useless, media_discoverer events are only triggered when calling |
4656 | + L{start}() and L{stop}(). |
4657 | + @return: event manager object. |
4658 | + ''' |
4659 | + return libvlc_media_discoverer_event_manager(self) |
4660 | + |
4661 | + |
4662 | class MediaLibrary(_Ctype): |
4663 | '''N/A |
4664 | ''' |
4665 | @@ -2198,7 +2934,7 @@ |
4666 | '''(INTERNAL) ctypes wrapper constructor. |
4667 | ''' |
4668 | return _Constructor(cls, ptr) |
4669 | - |
4670 | + |
4671 | def release(self): |
4672 | '''Release media library object. This functions decrements the |
4673 | reference count of the media library object. If it reaches 0, |
4674 | @@ -2206,7 +2942,6 @@ |
4675 | ''' |
4676 | return libvlc_media_library_release(self) |
4677 | |
4678 | - |
4679 | def retain(self): |
4680 | '''Retain a reference to a media library object. This function will |
4681 | increment the reference counting for this object. Use |
4682 | @@ -2214,27 +2949,26 @@ |
4683 | ''' |
4684 | return libvlc_media_library_retain(self) |
4685 | |
4686 | - |
4687 | def load(self): |
4688 | '''Load media library. |
4689 | @return: 0 on success, -1 on error. |
4690 | ''' |
4691 | return libvlc_media_library_load(self) |
4692 | |
4693 | - |
4694 | def media_list(self): |
4695 | '''Get media library subitems. |
4696 | @return: media list subitems. |
4697 | ''' |
4698 | return libvlc_media_library_media_list(self) |
4699 | |
4700 | + |
4701 | class MediaList(_Ctype): |
4702 | '''Create a new MediaList instance. |
4703 | - |
4704 | + |
4705 | Usage: MediaList(list_of_MRLs) |
4706 | |
4707 | See vlc.Instance.media_list_new documentation for details. |
4708 | - |
4709 | + |
4710 | ''' |
4711 | |
4712 | def __new__(cls, *args): |
4713 | @@ -2250,10 +2984,10 @@ |
4714 | |
4715 | def get_instance(self): |
4716 | return getattr(self, '_instance', None) |
4717 | - |
4718 | + |
4719 | def add_media(self, mrl): |
4720 | """Add media instance to media list. |
4721 | - |
4722 | + |
4723 | The L{lock} should be held upon entering this function. |
4724 | @param mrl: a media instance or a MRL. |
4725 | @return: 0 on success, -1 if the media list is read-only. |
4726 | @@ -2262,20 +2996,16 @@ |
4727 | mrl = (self.get_instance() or get_default_instance()).media_new(mrl) |
4728 | return libvlc_media_list_add_media(self, mrl) |
4729 | |
4730 | - |
4731 | - |
4732 | def release(self): |
4733 | '''Release media list created with L{new}(). |
4734 | ''' |
4735 | return libvlc_media_list_release(self) |
4736 | |
4737 | - |
4738 | def retain(self): |
4739 | '''Retain reference to a media list. |
4740 | ''' |
4741 | return libvlc_media_list_retain(self) |
4742 | |
4743 | - |
4744 | def set_media(self, p_md): |
4745 | '''Associate media instance with this media list instance. |
4746 | If another media instance was present it will be released. |
4747 | @@ -2284,7 +3014,6 @@ |
4748 | ''' |
4749 | return libvlc_media_list_set_media(self, p_md) |
4750 | |
4751 | - |
4752 | def media(self): |
4753 | '''Get media instance from this media list instance. This action will increase |
4754 | the refcount on the media instance. |
4755 | @@ -2293,7 +3022,6 @@ |
4756 | ''' |
4757 | return libvlc_media_list_media(self) |
4758 | |
4759 | - |
4760 | def insert_media(self, p_md, i_pos): |
4761 | '''Insert media instance in media list on a position |
4762 | The L{lock} should be held upon entering this function. |
4763 | @@ -2303,7 +3031,6 @@ |
4764 | ''' |
4765 | return libvlc_media_list_insert_media(self, p_md, i_pos) |
4766 | |
4767 | - |
4768 | def remove_index(self, i_pos): |
4769 | '''Remove media instance from media list on a position |
4770 | The L{lock} should be held upon entering this function. |
4771 | @@ -2312,7 +3039,6 @@ |
4772 | ''' |
4773 | return libvlc_media_list_remove_index(self, i_pos) |
4774 | |
4775 | - |
4776 | def count(self): |
4777 | '''Get count on media list items |
4778 | The L{lock} should be held upon entering this function. |
4779 | @@ -2323,7 +3049,6 @@ |
4780 | def __len__(self): |
4781 | return libvlc_media_list_count(self) |
4782 | |
4783 | - |
4784 | def item_at_index(self, i_pos): |
4785 | '''List media instance in media list at a position |
4786 | The L{lock} should be held upon entering this function. |
4787 | @@ -2339,7 +3064,6 @@ |
4788 | for i in range(len(self)): |
4789 | yield self[i] |
4790 | |
4791 | - |
4792 | def index_of_item(self, p_md): |
4793 | '''Find index position of List media instance in media list. |
4794 | Warning: the function will return the first matched position. |
4795 | @@ -2349,20 +3073,17 @@ |
4796 | ''' |
4797 | return libvlc_media_list_index_of_item(self, p_md) |
4798 | |
4799 | - |
4800 | def is_readonly(self): |
4801 | '''This indicates if this media list is read-only from a user point of view. |
4802 | @return: 1 on readonly, 0 on readwrite \libvlc_return_bool. |
4803 | ''' |
4804 | return libvlc_media_list_is_readonly(self) |
4805 | |
4806 | - |
4807 | def lock(self): |
4808 | '''Get lock on media list items. |
4809 | ''' |
4810 | return libvlc_media_list_lock(self) |
4811 | |
4812 | - |
4813 | def unlock(self): |
4814 | '''Release lock on media list items |
4815 | The L{lock} should be held upon entering this function. |
4816 | @@ -2377,13 +3098,14 @@ |
4817 | ''' |
4818 | return libvlc_media_list_event_manager(self) |
4819 | |
4820 | + |
4821 | class MediaListPlayer(_Ctype): |
4822 | '''Create a new MediaListPlayer instance. |
4823 | |
4824 | It may take as parameter either: |
4825 | - a vlc.Instance |
4826 | - nothing |
4827 | - |
4828 | + |
4829 | ''' |
4830 | |
4831 | def __new__(cls, arg=None): |
4832 | @@ -2401,10 +3123,8 @@ |
4833 | def get_instance(self): |
4834 | """Return the associated Instance. |
4835 | """ |
4836 | - return self._instance #PYCHOK expected |
4837 | - |
4838 | - |
4839 | - |
4840 | + return self._instance # PYCHOK expected |
4841 | + |
4842 | def release(self): |
4843 | '''Release a media_list_player after use |
4844 | Decrement the reference count of a media player object. If the |
4845 | @@ -2414,7 +3134,6 @@ |
4846 | ''' |
4847 | return libvlc_media_list_player_release(self) |
4848 | |
4849 | - |
4850 | def retain(self): |
4851 | '''Retain a reference to a media player list object. Use |
4852 | L{release}() to decrement reference count. |
4853 | @@ -2428,47 +3147,53 @@ |
4854 | ''' |
4855 | return libvlc_media_list_player_event_manager(self) |
4856 | |
4857 | - |
4858 | def set_media_player(self, p_mi): |
4859 | '''Replace media player in media_list_player with this instance. |
4860 | @param p_mi: media player instance. |
4861 | ''' |
4862 | return libvlc_media_list_player_set_media_player(self, p_mi) |
4863 | |
4864 | - |
4865 | + def get_media_player(self): |
4866 | + '''Get media player of the media_list_player instance. |
4867 | + @return: media player instance @note the caller is responsible for releasing the returned instance. |
4868 | + ''' |
4869 | + return libvlc_media_list_player_get_media_player(self) |
4870 | + |
4871 | def set_media_list(self, p_mlist): |
4872 | '''Set the media list associated with the player. |
4873 | @param p_mlist: list of media. |
4874 | ''' |
4875 | return libvlc_media_list_player_set_media_list(self, p_mlist) |
4876 | |
4877 | - |
4878 | def play(self): |
4879 | '''Play media list. |
4880 | ''' |
4881 | return libvlc_media_list_player_play(self) |
4882 | |
4883 | - |
4884 | def pause(self): |
4885 | '''Toggle pause (or resume) media list. |
4886 | ''' |
4887 | return libvlc_media_list_player_pause(self) |
4888 | |
4889 | - |
4890 | + def set_pause(self, do_pause): |
4891 | + '''Pause or resume media list. |
4892 | + @param do_pause: play/resume if zero, pause if non-zero. |
4893 | + @version: LibVLC 3.0.0 or later. |
4894 | + ''' |
4895 | + return libvlc_media_list_player_set_pause(self, do_pause) |
4896 | + |
4897 | def is_playing(self): |
4898 | '''Is media list playing? |
4899 | @return: true for playing and false for not playing \libvlc_return_bool. |
4900 | ''' |
4901 | return libvlc_media_list_player_is_playing(self) |
4902 | |
4903 | - |
4904 | def get_state(self): |
4905 | '''Get current libvlc_state of media list player. |
4906 | - @return: libvlc_state_t for media list player. |
4907 | + @return: L{State} for media list player. |
4908 | ''' |
4909 | return libvlc_media_list_player_get_state(self) |
4910 | |
4911 | - |
4912 | def play_item_at_index(self, i_index): |
4913 | '''Play media list item at position index. |
4914 | @param i_index: index in media list to play. |
4915 | @@ -2483,7 +3208,6 @@ |
4916 | for i in range(len(self)): |
4917 | yield self[i] |
4918 | |
4919 | - |
4920 | def play_item(self, p_md): |
4921 | '''Play the given media item. |
4922 | @param p_md: the media instance. |
4923 | @@ -2491,46 +3215,43 @@ |
4924 | ''' |
4925 | return libvlc_media_list_player_play_item(self, p_md) |
4926 | |
4927 | - |
4928 | def stop(self): |
4929 | '''Stop playing media list. |
4930 | ''' |
4931 | return libvlc_media_list_player_stop(self) |
4932 | |
4933 | - |
4934 | def next(self): |
4935 | '''Play next item from media list. |
4936 | @return: 0 upon success -1 if there is no next item. |
4937 | ''' |
4938 | return libvlc_media_list_player_next(self) |
4939 | |
4940 | - |
4941 | def previous(self): |
4942 | '''Play previous item from media list. |
4943 | @return: 0 upon success -1 if there is no previous item. |
4944 | ''' |
4945 | return libvlc_media_list_player_previous(self) |
4946 | |
4947 | - |
4948 | def set_playback_mode(self, e_mode): |
4949 | '''Sets the playback mode for the playlist. |
4950 | @param e_mode: playback mode specification. |
4951 | ''' |
4952 | return libvlc_media_list_player_set_playback_mode(self, e_mode) |
4953 | |
4954 | + |
4955 | class MediaPlayer(_Ctype): |
4956 | '''Create a new MediaPlayer instance. |
4957 | |
4958 | It may take as parameter either: |
4959 | - a string (media URI), options... In this case, a vlc.Instance will be created. |
4960 | - a vlc.Instance, a string (media URI), options... |
4961 | - |
4962 | + |
4963 | ''' |
4964 | |
4965 | def __new__(cls, *args): |
4966 | if len(args) == 1 and isinstance(args[0], _Ints): |
4967 | return _Constructor(cls, args[0]) |
4968 | - |
4969 | + |
4970 | if args and isinstance(args[0], Instance): |
4971 | instance = args[0] |
4972 | args = args[1:] |
4973 | @@ -2545,7 +3266,7 @@ |
4974 | def get_instance(self): |
4975 | """Return the associated Instance. |
4976 | """ |
4977 | - return self._instance #PYCHOK expected |
4978 | + return self._instance # PYCHOK expected |
4979 | |
4980 | def set_mrl(self, mrl, *options): |
4981 | """Set the MRL to play. |
4982 | @@ -2596,19 +3317,31 @@ |
4983 | ''' |
4984 | titleDescription_pp = ctypes.POINTER(TitleDescription)() |
4985 | n = libvlc_media_player_get_full_title_descriptions(self, ctypes.byref(titleDescription_pp)) |
4986 | - info = ctypes.cast(ctypes.titleDescription_pp, ctypes.POINTER(ctypes.POINTER(TitleDescription) * n)) |
4987 | - return info |
4988 | + info = ctypes.cast(titleDescription_pp, ctypes.POINTER(ctypes.POINTER(TitleDescription) * n)) |
4989 | + try: |
4990 | + contents = info.contents |
4991 | + except ValueError: |
4992 | + # Media not parsed, no info. |
4993 | + return None |
4994 | + descr = (contents[i].contents for i in range(len(contents))) |
4995 | + return descr |
4996 | |
4997 | def get_full_chapter_descriptions(self, i_chapters_of_title): |
4998 | '''Get the full description of available chapters. |
4999 | - @param index: of the title to query for chapters. |
5000 | - @return: the chapter list |
The diff has been truncated for viewing.