diff --git a/arm/build/config/compiler/BUILD.gn b/arm/build/config/compiler/BUILD.gn
index 46c23485..c5fb826e 100644
--- a/arm/build/config/compiler/BUILD.gn
+++ b/arm/build/config/compiler/BUILD.gn
@@ -499,6 +499,12 @@ config("compiler") {
ldflags += [ "-fPIC" ]
rustflags += [ "-Crelocation-model=pic" ]
+ if (is_clang && chrome_pgo_phase == 2) {
+ asmflags += [ "-fbasic-block-sections=labels" ]
+ cflags += [ "-fbasic-block-sections=labels" ]
+ rustflags += [ "-Cllvm-args=-basic-block-sections=labels" ]
+ }
+
if (!is_clang) {
# Use pipes for communicating between sub-processes. Faster.
# (This flag doesn't do anything with Clang.)
diff --git a/arm/raspi/build/config/compiler/BUILD.gn b/arm/raspi/build/config/compiler/BUILD.gn
index 9de6e0d9..2632b00c 100644
--- a/arm/raspi/build/config/compiler/BUILD.gn
+++ b/arm/raspi/build/config/compiler/BUILD.gn
@@ -499,6 +499,12 @@ config("compiler") {
ldflags += [ "-fPIC" ]
rustflags += [ "-Crelocation-model=pic" ]
+ if (is_clang && chrome_pgo_phase == 2) {
+ asmflags += [ "-fbasic-block-sections=labels" ]
+ cflags += [ "-fbasic-block-sections=labels" ]
+ rustflags += [ "-Cllvm-args=-basic-block-sections=labels" ]
+ }
+
if (!is_clang) {
# Use pipes for communicating between sub-processes. Faster.
# (This flag doesn't do anything with Clang.)
diff --git a/infra/THORIUM_DEV_BOOKMARKS.html b/infra/THORIUM_DEV_BOOKMARKS.html
index 3004c158..51113a23 100644
--- a/infra/THORIUM_DEV_BOOKMARKS.html
+++ b/infra/THORIUM_DEV_BOOKMARKS.html
@@ -48,6 +48,7 @@
BUILD.gn - Chromium Code Search
media_switches.cc - Chromium Code Search
ffmpeg_video_decoder.cc - Chromium Code Search
+ ffmpeg_glue.cc - Chromium Code Search
gpu_video_decode_accelerator_factory.cc - Chromium Code Search
gpu_video_decode_accelerator.cc - Chromium Code Search
vaapi_video_decode_accelerator.cc - Chromium Code Search
diff --git a/other/AVX2/build/config/compiler/BUILD.gn b/other/AVX2/build/config/compiler/BUILD.gn
index bcd95ff8..06219318 100644
--- a/other/AVX2/build/config/compiler/BUILD.gn
+++ b/other/AVX2/build/config/compiler/BUILD.gn
@@ -499,6 +499,12 @@ config("compiler") {
ldflags += [ "-fPIC" ]
rustflags += [ "-Crelocation-model=pic" ]
+ if (is_clang && chrome_pgo_phase == 2) {
+ asmflags += [ "-fbasic-block-sections=labels" ]
+ cflags += [ "-fbasic-block-sections=labels" ]
+ rustflags += [ "-Cllvm-args=-basic-block-sections=labels" ]
+ }
+
if (!is_clang) {
# Use pipes for communicating between sub-processes. Faster.
# (This flag doesn't do anything with Clang.)
diff --git a/other/CrOS/build/config/compiler/BUILD.gn b/other/CrOS/build/config/compiler/BUILD.gn
index 8038e1ed..dd92a4f2 100644
--- a/other/CrOS/build/config/compiler/BUILD.gn
+++ b/other/CrOS/build/config/compiler/BUILD.gn
@@ -499,6 +499,12 @@ config("compiler") {
ldflags += [ "-fPIC" ]
rustflags += [ "-Crelocation-model=pic" ]
+ if (is_clang && chrome_pgo_phase == 2) {
+ asmflags += [ "-fbasic-block-sections=labels" ]
+ cflags += [ "-fbasic-block-sections=labels" ]
+ rustflags += [ "-Cllvm-args=-basic-block-sections=labels" ]
+ }
+
if (!is_clang) {
# Use pipes for communicating between sub-processes. Faster.
# (This flag doesn't do anything with Clang.)
diff --git a/other/SSE3/build/config/compiler/BUILD.gn b/other/SSE3/build/config/compiler/BUILD.gn
index 845d66c7..847d1bc3 100644
--- a/other/SSE3/build/config/compiler/BUILD.gn
+++ b/other/SSE3/build/config/compiler/BUILD.gn
@@ -499,6 +499,12 @@ config("compiler") {
ldflags += [ "-fPIC" ]
rustflags += [ "-Crelocation-model=pic" ]
+ if (is_clang && chrome_pgo_phase == 2) {
+ asmflags += [ "-fbasic-block-sections=labels" ]
+ cflags += [ "-fbasic-block-sections=labels" ]
+ rustflags += [ "-Cllvm-args=-basic-block-sections=labels" ]
+ }
+
if (!is_clang) {
# Use pipes for communicating between sub-processes. Faster.
# (This flag doesn't do anything with Clang.)
diff --git a/src/build/config/compiler/BUILD.gn b/src/build/config/compiler/BUILD.gn
index e42d2006..919054d9 100644
--- a/src/build/config/compiler/BUILD.gn
+++ b/src/build/config/compiler/BUILD.gn
@@ -499,6 +499,12 @@ config("compiler") {
ldflags += [ "-fPIC" ]
rustflags += [ "-Crelocation-model=pic" ]
+ if (is_clang && chrome_pgo_phase == 2) {
+ asmflags += [ "-fbasic-block-sections=labels" ]
+ cflags += [ "-fbasic-block-sections=labels" ]
+ rustflags += [ "-Cllvm-args=-basic-block-sections=labels" ]
+ }
+
if (!is_clang) {
# Use pipes for communicating between sub-processes. Faster.
# (This flag doesn't do anything with Clang.)
diff --git a/src/media/filters/ffmpeg_glue.cc b/src/media/filters/ffmpeg_glue.cc
new file mode 100644
index 00000000..9a56b4e1
--- /dev/null
+++ b/src/media/filters/ffmpeg_glue.cc
@@ -0,0 +1,187 @@
+// Copyright 2023 The Chromium Authors, Alex313031, and RobRich999
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/filters/ffmpeg_glue.h"
+
+#include "base/check_op.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/notreached.h"
+#include "base/types/cxx23_to_underlying.h"
+#include "media/base/container_names.h"
+#include "media/ffmpeg/ffmpeg_common.h"
+
+namespace media {
+
+// Internal buffer size used by AVIO for reading.
+// TODO(dalecurtis): Experiment with this buffer size and measure impact on
+// performance. Currently we want to use 32kb to preserve existing behavior
+// with the previous URLProtocol based approach.
+enum { kBufferSize = 32 * 1024 };
+
+static int AVIOReadOperation(void* opaque, uint8_t* buf, int buf_size) {
+ return reinterpret_cast(opaque)->Read(buf_size, buf);
+}
+
+static int64_t AVIOSeekOperation(void* opaque, int64_t offset, int whence) {
+ FFmpegURLProtocol* protocol = reinterpret_cast(opaque);
+ int64_t new_offset = AVERROR(EIO);
+ switch (whence) {
+ case SEEK_SET:
+ if (protocol->SetPosition(offset))
+ protocol->GetPosition(&new_offset);
+ break;
+
+ case SEEK_CUR:
+ int64_t pos;
+ if (!protocol->GetPosition(&pos))
+ break;
+ if (protocol->SetPosition(pos + offset))
+ protocol->GetPosition(&new_offset);
+ break;
+
+ case SEEK_END:
+ int64_t size;
+ if (!protocol->GetSize(&size))
+ break;
+ if (protocol->SetPosition(size + offset))
+ protocol->GetPosition(&new_offset);
+ break;
+
+ case AVSEEK_SIZE:
+ protocol->GetSize(&new_offset);
+ break;
+
+ default:
+ NOTREACHED();
+ }
+ return new_offset;
+}
+
+static void LogContainer(bool is_local_file,
+ container_names::MediaContainerName container) {
+ base::UmaHistogramSparse("Media.DetectedContainer",
+ base::to_underlying(container));
+ if (is_local_file) {
+ base::UmaHistogramSparse("Media.DetectedContainer.Local",
+ base::to_underlying(container));
+ }
+}
+
+FFmpegGlue::FFmpegGlue(FFmpegURLProtocol* protocol) {
+ // Initialize an AVIOContext using our custom read and seek operations. Don't
+ // keep pointers to the buffer since FFmpeg may reallocate it on the fly. It
+ // will be cleaned up
+ format_context_ = avformat_alloc_context();
+ avio_context_.reset(avio_alloc_context(
+ static_cast(av_malloc(kBufferSize)), kBufferSize, 0,
+ protocol, &AVIOReadOperation, nullptr, &AVIOSeekOperation));
+
+ // Ensure FFmpeg only tries to seek on resources we know to be seekable.
+ avio_context_->seekable =
+ protocol->IsStreaming() ? 0 : AVIO_SEEKABLE_NORMAL;
+
+ // Ensure writing is disabled.
+ avio_context_->write_flag = 0;
+
+ // Tell the format context about our custom IO context. avformat_open_input()
+ // will set the AVFMT_FLAG_CUSTOM_IO flag for us, but do so here to ensure an
+ // early error state doesn't cause FFmpeg to free our resources in error.
+ format_context_->flags |= AVFMT_FLAG_CUSTOM_IO;
+
+ // Enable fast, but inaccurate seeks for MP3.
+ format_context_->flags |= AVFMT_FLAG_FAST_SEEK;
+
+ // Ensures format parsing errors will bail out. From an audit on 11/2017, all
+ // instances were real failures. Solves bugs like http://crbug.com/710791.
+ format_context_->error_recognition |= AV_EF_EXPLODE;
+
+ format_context_->pb = avio_context_.get();
+}
+
+bool FFmpegGlue::OpenContext(bool is_local_file) {
+ DCHECK(!open_called_) << "OpenContext() shouldn't be called twice.";
+
+ // If avformat_open_input() is called we have to take a slightly different
+ // destruction path to avoid double frees.
+ open_called_ = true;
+
+ // By passing nullptr for the filename (second parameter) we are telling
+ // FFmpeg to use the AVIO context we setup from the AVFormatContext structure.
+ const int ret =
+ avformat_open_input(&format_context_, nullptr, nullptr, nullptr);
+
+ // If FFmpeg can't identify the file, read the first 8k and attempt to guess
+ // at the container type ourselves. This way we can track emergent formats.
+ // Only try on AVERROR_INVALIDDATA to avoid running after I/O errors.
+ if (ret == AVERROR_INVALIDDATA) {
+ std::vector buffer(8192);
+
+ const int64_t pos = AVIOSeekOperation(avio_context_->opaque, 0, SEEK_SET);
+ if (pos < 0)
+ return false;
+
+ const int num_read =
+ AVIOReadOperation(avio_context_->opaque, buffer.data(), buffer.size());
+ if (num_read < container_names::kMinimumContainerSize)
+ return false;
+
+ container_ = container_names::DetermineContainer(buffer.data(), num_read);
+ LogContainer(is_local_file, container_);
+
+ detected_hls_ =
+ container_ == container_names::MediaContainerName::kContainerHLS;
+ return false;
+ } else if (ret < 0) {
+ return false;
+ }
+
+ // Rely on ffmpeg's parsing if we're able to succesfully open the file.
+ if (strcmp(format_context_->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") == 0)
+ container_ = container_names::MediaContainerName::kContainerMOV;
+ else if (strcmp(format_context_->iformat->name, "flac") == 0)
+ container_ = container_names::MediaContainerName::kContainerFLAC;
+ else if (strcmp(format_context_->iformat->name, "matroska,webm") == 0)
+ container_ = container_names::MediaContainerName::kContainerWEBM;
+ else if (strcmp(format_context_->iformat->name, "ogg") == 0)
+ container_ = container_names::MediaContainerName::kContainerOgg;
+ else if (strcmp(format_context_->iformat->name, "wav") == 0)
+ container_ = container_names::MediaContainerName::kContainerWAV;
+ else if (strcmp(format_context_->iformat->name, "aac") == 0)
+ container_ = container_names::MediaContainerName::kContainerAAC;
+ else if (strcmp(format_context_->iformat->name, "mp3") == 0)
+ container_ = container_names::MediaContainerName::kContainerMP3;
+ else if (strcmp(format_context_->iformat->name, "amr") == 0)
+ container_ = container_names::MediaContainerName::kContainerAMR;
+ else if (strcmp(format_context_->iformat->name, "avi") == 0)
+ container_ = container_names::MediaContainerName::kContainerAVI;
+
+ // For a successfully opened file, we will get a container we've compiled in.
+ CHECK_NE(container_, container_names::MediaContainerName::kContainerUnknown);
+ LogContainer(is_local_file, container_);
+
+ return true;
+}
+
+FFmpegGlue::~FFmpegGlue() {
+ // In the event of avformat_open_input() failure, FFmpeg may sometimes free
+ // our AVFormatContext behind the scenes, but leave the buffer alive. It will
+ // helpfully set |format_context_| to nullptr in this case.
+ if (!format_context_) {
+ av_free(avio_context_->buffer);
+ return;
+ }
+
+ // If avformat_open_input() hasn't been called, we should simply free the
+ // AVFormatContext and buffer instead of using avformat_close_input().
+ if (!open_called_) {
+ avformat_free_context(format_context_);
+ av_free(avio_context_->buffer);
+ return;
+ }
+
+ avformat_close_input(&format_context_);
+ av_free(avio_context_->buffer);
+}
+
+} // namespace media
diff --git a/src/media/filters/ffmpeg_video_decoder.cc b/src/media/filters/ffmpeg_video_decoder.cc
index 89924776..5a7c876e 100644
--- a/src/media/filters/ffmpeg_video_decoder.cc
+++ b/src/media/filters/ffmpeg_video_decoder.cc
@@ -1,4 +1,4 @@
-// Copyright 2023 The Chromium Authors and Alex313031
+// Copyright 2023 The Chromium Authors, Alex313031, and RobRich999
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.