brave-browser: Playlist crashes when playing large/long-running videos when they're cached

Description

Playlist crashes when switching between large/long-running videos (cached and uncached)

Steps to Reproduce

  1. install 1.62.89
  2. launch Brave
  3. set brave://flags/#playlist to Enabled
  4. click Relaunch
  5. load a bunch of large/long-running vidoes (4+ hours or more, each, typically)
  6. queue at least one – if not 3 or 4 – for offline-media playback via the context-menu
  7. play any video
  8. now, switch between videos

NOTE: It appears to be the larger videos (which are slower to cache offline) which are still downloading that might be the problem, here - but I haven’t fully nailed it down

Actual result:

💥

playlist-crasher

Crash ID: 6c330f00-f35a-140b-0000-000000000000

[ 00 ] partition_alloc::internal::OnNoMemoryInternal(unsigned long) ( oom.cc:58 )
[ 01 ] partition_alloc::TerminateBecauseOutOfMemory(unsigned long) ( oom.cc:65 )
[ 02 ] partition_alloc::internal::OnNoMemory(unsigned long) ( oom.cc:75 )
[ 03 ] partition_alloc::internal::PartitionExcessiveAllocationSize(unsigned long) ( partition_oom.cc:19 )
[ 04 ] partition_alloc::internal::(anonymous namespace)::PartitionDirectMap(partition_alloc::PartitionRoot*, partition_alloc::internal::AllocFlags, unsigned long, unsigned long) ( partition_bucket.cc:228 )
[ 05 ] partition_alloc::internal::PartitionBucket::SlowPathAlloc(partition_alloc::PartitionRoot*, partition_alloc::internal::AllocFlags, unsigned long, unsigned long, bool*) ( partition_bucket.cc:1340 )
[ 06 ] void* partition_alloc::PartitionRoot::AllocInternalNoHooks<(partition_alloc::internal::AllocFlags)16>(unsigned long, unsigned long) ( partition_root.h:1191 )
[ 07 ] void* partition_alloc::PartitionRoot::AllocInternal<(partition_alloc::internal::AllocFlags)16>(unsigned long, unsigned long, char const*) ( partition_root.h:1953 )
[ 08 ] void* partition_alloc::PartitionRoot::AllocInline<(partition_alloc::internal::AllocFlags)16>(unsigned long, char const*) ( partition_root.h:467 )
[ 09 ] allocator_shim::internal::PartitionMalloc(allocator_shim::AllocatorDispatch const*, unsigned long, void*) ( allocator_shim_default_dispatch_to_partition_alloc.cc:240 )
[ 10 ] base::allocator::dispatcher::internal::DispatcherImpl<base::PoissonAllocationSampler>::AllocFn(allocator_shim::AllocatorDispatch const*, unsigned long, void*) ( dispatcher_internal.h:113 )
[ 11 ] ShimCppNew ( allocator_shim.cc:188 )
[ 12 ] operator new(unsigned long) ( allocator_shim_override_cpp_symbols.h:35 )
[ 13 ] std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>::append(unsigned long, char) ( new:272 )
[ 14 ] std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>::resize(unsigned long, char) ( string:3205 )
[ 15 ] std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>::resize(unsigned long) ( string:1177 )
[ 16 ] base::ReadStreamToStringWithMaxSize(__sFILE*, unsigned long, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>*)::$_0::operator()(unsigned long) const ( file_util.cc:315 )
[ 17 ] decltype(std::declval<base::ReadStreamToStringWithMaxSize(__sFILE*, unsigned long, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>*)::$_0 const&>()(std::declval<unsigned long>())) std::__Cr::__invoke<base::ReadStreamToStringWithMaxSize(__sFILE*, unsigned long, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>*)::$_0 const&, unsigned long>(base::ReadStreamToStringWithMaxSize(__sFILE*, unsigned long, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>*)::$_0 const&, unsigned long&&) ( invoke.h:344 )
[ 18 ] std::__Cr::invoke_result<base::ReadStreamToStringWithMaxSize(__sFILE*, unsigned long, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>*)::$_0 const&, unsigned long>::type std::__Cr::invoke<base::ReadStreamToStringWithMaxSize(__sFILE*, unsigned long, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>*)::$_0 const&, unsigned long>(base::ReadStreamToStringWithMaxSize(__sFILE*, unsigned long, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>*)::$_0 const&, unsigned long&&) ( invoke.h:30 )
[ 19 ] base::span<unsigned char, 18446744073709551615ul, unsigned char*> absl::functional_internal::InvokeObject<base::ReadStreamToStringWithMaxSize(__sFILE*, unsigned long, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>*)::$_0, base::span<unsigned char, 18446744073709551615ul, unsigned char*>, unsigned long>(absl::functional_internal::VoidPtr, absl::functional_internal::ForwardT<unsigned long>::type) ( function_ref.h:78 )
[ 20 ] absl::FunctionRef<base::span<unsigned char, 18446744073709551615ul, unsigned char*> (unsigned long)>::operator()(unsigned long) const ( function_ref.h:132 )
[ 21 ] base::FunctionRef<base::span<unsigned char, 18446744073709551615ul, unsigned char*> (unsigned long)>::operator()(unsigned long) const ( function_ref.h:90 )
[ 22 ] base::(anonymous namespace)::ReadStreamToSpanWithMaxSize(__sFILE*, unsigned long, base::FunctionRef<base::span<unsigned char, 18446744073709551615ul, unsigned char*> (unsigned long)>) ( file_util.cc:0 )
[ 23 ] base::ReadStreamToStringWithMaxSize(__sFILE*, unsigned long, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>*) ( file_util.cc:313 )
[ 24 ] base::ReadFileToStringWithMaxSize(base::FilePath const&, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>*, unsigned long) ( file_util.cc:362 )
[ 25 ] base::ReadFileToString(base::FilePath const&, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>*) ( file_util.cc:348 )
[ 26 ] playlist::(anonymous namespace)::ReadFileToString(base::FilePath const&) ( playlist_data_source.cc:32 )
[ 27 ] base::OnceCallback<scoped_refptr<base::RefCountedBytes> ()>::Run() && ( callback.h:154 )
[ 28 ] void base::internal::ReturnAsParamAdapter<scoped_refptr<base::RefCountedBytes>>(base::OnceCallback<scoped_refptr<base::RefCountedBytes> ()>, std::__Cr::unique_ptr<scoped_refptr<base::RefCountedBytes>, std::__Cr::default_delete<scoped_refptr<base::RefCountedBytes>>>*) ( post_task_and_reply_with_result_internal.h:23 )
[ 29 ] base::OnceCallback<void ()>::Run() && ( callback.h:154 )
[ 30 ] base::internal::PostTaskAndReplyRelay::RunTaskAndPostReply(base::internal::PostTaskAndReplyRelay) ( post_task_and_reply_impl.h:45 )
[ 31 ] void base::internal::FunctorTraits<void (*)(base::internal::PostTaskAndReplyRelay), void>::Invoke<void (*)(base::internal::PostTaskAndReplyRelay), base::internal::PostTaskAndReplyRelay>(void (*&&)(base::internal::PostTaskAndReplyRelay), base::internal::PostTaskAndReplyRelay&&) ( bind_internal.h:631 )
[ 32 ] void base::internal::InvokeHelper<false, void, 0ul>::MakeItSo<void (*)(base::internal::PostTaskAndReplyRelay), std::__Cr::tuple<base::internal::PostTaskAndReplyRelay>>(void (*&&)(base::internal::PostTaskAndReplyRelay), std::__Cr::tuple<base::internal::PostTaskAndReplyRelay>&&) ( bind_internal.h:868 )
[ 33 ] void base::internal::Invoker<base::internal::BindState<void (*)(base::internal::PostTaskAndReplyRelay), base::internal::PostTaskAndReplyRelay>, void ()>::RunImpl<void (*)(base::internal::PostTaskAndReplyRelay), std::__Cr::tuple<base::internal::PostTaskAndReplyRelay>, 0ul>(void (*&&)(base::internal::PostTaskAndReplyRelay), std::__Cr::tuple<base::internal::PostTaskAndReplyRelay>&&, std::__Cr::integer_sequence<unsigned long, 0ul>) ( bind_internal.h:968 )
[ 34 ] base::internal::Invoker<base::internal::BindState<void (*)(base::internal::PostTaskAndReplyRelay), base::internal::PostTaskAndReplyRelay>, void ()>::RunOnce(base::internal::BindStateBase*) ( bind_internal.h:919 )
[ 35 ] base::TaskAnnotator::RunTaskImpl(base::PendingTask&) ( callback.h:154 )
[ 36 ] void base::TaskAnnotator::RunTask<base::internal::TaskTracker::RunTaskImpl(base::internal::Task&, base::TaskTraits const&, base::internal::TaskSource*, base::SequenceToken const&)::$_0>(perfetto::StaticString, base::PendingTask&, base::internal::TaskTracker::RunTaskImpl(base::internal::Task&, base::TaskTraits const&, base::internal::TaskSource*, base::SequenceToken const&)::$_0&&) ( task_annotator.h:89 )
[ 37 ] base::internal::TaskTracker::RunTaskImpl(base::internal::Task&, base::TaskTraits const&, base::internal::TaskSource*, base::SequenceToken const&) ( task_tracker.cc:644 )
[ 38 ] base::internal::TaskTracker::RunSkipOnShutdown(base::internal::Task&, base::TaskTraits const&, base::internal::TaskSource*, base::SequenceToken const&) ( task_tracker.cc:629 )
[ 39 ] base::internal::WorkerThread::RunWorker() ( task_tracker.cc:659 )
[ 40 ] base::internal::WorkerThread::RunPooledWorker() ( worker_thread.cc:359 )
[ 41 ] base::internal::WorkerThread::ThreadMain() ( worker_thread.cc:339 )
[ 42 ] base::(anonymous namespace)::ThreadFunc(void*) ( platform_thread_posix.cc:101 )
[ 43 ] _pthread_start
[ 44 ] thread_start

Expected result:

No crash

Reproduces how often:

100% with: multiple large files, at least stored for offline, media playing, and switching betweeen them

Brave version (brave://version info)

Brave | 1.62.89 Chromium: 120.0.6099.35 (Official Build) nightly (x86_64)
-- | --
Revision | f68a18538c0af7dba0f91c6176be4c1eee17101c
OS | macOS Version 11.7.10 (Build 20G1427)

Version/Channel Information:

  • Can you reproduce this issue with the current release?
  • Can you reproduce this issue with the beta channel?
  • Can you reproduce this issue with the nightly channel?

Other Additional Information:

  • Does the issue resolve itself when disabling Brave Shields?
  • Does the issue resolve itself when disabling Brave Rewards?
  • Is the issue reproducible on the latest version of Chrome?

Miscellaneous Information:

/cc @sangwoo108 @rebron @brave/qa-team

About this issue

  • Original URL
  • State: closed
  • Created 7 months ago
  • Comments: 20 (3 by maintainers)

Most upvoted comments

Yay, I think we’re close to it. Succeeded in playing 24hr long video

image

Yes, that’s right.

That’s…pretty “reasonable.”

😆 - nice work as always!

Maybe loading url something like /Users/simon/Library/ApplicationSupport/BraveSoftware/Brave-Browser-Beta//Default/playlist/60A2BE63931C52698229F7F0C430D243/media_file.mp4 in omnibox will play it well?

it might not be allowed due to the CSP.

local file path instead of custom media path if it’s possible from untrusted webui?

Also this seems to be difficult without explicit user interaction via <input type=file for security/privacy reason.

So, not sure if it works, but I guess we should do something like from PlaylistDataSource

  1. chrome://playlist-data/{id}/media/ should return the size of chunks and media type
  2. `chrome://playlist-data/{id}/media/chunk/{number} should return the requested chunk.
  3. WebUI should get size of chunks first and iterate chunks to add buffers to the MediaSource.

Update:

It seems that Youtube videos(mp4) we caches are not in format that can be used for MediaSource. So I’m going to try gather chunks into byte array(not MediaSource’s source buffer), and set it to video tag’s src attribute.

Even if the byte array causes OOM, only renderer would crash. I think that’s better. But eventually, we’ll need to work on caching MediaSource object as is.

[35205:259:0220/185131.533058:ERROR:box_definitions.cc(2063)] Failure parsing MP4: Detected unfragmented MP4. Media Source Extensions require ISO BMFF moov to contain mvex to indicate that Movie Fragments are to be expected.

Just curious why we don’t play with local media file path and instead passing it via string? It’s bcause of chrome-untrusted://? NVM Data source should pass that file’s data 😃 As we’re using custom chrome-untrusted://playlist-data/... url for playlist data, we have its own data source.

I think it’s worth to investigate how file:// scheme load big size media file. Maybe loading url something like /Users/simon/Library/ApplicationSupport/BraveSoftware/Brave-Browser-Beta//Default/playlist/60A2BE63931C52698229F7F0C430D243/media_file.mp4 in omnibox will play it well?

Or how about trying local file path instead of custom media path if it’s possible from untrusted webui?