or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-rendering.mdcore-playback.mdevent-handling.mdindex.mdinput-keybinding.mdplaylist-media.mdproperty-management.mdscreenshots-overlays.mdstreaming.md

screenshots-overlays.mddocs/

0

# Screenshots and Overlays

1

2

Screenshot capture with multiple output formats and overlay system for displaying images and text on top of video content. Supports various image formats, positioning, and dynamic overlay management.

3

4

## Capabilities

5

6

### Screenshot Capture

7

8

Capture screenshots in various formats and configurations.

9

10

```python { .api }

11

def screenshot(self, includes: str = 'subtitles', mode: str = 'single'):

12

"""

13

Take a screenshot and save to default location.

14

15

Parameters:

16

- includes: What to include ('subtitles', 'video', 'window')

17

- mode: Screenshot mode ('single', 'each-frame')

18

'single': Take one screenshot

19

'each-frame': Screenshot every frame

20

"""

21

22

def screenshot_to_file(self, filename: str, includes: str = 'subtitles'):

23

"""

24

Take a screenshot and save to specific file.

25

26

Parameters:

27

- filename: Output filename (extension determines format)

28

- includes: What to include ('subtitles', 'video', 'window')

29

"""

30

31

def screenshot_raw(self, includes: str = 'subtitles'):

32

"""

33

Take a screenshot and return raw image data.

34

35

Parameters:

36

- includes: What to include ('subtitles', 'video', 'window')

37

38

Returns:

39

Dictionary with image data, width, height, stride, and format information

40

41

Note: Requires Pillow for image processing if includes != 'video'

42

"""

43

```

44

45

### Overlay Management

46

47

Create and manage image and text overlays on video content.

48

49

```python { .api }

50

def allocate_overlay_id(self) -> int:

51

"""

52

Allocate a unique overlay ID.

53

54

Returns:

55

Integer overlay ID for use with overlay functions

56

"""

57

58

def free_overlay_id(self, overlay_id: int):

59

"""

60

Free an allocated overlay ID.

61

62

Parameters:

63

- overlay_id: ID to free for reuse

64

"""

65

66

def remove_overlay(self, overlay_id: int):

67

"""

68

Remove an overlay by ID.

69

70

Parameters:

71

- overlay_id: ID of overlay to remove

72

"""

73

```

74

75

### Image Overlays

76

77

Display images on top of video content with positioning control.

78

79

```python { .api }

80

def create_image_overlay(self, img=None, pos=(0, 0)) -> 'ImageOverlay':

81

"""

82

Create an image overlay.

83

84

Parameters:

85

- img: PIL Image object or image data

86

- pos: (x, y) position tuple

87

88

Returns:

89

ImageOverlay object for managing the overlay

90

"""

91

92

def overlay_add(self, overlay_id: int, x: int, y: int, file_or_fd, offset: int, fmt: str, w: int, h: int, stride: int):

93

"""

94

Add a low-level overlay.

95

96

Parameters:

97

- overlay_id: Overlay identifier

98

- x, y: Position coordinates

99

- file_or_fd: File path or file descriptor

100

- offset: Byte offset in file

101

- fmt: Image format ('bgra', 'rgba', etc.)

102

- w, h: Image dimensions

103

- stride: Bytes per row

104

"""

105

106

def overlay_remove(self, overlay_id: int):

107

"""

108

Remove a low-level overlay.

109

110

Parameters:

111

- overlay_id: Overlay identifier to remove

112

"""

113

```

114

115

### File-Based Overlays

116

117

Display images from files with efficient file-based rendering.

118

119

```python { .api }

120

def create_file_overlay(self, filename: str = None, size: tuple = None, stride: int = None, pos: tuple = (0, 0)) -> 'FileOverlay':

121

"""

122

Create a file-based overlay.

123

124

Parameters:

125

- filename: Path to image file

126

- size: (width, height) tuple

127

- stride: Bytes per row (auto-calculated if not provided)

128

- pos: (x, y) position tuple

129

130

Returns:

131

FileOverlay object for managing the overlay

132

"""

133

```

