Skip to content

fix(android): read stream-only content URIs and copy content in safeFilePath, release 2.23.0 - #229

Merged
hm21 merged 2 commits into
stablefrom
claude/pro-video-editor-issue-221-f66f9c
Oct 3, 2026
Merged

hm21 merged 2 commits into
stablefrom
claude/pro-video-editor-issue-221-f66f9c

Conversation

@hm21

@hm21 hm21 commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Description

Follow-up to #227 (EditorVideo.content), covering the points still open from #221.

  • Stream-only providers: a provider that hands out a content URI as a pipe (some cloud and archive providers do) failed most calls with setDataSource failed: status = 0xFFFFFFEA, because MediaExtractor and MediaMetadataRetriever need random access. Before dispatching a call, the plugin now checks every content URI it has not seen yet on a background thread (StreamOnlySources). Only a source that is not a regular file is copied, once, into the cache. Every other content URI is still read in place. Calls keep their order while a check runs, so a cancel never overtakes the task it cancels.
  • EditorVideo.safeFilePath copies a content video into a temporary file on Android instead of throwing, the same way a network video is downloaded. The copy runs natively (copyContentToFile); no file data goes through the channel. Other platforms still throw an UnsupportedError. The plugin's own calls keep reading the URI in place through contentOrSafeFilePath.
  • Device tests: content_uri_test.dart now runs the whole suite against three sources: MediaStore, a seekable document provider, and a pipe. The pipe and the document provider are served by a new test provider in the example app (TestMediaProvider). The suite also gains a test for safeFilePath.

Related Issue: #221

Verification

  • Galaxy S26 (Android 16): content_uri_test.dart, 54/54 passing. Before the fix, 11 of the 18 pipe tests failed.
  • Real picker URIs, checked once by hand on the same device (not part of the suite, since it needs the system UI): a photo picker URI (content://media/picker/0/com.android.providers.media.photopicker/...) and a SAF document URI (content://com.android.externalstorage.documents/...). Metadata, thumbnails, audio extraction, waveform, a render with a dissolve and a reversed clip, a two-layer composition, split and audio merge all passed without warnings.
  • Regression on device: concurrency_test, thumbnail_stream_test and error_handling_test pass.
  • flutter analyze, flutter test (500) and the Android unit tests (271) pass.

Type of Change

  • ✨ New feature (non-breaking change which adds functionality)
  • 🛠️ Bug fix (non-breaking change which fixes an issue)
  • ❌ Breaking change (fix or feature that would cause existing functionality to change)
  • 🧹 Code refactor
  • ✅ Build configuration change
  • 📝 Documentation
  • 🗑️ Chore

hm21 added 2 commits October 3, 2026 10:46
…ilePath, release 2.23.0

A provider that hands out a content URI as a pipe (some cloud and archive
providers) failed most calls with "setDataSource failed", because
MediaExtractor and MediaMetadataRetriever need random access. The plugin
now checks every new content URI off the main thread before dispatching a
call and copies only such a stream-only source once into the cache; every
other content URI is still read in place.

EditorVideo.safeFilePath copies a content video into a temporary file on
Android instead of throwing, the same way a network video is downloaded.

The content URI device suite now runs against MediaStore, a seekable
document provider and a pipe, served by a test provider in the example app.
…cking other calls

- A copy of a stream-only source is kept while any call that reads it is in
  flight. Before, a render of five stream-only clips could delete one of its
  own copies and fail with "Failed to instantiate extractor".
- Only calls with the same task id or a source still to check wait for a
  check; other calls no longer wait behind a long copy.
- The check copies from the stream it opened instead of opening the source
  twice, and a failed check still answers the call.
- Stale copies are cleared off the main thread, calls still waiting when the
  engine detaches are dropped, and a stream-only source used on two layers is
  linked instead of copied again.
- safeFilePath docs: the copy is used for the video from then on.
@hm21
hm21 merged commit ae3d8fc into stable Oct 3, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant