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
- Ngôn ngữ chính
- Kotlin
- Star
- 11.8k
- Fork
- 2.9k
- Merge trung bình
- 2 ngày 3 giờ
- Pull request đã merge (30 ngày)
- 171
Mô tả
### 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:
{{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
Hướng dẫn đóng góp
Đánh giá
Issue này chưa được đánh giá.