134

135

### OSD Overlays

136

137

Display text and graphics using mpv's On-Screen Display system.

138

139

```python { .api }

140

def osd_overlay(self, overlay_id: int, data: str, res_x: int = 0, res_y: int = 720, z: int = 0, hidden: bool = False):

141

"""

142

Create an OSD overlay with ASS subtitle formatting.

143

144

Parameters:

145

- overlay_id: Overlay identifier

146

- data: ASS-formatted text/graphics data

147

- res_x: X resolution (0 for auto)

148

- res_y: Y resolution (720 default)

149

- z: Z-order (higher values on top)

150

- hidden: Whether overlay starts hidden

151

"""

152

153

def osd_overlay_remove(self, overlay_id: int):

154

"""

155

Remove an OSD overlay.

156

157

Parameters:

158

- overlay_id: Overlay identifier to remove

159

"""

160

```

161

162

## Overlay Classes

163

164

### ImageOverlay Class

165

166

```python { .api }

167

class ImageOverlay:

168

"""Manages image-based overlays with PIL integration."""

169

170

def __init__(self, m: 'MPV', overlay_id: int, img=None, pos: tuple = (0, 0)):

171

"""

172

Initialize image overlay.

173

174

Parameters:

175

- m: MPV instance

176

- overlay_id: Unique overlay identifier

177

- img: PIL Image object or None

178

- pos: (x, y) position tuple

179

"""

180

181

def update(self, img=None, pos: tuple = None):

182

"""

183

Update overlay image and/or position.

184

185

Parameters:

186

- img: New PIL Image object (None to keep current)

187

- pos: New (x, y) position (None to keep current)

188

"""

189

190

def remove(self):

191

"""Remove this overlay from the video."""

192

```

193

194

### FileOverlay Class

195

196

```python { .api }

197

class FileOverlay:

198

"""Manages file-based overlays for efficient image display."""

199

200

def __init__(self, m: 'MPV', overlay_id: int, filename: str = None, size: tuple = None, stride: int = None, pos: tuple = (0, 0)):

201

"""

202

Initialize file overlay.

203

204

Parameters:

205

- m: MPV instance

206

- overlay_id: Unique overlay identifier

207

- filename: Path to image file

208

- size: (width, height) image dimensions

209

- stride: Bytes per row

210

- pos: (x, y) position tuple

211

"""

212

213

def update(self, filename: str = None, size: tuple = None, stride: int = None, pos: tuple = None):

214

"""

215

Update overlay file and/or properties.

216

217

Parameters:

218

- filename: New image file path

219

- size: New (width, height) dimensions

220

- stride: New bytes per row

221

- pos: New (x, y) position

222

"""

223

224

def remove(self):

225

"""Remove this overlay from the video."""

226

```

227

228

## Usage Examples

229

230

### Basic Screenshots

231

232

```python

233

import mpv

234

235

player = mpv.MPV()

236

player.play('/path/to/video.mp4')

237

player.wait_until_playing()

238

239

# Take screenshot to default location

240

player.screenshot()

241

242

# Save to specific file

243

player.screenshot_to_file('/path/to/screenshot.png')

244

245

# Different screenshot modes

246

player.screenshot(includes='video') # Video only, no subtitles

247

player.screenshot(includes='window') # Entire window

248

player.screenshot(includes='subtitles') # Video with subtitles (default)

249

250

# Save in different formats

251

player.screenshot_to_file('capture.jpg') # JPEG format

252

player.screenshot_to_file('capture.png') # PNG format

253

player.screenshot_to_file('capture.webp') # WebP format

254

```

255

256

### Raw Screenshot Data

257

258

