Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion sdk/python/packages/flet-video/src/flet_video/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from dataclasses import dataclass, field
from enum import Enum
from typing import Optional
from typing import Optional, Union

import flet as ft

Expand Down Expand Up @@ -90,6 +90,29 @@ class VideoConfiguration:
Specifying this option will cause [`width`][(c).] & [`height`][(c).] to be ignored.
"""

mpv_properties: Optional[dict[str, Union[str, int, float, bool]]] = None
"""
Extra mpv/libmpv properties to set on
native backends (Windows/macOS/Linux/iOS/Android).

The keys are mpv option/property names without the leading `--`. Values can be
`str`, `int`, `float` or `bool`. All values are converted to strings before being
passed to mpv; boolean values are converted to `"yes"` / `"no"`.

Full list of mpv options: https://mpv.io/manual/stable/#options

Example:
```python
>>> VideoConfiguration(
mpv_properties={
"profile": "low-latency", # --profile=low-latency
"untimed": True, # --untimed
"volume": 80, # --volume=80
}
)
```
"""


@dataclass
class VideoSubtitleTrack:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,27 @@ class _VideoControlState extends State<VideoControl> with FletStoreMixin {
late VideoController _controller;
bool _initialized = false;

Future<void> _applyMpvProperties(Control control) async {
final cfg = control.get("configuration");
if (cfg is! Map) return;

final mpvPropsRaw = cfg["mpv_properties"];
if (mpvPropsRaw is! Map) return;

final platform = _player.platform;
if (platform is! NativePlayer) return;
final native = platform as dynamic;

for (final entry in mpvPropsRaw.entries) {
final key = entry.key.toString();
final val = entry.value;
if (val == null) continue;
final valueStr = val is bool ? (val ? "yes" : "no") : val.toString();
await native.setProperty(key, valueStr);
Comment on lines +37 to +44
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Casting the NativePlayer to dynamic bypasses Dart's type safety and could lead to runtime errors if the setProperty method signature changes or doesn't exist. The code assumes that NativePlayer has a setProperty method available through dynamic invocation, but this is not type-safe.

Consider checking if the media_kit package provides a proper typed interface for setting properties, or add proper error handling around the dynamic method call to catch potential runtime errors.

Suggested change
final native = platform as dynamic;
for (final entry in mpvPropsRaw.entries) {
final key = entry.key.toString();
final val = entry.value;
if (val == null) continue;
final valueStr = val is bool ? (val ? "yes" : "no") : val.toString();
await native.setProperty(key, valueStr);
final native = platform;
for (final entry in mpvPropsRaw.entries) {
final key = entry.key.toString();
final val = entry.value;
if (val == null) continue;
final valueStr = val is bool ? (val ? "yes" : "no") : val.toString();
try {
await (native as dynamic).setProperty(key, valueStr);
} catch (e, stackTrace) {
debugPrint(
'Error setting MPV property "$key" to "$valueStr": $e\n$stackTrace',
);
}

Copilot uses AI. Check for mistakes.
}
}


void _setup(Control control) {
final playerConfig = PlayerConfiguration(
title: control.getString("title", "flet-video")!,
Expand Down Expand Up @@ -64,8 +85,14 @@ class _VideoControlState extends State<VideoControl> with FletStoreMixin {
});
}

_player.open(Playlist(parseVideoMedias(control.get("playlist"), [])!),
play: control.getBool("autoplay", false)!);
final playlist =
Playlist(parseVideoMedias(control.get("playlist"), [])!);
final autoplay = control.getBool("autoplay", false)!;

() async {
await _applyMpvProperties(control);
await _player.open(playlist, play: autoplay);
}();
}

void _teardown(Control control) {
Expand Down Expand Up @@ -294,4 +321,4 @@ class _VideoControlState extends State<VideoControl> with FletStoreMixin {

return ConstrainedControl(control: widget.control, child: video);
}
}
}