ankidroid / ankidroid/Anki-Android

[BUG]: Video files in [sound:] tags don't load — file:// src blocked by cross-origin policy from http://127.0.0.1 base URL

Offen
#20,668 13 Kommentare 0 Reaktionen 1 zugewiesene Person Beansprucht von @Ayush-Patel-56 Auf GitHub ansehen
Can't reproduce
Vorherrschende Sprache
Kotlin
Sterne
11.8k
Forks
2.9k
Ø Merge
2 T. 3 Std.
Gemergte PRs (30 T.)
171

Beschreibung

### Checked for duplicates?

- This issue is not a duplicate

### Does it also happen in the desktop version?

- This bug does not occur in the latest version of Anki Desktop

### What are the steps to reproduce this bug?

1. Create a card with a video field using `[sound:video.mp4]` syntax
2. Card template example:
```
Front:

{{Snapshot}}

{{Video}}

Back:
{{FrontSide}}



{{Audio}}
```
Where the `Video` field contains `[sound:somefile.mp4]`
3. Open the reviewer to study the card

### Expected behaviour

The video plays automatically when the card loads, as it did in version 2.16.5.

### Actual behaviour

The `` element renders in the HTML but the source fails to load. A broken media icon is displayed with video controls stuck at 0:00. The video cannot be played even by tapping. Audio `[sound:*.mp3]` tags on the back of the card work correctly.

### Root cause

There are two independent problems that together prevent video playback:

**Problem 1: `file://` video source blocked by cross-origin policy**

In `SoundUtils.kt`, the `asHtmlVideo()` function generates an absolute `file:///` URI for the `` element's `src` attribute:

```kotlin
val path = Paths.get(mediaDir.absolutePath, filename).toString()
val uri = getFileUri(path)
// Produces: file:///storage/emulated/0/.../collection.media/video.mp4
```

Since 2.17, card HTML is loaded via `loadDataWithBaseURL(server.baseUrl(), ...)` where the base URL is `http://127.0.0.1:/`. Modern Android WebView blocks `file://` resources requested from an `http://` origin due to cross-origin security restrictions. Images and audio are unaffected because images use relative paths resolved through `ViewerResourceHandler.shouldInterceptRequest()`, and audio plays through the native Android `MediaPlayer` (bypassing the WebView entirely).

**Problem 2: `hasVideoThumbnail` misclassifies short video clips as audio**

Even after fixing the video source URL, `getTagType()` in `SoundUtils.kt` calls `isAudioFileInVideoContainer()` which uses `CompatHelper.compat.hasVideoThumbnail()` to determine if an mp4 file contains video. This check returns false for short video clips (e.g. 3-5 second anime dialogue clips), causing them to be classified as `Type.AUDIO`. They are then played through `SoundTagPlayer.playSound()` which uses `MediaPlayer` without a video surface — so only the audio track plays.

### History

- **2.16.5 and earlier**: Video worked. `[sound:*.mp4]` was detected as video and played through a dedicated `VideoPlayer` Activity with a native `VideoView` and `MediaPlayer.setDisplay()`. This was a fullscreen activity that overlaid the card viewer and finished on completion.
- **2.17**: Switched to `http://127.0.0.1` base URL for cards. Video playback was broken entirely (issue #14693).
- **2.18 (PR #15840)**: Attempted to fix video autoplay by rendering `` HTML elements in the WebView. The `file://` source URL is blocked by cross-origin policy on most devices. The old `VideoPlayer` Activity was removed.
- **2.18 through current (2.24.0alpha12)**: Video remains broken.

### Proposed solution: restore the native VideoPlayer Activity

The HTML `` element approach (PR #15840) is fundamentally incompatible with the `http://127.0.0.1` base URL architecture. The reliable fix is to restore the native `VideoPlayer` Activity from 2.16.5. This requires:

1. **`VideoPlayerActivity.kt`** — A fullscreen `Activity` with a `VideoView`. Uses `MediaPlayer.setDisplay(videoView.holder)` to render video frames and `MediaPlayer.setDataSource()` to play the file. Finishes on completion and calls a completion listener so the next sound/TTS in the queue can play.

2. **`video_player.xml`** — Layout with a centered `VideoView`.

3. **`AndroidManifest.xml`** — Register the new activity.

4. **`SoundTagPlayer.kt`** — Change `playVideo()` to launch `VideoPlayerActivity` with the media file path instead of evaluating JavaScript on a `` element.

5. **`SoundUtils.kt`** — Render video tags as audio play buttons (since the native player handles the visual display). Also fix `getTagType()` to always classify files with video extensions (mp4, webm, mpg, mpeg, mov, mkv) as `Type.VIDEO` without the unreliable `hasVideoThumbnail` check.

I have built and tested this approach on Android 13 with AnkiDroid 2.24.0alpha12 and it works — videos autoplay on card load with both visual and audio, replicating the 2.16.5 behaviour.

### Related issues

- #14693 — 2.17: videos no longer autoplay
- #15840 — feat: autoplay videos (the PR that introduced the HTML `` approach)
- #7760 — `file://` blocked by CORS policy in WebView (same underlying cross-origin issue)
- #16373 — Fetch API cannot load `file://` URL scheme (same underlying cross-origin issue)
- #16407 — Autoplay of videos sometimes causes card answer steps to skip

### Debug info

```
AnkiDroid Version = 2.24.0alpha12
Android Version = 13
```

### Research

- [x] I am reporting a bug specific to AnkiDroid (Android app)
- [x] I have checked the manual and the FAQ and could not find a solution to my issue
- [x] I have confirmed the issue is not resolved in the latest alpha release

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.