video — u_pbt_video #
← Component reference · Guide contents
Video player: a file of the workstation — streamed by the DLL, a long film starts at once — or a URL, with the component's own transport bar, which follows the theme: play, seek, time, mute, volume. WebVTT subtitles, a poster before playback, loop, speed, framing, capture of the current picture as PNG or JPEG. Whatever the user does on the bar, your application knows.
▶ See it live — Demo application, Video player tile: the film, the code driving it and this page, side by side (Internet connection needed for the sample film).
At a glance #
| Userobject | u_pbt_video |
| Item class | — (component without items) |
| Used for | A training film in the application, a product video, the replay of a recording, a showcase loop on a stand |
| Principle | A <video> of the WebView2 engine: every format it decodes (mp4, webm, m4v, mov, mkv). The bar is the component's; its gestures go through the same verbs as your calls, hence the same events |
| Dependency | The WebView2 runtime, already required by the library — nothing else |
Quick start #
// A film of the workstation, streamed by the DLL : starts at once
uo_video.is_poster = "img\packimages.dll:PNG/COVER" // shown until the film starts
uo_video.is_subtitles = "films\training.vtt"
uo_video.of_play(/*source*/ "films\training.mp4")
// A URL plays the same way
uo_video.of_play(/*source*/ "https://www.w3schools.com/html/mov_bbb.mp4")
// The user pauses from the bar, or your code does : either way ue_paused fires
uo_video.of_pause()
uo_video.of_seek(/*ms*/ 90000) // to 1:30, in milliseconds
Everything you set is a property (is_source, ii_volume, ib_loop…), read live from the component; everything you do is a method (of_play, of_pause, of_stop, of_seek, of_capture); everything that happens is an event (ue_started, ue_ended, ue_progress…). A missing file is not an exception: ue_failed says so, and the message shows on the picture.
Properties #
| Property | Type | Default | Role |
|---|---|---|---|
is_source | string | "" | The film: a file of the workstation (any path, streamed) or an https URL. An http:// address is refused (ue_failed, REASON_INSECURE): the engine upgrades it to https and fails — download the film first (restclient, of_download). Formats: mp4, webm, m4v, mov (an iPhone or camera film in H.264), mkv, and the audio ones; avi, wmv and flv are refused by their name (REASON_FORMAT). Setting it stops what was playing; ib_autoplay decides whether the new one starts by itself. A film of any size, in a 32-bit application too: the DLL streams it by slices, never the whole file at once; a film the engine cannot decode is reported by ue_failed. A NEW film leaves behind what belonged to the old one: its segment, subtitles, markers and chapters (set before any film, they wait for the first one); a playlist film keeps its own subtitles |
ib_autoplay | boolean | false | Starts the film as soon as is_source is set; otherwise it waits for of_play, the bar or the keyboard, and shows is_poster |
ib_muted | boolean | false | Cuts the sound, volume kept; the bar button and the M key set it too |
ii_volume | integer | 100 | Volume in percent, 0 to 100; the bar slider and the up/down arrows too |
ib_loop | boolean | false | Plays the film again and again until of_stop; a looping film never raises ue_ended |
ii_rate | integer | 100 | Speed in percent, 25 to 400: 50 = half, 200 = twice, the sound follows |
is_stretch | string | "uniform" | Framing: STRETCH_NONE, STRETCH_FILL, STRETCH_UNIFORM, STRETCH_UNIFORMTOFILL — the four modes of a picture |
ib_controls | boolean | true | The component's transport bar, themed. false hides it: your window drives the film |
is_poster | string | "" | The poster shown before the film: a file, a URL or pack.dll:NAME, like a picture's source. A mono:/tint:/white:/black: prefix recolours a monochrome image to the theme |
is_subtitles | string | "" | A subtitle file, local or an https URL: WebVTT (.vtt) or SubRip (.srt, converted — UTF-8, UTF-16 or the workstation's ANSI code page). A URL is DOWNLOADED by the component: its server must allow CORS (GitHub, a CDN do); a refusal, or an http:// URL, is told by ue_subtitles_failed and the film plays on. One track; of_add_subtitles piles up several. It belongs to the film: a new is_source drops it |
is_subtitle_lang | string | "" | The subtitle track shown (a language of of_add_subtitles); empty = none |
ii_fps | integer | 25 | Pictures per second of the film, for of_step_frames |
ib_remember_position | boolean | false | Remembers where each film is left and resumes there at the next of_play of the same source |
is_theme_style | string | "" | Visual style of the component (THEME_STYLE_* constants); empty = the application's, followed at every change |
is_theme_mode | string | "" | Light or dark variant (THEME_MODE_* constants); empty = the application's, followed at every change |
il_theme_accent | long | -1 | Accent colour of this component (-1 = the application accent, or the theme's) |
is_tooltip | string | "" | Simple tooltip shown when hovering the component |
is_super_tooltip_title | string | "" | Title of the rich tooltip (takes precedence over is_tooltip) |
is_super_tooltip_text | string | "" | Text of the rich tooltip (rich markup accepted) |
is_super_tooltip_image | string | "" | Image of the rich tooltip |
ib_enabled | boolean | true | false: dimmed picture, bar and keyboard inert — except Escape in full screen: leaving is always possible; your code still commands |
ib_scrub_preview | boolean | true | A time bubble follows the cursor over the seek bar (true, the default), with the chapter when there are any. false hides it |
ib_pause_when_hidden | boolean | true | Pauses the film when the component is HIDDEN (another page of a PBToolboxAI tab or dock, PBT_SetVisible): ue_paused follows, and the film waits for of_play, it never resumes by itself. false keeps it playing (a wallboard). A NATIVE PowerBuilder Tab does not tell the component: call of_pause in its SelectionChanged |
A click on the picture pauses, a second one resumes. Keyboard, when the film has the focus: Space or K play/pause, ←/→ five seconds, ↑/↓ volume, M mute, Home/End.
Methods #
| Method | Role | |
|---|---|---|
of_play ( ) → long | Plays is_source from where it is: from the start the first time, from the pause afterwards (ue_resumed). Returns 0 once sent, -2 when the component is not created | |
of_play (string as_source) → long | Sets is_source and plays it: the same call as the sound player's. Returns 0 once sent, -1 without a component | |
of_pause ( ) → long | Suspends the film where it is; of_play picks it up. Returns 0 once sent, -1 without a component | |
of_stop ( ) | Stops the film and goes back to its start; ue_stopped follows | |
of_seek (long al_ms) → long | Moves to a position of the film, in milliseconds, playing or not; a local file seeks at once. ue_seeked follows, as for the bar. Returns 0 once sent, -2 when the component is not created | |
of_is_playing ( ) → boolean | True while a film is under way — paused included, it has not finished | |
of_is_paused ( ) → boolean | True while the film is suspended — by of_pause, the bar or the keyboard | |
of_is_buffering ( ) → boolean | True while the film RUNS but waits for its data — the time ue_buffering announced. Read from the component, never from a copy | |
of_duration ( ) → long | Returns the number of milliseconds the film lasts, 0 while unknown | |
of_position ( ) → long | Returns the number of milliseconds played since the start; ue_progress brings it every second too | |
of_capture (string as_path) → long | Saves the picture shown now, at the film's size: of_capture(as_path, 0). The EXTENSION chooses the format: .jpg or .jpeg writes a JPEG, anything else a PNG; waits for the first decoded picture (10 s at most), so it can follow of_play directly. Returns 0 once written, -4 without a film, with a film that could not load, without a picture in time, when a film from another site refuses its pixels or when the file cannot be written, -5 on an empty path or one that depends on the current folder (\x, C:x), -2 when the component is not created; after a negative return, of_get_last_error says why. A relative path is written in the folder the application started in (the current folder when the library was loaded, the same in the IDE and compiled) | |
of_capture (string as_path, long al_max_width) → long | The same capture, SCALED DOWN to al_max_width pixels wide (height in proportion): the thumbnail of a 4K film is not a 4K picture. 0 keeps the film's size. Same returns as of_capture(as_path) | |
of_fullscreen (boolean ab_on) → long | The film on the WHOLE monitor (the DLL moves the control into a window of its own; your window is not touched), or back. Above everything while it is the active window: Alt+Tab to another application brings that application in front, and coming back to yours puts the film above everything again. Double click, the bar's button, Escape, Alt+F4. Escape leaves even when ib_enabled is false. These gestures and this call raise ue_fullscreen_changed (of_is_fullscreen reads it). Returns 0, -2 when the component is not created | |
of_is_fullscreen ( ) → boolean | True while the film covers the monitor | |
of_add_marker (long al_ms, string as_label) → long | A MARKER on the bar: a clickable tick, and ue_marker_reached when the film passes it. Returns 0, -5 on a negative position, -2 when the component is not created | |
of_clear_markers ( ) → long | Removes every marker. Returns 0, -2 when the component is not created | |
of_marker_count ( ) → long | Returns the number of markers | |
of_play_range (long al_from_ms, long al_to_ms) → long | Plays ONE segment: at its end, ue_ended, or with ib_loop the segment starts again. Returns 0, -5 when the bounds make no sense, -2 when the component is not created | |
of_clear_range ( ) → long | Frees the film from its segment. Returns 0, -2 when the component is not created | |
of_step_frames (long al_frames) → long | Moves by al_frames pictures (ii_fps), back when negative, and pauses; keys . and , on the picture. ue_seeked follows, as for the keys. Returns 0, -2 when the component is not created | |
of_add_source (string as_source) → long | Adds a film to the PLAYLIST: the first becomes is_source (over a film set before, unless that one is PLAYING: the playlist then follows it when it ends), the next ones follow by themselves (ue_source_changed for each film that follows, and for the first one when this call loads it). Returns 0, -5 on an empty source, -2 when the component is not created | |
of_add_source (string as_source, string as_subtitles) → long | Adds a film WITH its subtitle file (.vtt or .srt, converted by the DLL): the subtitle belongs to that film and shows only when it plays. The simple, unambiguous way to subtitle a playlist. Returns 0, -5 on an empty source | |
of_clear_playlist ( ) → long | Empties the playlist; the film playing goes on. Returns 0, -2 when the component is not created | |
of_next ( ) / of_previous ( ) → long | The next or previous film of the playlist; of_playlist_index says where it is, and ue_source_changed follows. Returns 0, -2 when the component is not created | |
of_playlist_count ( ) → long | Returns the number of films in the playlist | |
of_playlist_index ( ) → long | Returns the index (from 1) of the playlist film playing, 0 when off the list | |
of_add_subtitles (string as_lang, string as_source) → long | A subtitle track per language: .vtt, or .srt converted, from the workstation or an https URL (downloaded: CORS required, see ue_subtitles_failed). The bar's CC button cycles them. Returns 0, -5 on an empty source, a language already posed on the film (of_remove_subtitles first) or holding / or ` | , -2` when the component is not created |
of_remove_subtitles (string as_lang) → long | Removes the track of a language from the film on screen (and from the playlist film that plays: it does not come back on of_previous). The track of is_subtitles is named default. Returns 0, -5 for a language the film does not carry, -2 when the component is not created | |
of_subtitle_count ( ) → long | Returns the number of subtitle tracks | |
of_remembered_position ( ) → long | Returns the number of milliseconds where is_source was left (ib_remember_position), 0 otherwise | |
of_has_output ( ) → boolean | True when the workstation has an audio output | |
of_add_chapter (long al_ms, string as_title) → long | A CHAPTER (table of contents): ue_chapter_changed when playback enters one. of_go_chapter jumps (1-based), of_next_chapter / of_previous_chapter walk them (each jump raises ue_seeked and ue_chapter_changed), of_chapter_count / of_chapter_index / of_chapters read them, of_clear_chapters empties them. Returns 0, -5 if negative | |
of_clear_chapters ( ) → long | Removes every chapter; the bar and the scrub bubble forget them. Returns 0, -2 when the component is not created | |
of_go_chapter (long al_index) → long | Jumps to chapter al_index (1-based, in the order of of_add_chapter); of_chapter_index reads it at once, and ue_seeked then ue_chapter_changed follow, as for a click on the bar. Returns 0, -5 for a number below 1 or above of_chapter_count(), -2 when the component is not created | |
of_next_chapter ( ) → long | Jumps to the chapter after the current position; of_chapter_index reads it at once, and ue_seeked then ue_chapter_changed follow. Nothing moves from the last chapter. Returns 0, -2 when the component is not created | |
of_previous_chapter ( ) → long | Jumps to the chapter before the one the playhead is in; of_chapter_index reads it at once, and ue_seeked then ue_chapter_changed follow. Nothing moves from the first chapter. Returns 0, -2 when the component is not created | |
of_chapter_count ( ) → long | Returns how many chapters the film carries (of_add_chapter), 0 with none | |
of_chapter_index ( ) → long | Returns the number (1-based) of the chapter the playhead is in, 0 before the first one or with no chapter. Read live | |
of_chapters (ref long al_ms[], ref string as_titles[]) → long | Fills the chapters in order — the position of each in ms into al_ms, its title into as_titles — to build a menu of yours; a title may hold any character. Returns how many there are, 0 with none | |
of_picture_in_picture (boolean ab_on) → long | The film in a floating window of its own (true) or back (false); ue_pip_changed follows, as when the user closes the little window. of_is_pip tells if it floats, of_pip_available if the workstation allows it. Returns 0, -2 when the component is not created | |
of_is_pip ( ) → boolean | True while the film floats in its Picture-in-Picture window; false again once the user closes it | |
of_pip_available ( ) → boolean | True when the engine and the workstation allow Picture-in-Picture at all: ask before offering the button |
Events #
| Event | When |
|---|---|
ue_started (long al_duration_ms) | The film really starts; the length when the file says it, 0 otherwise |
ue_ended (boolean ab_truncated) | The film ended of itself; ab_truncated true when the demo limit cut it |
ue_failed (string as_message, string as_reason) | The film could not play. as_reason says why in a word your code tests: REASON_INSECURE (an http:// source), REASON_FORMAT (avi, wmv, flv, or a format the engine declares unplayable), REASON_UNSUPPORTED (a missing file or an undecodable container), REASON_DECODE, REASON_NETWORK, REASON_NO_SOURCE, REASON_FAILED; as_message is the text shown on the picture |
ue_stopped ( ) | of_stop cut a film under way |
ue_paused ( ) / ue_resumed ( ) | The film is suspended, then picks up — by your code, the bar or the keyboard alike; also when the component is hidden (ib_pause_when_hidden) |
ue_progress (long al_position_ms, long al_duration_ms) | Once a second while playing: what a progress bar of yours needs, without a timer |
ue_seeked (long al_position_ms) | The position moved: the user (bar, arrows, marker) or your code — of_seek, of_step_frames and the chapter functions raise it too, like the gesture |
ue_volume_changed (long al_percent) | The user turned the volume; never ii_volume |
ue_rate_changed (long al_percent) | The user picked a speed on the bar; never ii_rate |
ue_subtitles_changed (string as_lang) | The user cycled the subtitles (CC); empty = none |
ue_muted_changed (boolean ab_on) | The user muted (true) or unmuted (false) the sound — the bar's speaker, the M key; never ib_muted |
ue_fullscreen_changed (boolean ab_on) | The film went full screen, or came back: double click, the button, Escape, Alt+F4, or of_fullscreen. of_reset never raises it |
ue_marker_reached (long al_ms, string as_label) | The film passes a marker |
ue_source_changed (long al_index, string as_source) | The playlist moves to another film: by itself, the previous one having ended, or by of_next, of_previous and the first of_add_source |
ue_chapter_changed (long al_index, string as_title) | Playback enters another chapter (of_add_chapter): its number (1-based, 0 before the first) and its title; also when the user or your code (of_go_chapter, of_next_chapter, of_previous_chapter) jumps there |
ue_pip_changed (boolean ab_on) | The film entered (true) or left (false) the Picture-in-Picture window: the user closed it, the engine moved the film there by itself, or of_picture_in_picture asked it (of_is_pip reads it) |
ue_subtitles_failed (string as_lang, string as_reason) | A subtitle file could not be loaded: an https URL whose server refuses CORS or answers an error (REASON_NETWORK, REASON_NOT_FOUND), an http:// URL (REASON_INSECURE). The track is removed, the film plays on |
ue_buffering (boolean ab_on) | The film RUNS but has to wait for its data for more than a quarter of a second (true) — a slow network, a jump far into a film from a URL: a ring in the theme's accent turns on the picture — then the wait ends (false): the film runs again, or was paused, stopped, replaced, or failed. of_reset never raises it |
Full screen, markers, segment, frame by frame #
- Full screen.
of_fullscreen(true), a double click on the picture or the bar's last button. The DLL moves the control into a window of its own covering the monitor; your PowerBuilder window is not touched, and Escape (or Alt+F4) brings the film back. It stays above everything only while it is the active window: Alt+Tab to another application brings that application in front, and coming back to yours puts the film above everything again. Escape leaves even whenib_enabledis false.ue_fullscreen_changedtells each change, both ways: these gestures of the user as well asof_fullscreen. - Markers.
of_add_marker(ms, label)puts a tick on the bar: the user sees it, hovers it (the label), clicks it (the film jumps there,ue_seeked), andue_marker_reachedarrives when the film passes it. Chapters of a training, points to check, defects found. - Segment.
of_play_range(from, to)plays one extract only; withib_loopit replays it untilof_clear_range. - Frame by frame.
of_step_frames(±n)moves by n pictures atii_fpsa second and pauses; the keys . and , do the same. The engine does not say a film's rate: you do. - The bar speaks. Each gesture has its event:
ue_seeked,ue_volume_changed,ue_rate_changed(the speed button, 0.5× to 2×),ue_subtitles_changed(the CC button),ue_muted_changed(the speaker, the M key). A move asked by your code raises the same one as the gesture:of_seek,of_step_framesand the chapter functions raiseue_seeked. A VALUE set by your code stays silent, likeSetItem:ii_volume,ii_rate,is_subtitle_lang,ib_muted.
// Chapters on the bar, then one extract in a loop
uo_video.of_add_marker(/*ms*/ 2000, /*label*/ "Intro")
uo_video.of_add_marker(/*ms*/ 5000, /*label*/ "The bunny")
uo_video.ib_loop = true
uo_video.of_play_range(/*from_ms*/ 2000, /*to_ms*/ 8000)
// Surveillance : back one picture at a time
uo_video.ii_fps = 30
uo_video.of_step_frames(/*frames*/ -1)
Playlist, subtitles, resuming, formats #
- Playlist.
of_add_sourcestacks films; the first becomesis_source, the next ones follow by themselves at the end of each,ue_source_changednames each change.of_nextandof_previousby hand, with the same event:of_playlist_indexsays where the playlist is. - What belongs to a film. Its segment, subtitles, markers and chapters: a new
is_sourceleaves them behind (set before any film, they wait for the first one). The playlist keeps its own: the subtitle given toof_add_source(film, subtitle)comes back with its film. - Several subtitle tracks.
of_add_subtitles(language, file)per language,of_remove_subtitles(language)to take one away;is_subtitle_langpicks, the bar's CC button cycles. A.srtis converted to WebVTT as it is served: nothing to convert on your side. A subtitle given by anhttpsURL is downloaded by the component: its server must allow CORS, otherwiseue_subtitles_failedsays so and the film plays on without it. - Resuming.
ib_remember_position = true: where a film is left (pause, stop) is kept by the engine on this workstation, per user, and the nextof_playof the same source resumes there. A film watched to its end starts over. - Formats. What WebView2 decodes: mp4 (H.264, AAC), webm (VP8, VP9, AV1), mov (the H.264 of an iPhone or a camera), mkv (an OBS recording), and the audio formats (mp3, wav, ogg, opus, flac, aac, m4a). Not H.265/HEVC without the Windows extension (a HEVC
.movends inue_failed, which names the extension), nor AVI, WMV, FLV: the component refuses them by their name (REASON_FORMAT) instead of a black screen. No HLS nor DASH: an IP camera goes through an mp4 or webm stream.httpsonly: an intranethttp://address is refused (REASON_INSECURE) — download the film first (restclient,of_download) or serve it from a\\server\…share. - Several audio tracks. Chromium hides them behind a flag: not exposed.
// A playlist, each film WITH its subtitles, the position remembered
uo_video.ib_remember_position = true
uo_video.of_add_source(/*source*/ "intro.mp4", /*subtitles*/ "intro.en.vtt")
uo_video.of_add_source(/*source*/ "lesson-1.mp4", /*subtitles*/ "lesson-1.en.srt") // .srt : converted by the DLL
uo_video.of_play()
// A second language for the film on screen : it stays with that film
uo_video.of_add_subtitles(/*lang*/ "fr", /*source*/ "intro.fr.vtt")
uo_video.is_subtitle_lang = "fr"
Examples #
A silent showcase loop, without a bar #
// A silent showcase film, in a loop, without its bar
uo_video.ib_controls = false
uo_video.ib_muted = true
uo_video.ib_loop = true
uo_video.is_stretch = u_pbt_video.STRETCH_UNIFORMTOFILL
uo_video.of_play(/*source*/ "films\showcase.mp4")
Your own buttons and a progress bar #
// cb_play.clicked
if uo_video.of_is_paused() or not uo_video.of_is_playing() then uo_video.of_play() else uo_video.of_pause()
// uo_video.ue_progress : once a second, no timer needed
hpb_progress.Position = al_position_ms * 100 / Max(al_duration_ms, 1)
A thumbnail of the film for a report #
// Stop the film on the picture to keep
uo_video.of_play(/*source*/ "films\training.mp4")
uo_video.of_pause()
uo_video.of_seek(/*ms*/ 15000) // the frame at 0:15
// of_capture waits for the picture itself (10 s at most) : no timer to write.
// A .jpg path writes a JPEG ; 320 : a thumbnail 320 pixels wide.
// A relative path goes to the folder the application started in.
if uo_video.of_capture(/*path*/ "C:\Reports\training.jpg", /*max_width*/ 320) < 0 then MessageBox("Capture", uo_video.of_get_last_error())
Good practice #
- A file of the workstation rather than a URL whenever you can: streamed by the DLL, it starts at once, seeks without reloading, and
of_capturemay read its pixels — which a film from another site refuses. - Script
ue_failedon any film whose path depends on data: it is your only net, and the message is already on screen. - Set
ib_autoplayonly for a showcase loop: a film that starts by itself with sound surprises the user; elsewhere the poster and the play button are enough. ue_progressreplaces a timer: once a second, position and length, only while playing.
Inherited from the common base #
These members exist on every visual component — they are not specific to this one. They are detailed once, in the transverse chapters; this table only says where to read them.
| Members | Role | Detailed in |
|---|---|---|
of_reset | Put the component back to zero | 3.6 Resetting a component: of_reset() |
of_register_shortcut · of_clear_shortcuts | The component's keyboard chords | 3.5 Keyboard shortcuts |
of_is_created · of_is_ready · of_get_last_error | Whether it was born, whether it is ready, what failed | 3.7 Diagnostics |
of_save_as_png · of_save_as_jpg | Export the rendering as an image | 3.8 Exporting the rendering as an image |
of_set_redraw | Group changes into a single repaint | 3.10 Best practices |
of_preload_icons | Icons shown with no delay | Instant display: of_icon |
of_set_translation | Translate one of the component's labels | 5.2 Adapting a label: of_set_translation |
of_focus_webview | Give the component the focus | 6.4 Keyboard and focus |
of_print · of_print_to_pdf | Print, or write a PDF | 6.9 Printing |
of_set_property · of_get_property · of_component_name | Driving a property by its name | 3.1 The property engine |