```python

259

# Get raw screenshot data for processing

260

screenshot_data = player.screenshot_raw()

261

262

print(f"Image size: {screenshot_data['width']}x{screenshot_data['height']}")

263

print(f"Format: {screenshot_data['format']}")

264

print(f"Stride: {screenshot_data['stride']}")

265

266

# Access raw pixel data

267

pixel_data = screenshot_data['data']

268

269

# Convert to PIL Image (if Pillow is available)

270

if 'pil_image' in screenshot_data:

271

pil_img = screenshot_data['pil_image']

272

pil_img.save('processed_screenshot.png')

273

274

# Apply image processing

275

from PIL import ImageEnhance

276

enhancer = ImageEnhance.Brightness(pil_img)

277

bright_img = enhancer.enhance(1.5)

278

bright_img.save('bright_screenshot.png')

279

```

280

281

### Image Overlays

282

283

```python

284

from PIL import Image

285

286

player = mpv.MPV()

287

player.play('/path/to/video.mp4')

288

289

# Create image overlay

290

logo = Image.open('/path/to/logo.png')

291

overlay = player.create_image_overlay(logo, pos=(50, 50))

292

293

# Update overlay position

294

overlay.update(pos=(100, 100))

295

296

# Update overlay image

297

new_logo = Image.open('/path/to/new_logo.png')

298

overlay.update(img=new_logo)

299

300

# Remove overlay

301

overlay.remove()

302

```

303

304

### File-Based Overlays

305

306

```python

307

# More efficient for static images

308

overlay = player.create_file_overlay(

309

filename='/path/to/watermark.png',

310

pos=(10, 10)

311

)

312

313

# Update file overlay

314

overlay.update(

315

filename='/path/to/different_watermark.png',

316

pos=(20, 20)

317

)

318

319

# Clean up

320

overlay.remove()

321

```

322

323

### OSD Text Overlays

324

325

```python

326

# Simple text overlay

327

overlay_id = player.allocate_overlay_id()

328

player.osd_overlay(

329

overlay_id,

330

"Hello World!",

331

res_y=720,

332

z=1

333

)

334

335

# Formatted text with ASS styling

336

ass_text = "{\\an7}{\\fs24}{\\c&H00FF00&}Green Text in Top-Left"

337

player.osd_overlay(overlay_id, ass_text)

338

339

# Complex OSD with positioning and styling

340

complex_osd = """

341

{\\an1}{\\pos(10,500)}{\\fs20}{\\c&HFFFFFF&}Title: {\\c&H00FFFF&}Video Name

342

{\\an1}{\\pos(10,530)}{\\fs16}{\\c&HCCCCCC&}Duration: 01:23:45

343

{\\an1}{\\pos(10,550)}{\\fs16}{\\c&HCCCCCC&}Quality: 1080p

344

"""

345

player.osd_overlay(overlay_id, complex_osd)

346

347

# Remove OSD overlay

348

player.osd_overlay_remove(overlay_id)

349

player.free_overlay_id(overlay_id)

350

```

351

352

### Dynamic Overlays

353

354

```python

355

import time

356

import threading

357

from PIL import Image, ImageDraw, ImageFont

358

359

class LiveOverlay:

360

def __init__(self, player):

361

self.player = player

362

self.overlay = None

363

self.running = False

364

365

def start_time_overlay(self):

366

"""Display current time as overlay."""

367

self.overlay = self.player.create_image_overlay(pos=(10, 10))

368

self.running = True

369

370

def update_time():

371

while self.running:

372

# Create time image

373

img = Image.new('RGBA', (200, 50), (0, 0, 0, 128))

374

draw = ImageDraw.Draw(img)

375

376

current_time = time.strftime('%H:%M:%S')

377

draw.text((10, 15), current_time, fill='white')

378

379

# Update overlay

380

self.overlay.update(img=img)

381

time.sleep(1)

382

383

self.thread = threading.Thread(target=update_time)

384

self.thread.start()

385

386

def stop(self):

387

self.running = False

388

if hasattr(self, 'thread'):

389

self.thread.join()

390

if self.overlay:

391

self.overlay.remove()

392

393

# Usage

394

player = mpv.MPV()

395

live_overlay = LiveOverlay(player)

396

397

player.play('/path/to/video.mp4')

398

live_overlay.start_time_overlay()

399

400

# Later...

401

live_overlay.stop()

402

```

403

404

### Multi-Layer Overlays

405

406

