PBToolboxAI v4 ← Site

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 #

Userobjectu_pbt_video
Item class— (component without items)
Used forA training film in the application, a product video, the replay of a recording, a showcase loop on a stand
PrincipleA <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
DependencyThe 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 #

PropertyTypeDefaultRole
is_sourcestring""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_autoplaybooleanfalseStarts 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_mutedbooleanfalseCuts the sound, volume kept; the bar button and the M key set it too
ii_volumeinteger100Volume in percent, 0 to 100; the bar slider and the up/down arrows too
ib_loopbooleanfalsePlays the film again and again until of_stop; a looping film never raises ue_ended
ii_rateinteger100Speed in percent, 25 to 400: 50 = half, 200 = twice, the sound follows
is_stretchstring"uniform"Framing: STRETCH_NONE, STRETCH_FILL, STRETCH_UNIFORM, STRETCH_UNIFORMTOFILL — the four modes of a picture
ib_controlsbooleantrueThe component's transport bar, themed. false hides it: your window drives the film
is_posterstring""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_subtitlesstring""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_langstring""The subtitle track shown (a language of of_add_subtitles); empty = none
ii_fpsinteger25Pictures per second of the film, for of_step_frames
ib_remember_positionbooleanfalseRemembers where each film is left and resumes there at the next of_play of the same source
is_theme_stylestring""Visual style of the component (THEME_STYLE_* constants); empty = the application's, followed at every change
is_theme_modestring""Light or dark variant (THEME_MODE_* constants); empty = the application's, followed at every change
il_theme_accentlong-1Accent colour of this component (-1 = the application accent, or the theme's)
is_tooltipstring""Simple tooltip shown when hovering the component
is_super_tooltip_titlestring""Title of the rich tooltip (takes precedence over is_tooltip)
is_super_tooltip_textstring""Text of the rich tooltip (rich markup accepted)
is_super_tooltip_imagestring""Image of the rich tooltip
ib_enabledbooleantruefalse: dimmed picture, bar and keyboard inert — except Escape in full screen: leaving is always possible; your code still commands
ib_scrub_previewbooleantrueA 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_hiddenbooleantruePauses 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 #

MethodRole
of_play ( ) → longPlays 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) → longSets is_source and plays it: the same call as the sound player's. Returns 0 once sent, -1 without a component
of_pause ( ) → longSuspends 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) → longMoves 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 ( ) → booleanTrue while a film is under way — paused included, it has not finished
of_is_paused ( ) → booleanTrue while the film is suspended — by of_pause, the bar or the keyboard
of_is_buffering ( ) → booleanTrue while the film RUNS but waits for its data — the time ue_buffering announced. Read from the component, never from a copy
of_duration ( ) → longReturns the number of milliseconds the film lasts, 0 while unknown
of_position ( ) → longReturns the number of milliseconds played since the start; ue_progress brings it every second too
of_capture (string as_path) → longSaves 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) → longThe 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) → longThe 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 ( ) → booleanTrue while the film covers the monitor
of_add_marker (long al_ms, string as_label) → longA 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 ( ) → longRemoves every marker. Returns 0, -2 when the component is not created
of_marker_count ( ) → longReturns the number of markers
of_play_range (long al_from_ms, long al_to_ms) → longPlays 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 ( ) → longFrees the film from its segment. Returns 0, -2 when the component is not created
of_step_frames (long al_frames) → longMoves 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) → longAdds 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) → longAdds 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 ( ) → longEmpties the playlist; the film playing goes on. Returns 0, -2 when the component is not created
of_next ( ) / of_previous ( ) → longThe 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 ( ) → longReturns the number of films in the playlist
of_playlist_index ( ) → longReturns the index (from 1) of the playlist film playing, 0 when off the list
of_add_subtitles (string as_lang, string as_source) → longA 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) → longRemoves 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 ( ) → longReturns the number of subtitle tracks
of_remembered_position ( ) → longReturns the number of milliseconds where is_source was left (ib_remember_position), 0 otherwise
of_has_output ( ) → booleanTrue when the workstation has an audio output
of_add_chapter (long al_ms, string as_title) → longA 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 ( ) → longRemoves 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) → longJumps 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 ( ) → longJumps 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 ( ) → longJumps 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 ( ) → longReturns how many chapters the film carries (of_add_chapter), 0 with none
of_chapter_index ( ) → longReturns 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[]) → longFills 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) → longThe 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 ( ) → booleanTrue while the film floats in its Picture-in-Picture window; false again once the user closes it
of_pip_available ( ) → booleanTrue when the engine and the workstation allow Picture-in-Picture at all: ask before offering the button

Events #

EventWhen
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 #

// 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 #

// 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 #

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.

MembersRoleDetailed in
of_resetPut the component back to zero3.6 Resetting a component: of_reset()
of_register_shortcut · of_clear_shortcutsThe component's keyboard chords3.5 Keyboard shortcuts
of_is_created · of_is_ready · of_get_last_errorWhether it was born, whether it is ready, what failed3.7 Diagnostics
of_save_as_png · of_save_as_jpgExport the rendering as an image3.8 Exporting the rendering as an image
of_set_redrawGroup changes into a single repaint3.10 Best practices
of_preload_iconsIcons shown with no delayInstant display: of_icon
of_set_translationTranslate one of the component's labels5.2 Adapting a label: of_set_translation
of_focus_webviewGive the component the focus6.4 Keyboard and focus
of_print · of_print_to_pdfPrint, or write a PDF6.9 Printing
of_set_property · of_get_property · of_component_nameDriving a property by its name3.1 The property engine

← Component reference · Guide contents