```python

407

# Create multiple overlays with different Z-orders

408

overlays = []

409

410

# Background overlay (lowest Z-order)

411

bg_overlay_id = player.allocate_overlay_id()

412

player.osd_overlay(bg_overlay_id,

413

"{\\pos(10,10)}{\\c&H000000&}{\\1a&H80&}Background",

414

z=0)

415

416

# Foreground overlay (higher Z-order)

417

fg_overlay_id = player.allocate_overlay_id()

418

player.osd_overlay(fg_overlay_id,

419

"{\\pos(15,15)}{\\c&HFFFFFF&}Foreground Text",

420

z=1)

421

422

# Image overlay (highest priority)

423

logo_overlay = player.create_image_overlay(

424

Image.open('/path/to/logo.png'),

425

pos=(200, 200)

426

)

427

428

overlays.extend([bg_overlay_id, fg_overlay_id, logo_overlay])

429

430

# Clean up all overlays

431

for overlay_id in [bg_overlay_id, fg_overlay_id]:

432

player.osd_overlay_remove(overlay_id)

433

player.free_overlay_id(overlay_id)

434

logo_overlay.remove()

435

```

436

437

### Screenshot-Based Processing

438

439

```python

440

# Automated screenshot processing

441

def process_screenshots():

442

player.play('/path/to/video.mp4')

443

player.wait_until_playing()

444

445

# Take screenshots at intervals

446

duration = player.duration

447

interval = 10 # Every 10 seconds

448

449

screenshots = []

450

for pos in range(0, int(duration), interval):

451

player.seek(pos, reference='absolute')

452

time.sleep(0.1) # Wait for seek

453

454

# Capture and process

455

data = player.screenshot_raw(includes='video')

456

if 'pil_image' in data:

457

img = data['pil_image']

458

# Apply processing

459

processed = img.resize((320, 240))

460

screenshots.append(processed)

461

462

# Create thumbnail montage

463

if screenshots:

464

montage_width = 5 * 320 # 5 thumbnails wide

465

montage_height = ((len(screenshots) + 4) // 5) * 240

466

montage = Image.new('RGB', (montage_width, montage_height))

467

468

for i, thumb in enumerate(screenshots):

469

x = (i % 5) * 320

470

y = (i // 5) * 240

471

montage.paste(thumb, (x, y))

472

473

montage.save('video_montage.png')

474

475

# Usage

476

process_screenshots()

477

```

478

479

### Interactive Overlay Controls

480

481

```python

482

class InteractiveOverlay:

483

def __init__(self, player):

484

self.player = player

485

self.overlay_id = player.allocate_overlay_id()

486

self.visible = True

487

488

def toggle_info_display(self):

489

"""Toggle information overlay."""

490

if self.visible:

491

self.hide_info()

492

else:

493

self.show_info()

494

495

def show_info(self):

496

"""Show current playback information."""

497

pos = self.player.time_pos or 0

498

duration = self.player.duration or 0

499

filename = self.player.filename or "Unknown"

500

501

info_text = f"""

502

{{\\an7}}{{\\pos(10,10)}}{{\\fs16}}{{\\c&HFFFFFF&}}

503

File: {{\\c&H00FFFF&}}{filename}

504

Time: {{\\c&H00FF00&}}{pos:.1f}s / {duration:.1f}s

505

Volume: {{\\c&HFF8000&}}{self.player.volume}%

506

"""

507

508

self.player.osd_overlay(self.overlay_id, info_text, z=10)

509

self.visible = True

510

511

def hide_info(self):

512

"""Hide information overlay."""

513

self.player.osd_overlay_remove(self.overlay_id)

514

self.visible = False

515

516

def cleanup(self):

517

"""Clean up overlay resources."""

518

if self.visible:

519

self.hide_info()

520

self.player.free_overlay_id(self.overlay_id)

521

522

# Bind to key press

523

interactive = InteractiveOverlay(player)

524

525

@player.key_binding('i')

526

def toggle_info():

527

interactive.toggle_info_display()

528

529

# Clean up when done

530

# interactive.cleanup()

531

```