[go: nahoru, domu]

Replace DecodeStatus with Status in DecodeCB.

This is the first of several CLs to replace DecodeStatus with
media::Status.  This one adjusts DecodeCB to return a Status, and
alters the consumers to expect it.  It also adds the DecodeStatus
enum values to StatusCode, so that old code continues to work
without modification.  DecodeStatus is aliased to StatusCode.

DecodeCB implementations have been modified to check for "not
ok, not aborted" where they used to check for
`DecodeStatus::DECODE_ERROR`.  While `DECODE_ERROR` is still defined
in the enum, and decoders continue to return it, the consumers
should now work even if individual decoders start sending more
detailed status codes.  `DECODE_ERROR` will be removed once all the
decoders have been updated.

For tests, there is now a `IsDecodeErrorStatus()` matcher that does
the same thing.

Future CLs will update other uses of DecodeStatus to do it more
properly, and not rely on this somewhat hacky enum-merging.  It can
be done incrementally with these changes, which is the real goal.

Change-Id: I77dd3ee9e3be5b17ca070e602f2b173ba98d4694
Bug: 1129662
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2392950
Reviewed-by: Sergey Volk <servolk@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Bill Budge <bbudge@chromium.org>
Reviewed-by: Dan Sanders <sandersd@chromium.org>
Reviewed-by: Xiaohan Wang <xhwang@chromium.org>
Commit-Queue: Frank Liberato <liberato@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810257}
diff --git a/chromecast/media/cma/decoder/cast_audio_decoder.cc b/chromecast/media/cma/decoder/cast_audio_decoder.cc
index 92c04ee..8bbfc6c9 100644
--- a/chromecast/media/cma/decoder/cast_audio_decoder.cc
+++ b/chromecast/media/cma/decoder/cast_audio_decoder.cc
@@ -184,15 +184,15 @@
   }
 
   void OnDecodeStatus(base::TimeDelta buffer_timestamp,
-                      ::media::DecodeStatus status) {
+                      ::media::Status status) {
     DCHECK(pending_decode_callback_);
 
     Status result_status = kDecodeOk;
     scoped_refptr<media::DecoderBufferBase> decoded;
-    if (status == ::media::DecodeStatus::OK && !decoded_chunks_.empty()) {
+    if (status.is_ok() && !decoded_chunks_.empty()) {
       decoded = ConvertDecoded();
     } else {
-      if (status != ::media::DecodeStatus::OK)
+      if (!status.is_ok())
         result_status = kDecodeError;
       decoded = base::MakeRefCounted<media::DecoderBufferAdapter>(
           output_config_.id, base::MakeRefCounted<::media::DecoderBuffer>(0));
diff --git a/content/renderer/pepper/video_decoder_shim.cc b/content/renderer/pepper/video_decoder_shim.cc
index 7b43c76..3c3126d 100644
--- a/content/renderer/pepper/video_decoder_shim.cc
+++ b/content/renderer/pepper/video_decoder_shim.cc
@@ -120,7 +120,7 @@
  private:
   void OnInitDone(media::Status status);
   void DoDecode();
-  void OnDecodeComplete(media::DecodeStatus status);
+  void OnDecodeComplete(media::Status status);
   void OnOutputComplete(scoped_refptr<media::VideoFrame> frame);
   void OnResetComplete();
 
@@ -252,18 +252,17 @@
   pending_decodes_.pop();
 }
 
-void VideoDecoderShim::DecoderImpl::OnDecodeComplete(
-    media::DecodeStatus status) {
+void VideoDecoderShim::DecoderImpl::OnDecodeComplete(media::Status status) {
   DCHECK(awaiting_decoder_);
   awaiting_decoder_ = false;
 
   int32_t result;
-  switch (status) {
-    case media::DecodeStatus::OK:
-    case media::DecodeStatus::ABORTED:
+  switch (status.code()) {
+    case media::StatusCode::kOk:
+    case media::StatusCode::kAborted:
       result = PP_OK;
       break;
-    case media::DecodeStatus::DECODE_ERROR:
+    default:
       result = PP_ERROR_RESOURCE_FAILED;
       break;
   }
diff --git a/media/base/audio_decoder.h b/media/base/audio_decoder.h
index d9a458db4..7361e251 100644
--- a/media/base/audio_decoder.h
+++ b/media/base/audio_decoder.h
@@ -27,16 +27,20 @@
 
 class MEDIA_EXPORT AudioDecoder : public Decoder {
  public:
-  // Callback for AudioDecoder initialization.
+  // Callback for Decoder initialization.
   using InitCB = base::OnceCallback<void(Status)>;
 
   // Callback for AudioDecoder to return a decoded frame whenever it becomes
   // available. Only non-EOS frames should be returned via this callback.
   using OutputCB = base::RepeatingCallback<void(scoped_refptr<AudioBuffer>)>;
 
-  // Callback for Decode(). Called after the decoder has accepted corresponding
-  // DecoderBuffer, indicating that the pipeline can send next buffer to decode.
-  using DecodeCB = base::OnceCallback<void(DecodeStatus)>;
+  // Callback type for Decode(). Called after the decoder has completed decoding
+  // corresponding DecoderBuffer, indicating that it's ready to accept another
+  // buffer to decode.  |kOk| implies success, |kAborted| implies that the
+  // decode was aborted, which does not necessarily indicate an error.  For
+  // example, a Reset() can trigger this.  Any other status code indicates that
+  // the decoder encountered an error, and must be reset.
+  using DecodeCB = base::OnceCallback<void(Status)>;
 
   AudioDecoder();
 
diff --git a/media/base/decode_status.cc b/media/base/decode_status.cc
index de30ca7..af52c1b8d 100644
--- a/media/base/decode_status.cc
+++ b/media/base/decode_status.cc
@@ -7,6 +7,7 @@
 #include <ostream>
 
 #include "base/trace_event/trace_event.h"
+#include "media/base/status.h"
 
 namespace media {
 
@@ -18,17 +19,16 @@
       return "DecodeStatus::ABORTED";
     case DecodeStatus::DECODE_ERROR:
       return "DecodeStatus::DECODE_ERROR";
+    default:
+      // TODO(liberato): Temporary while converting to media::Status.  This
+      // fn should go away.
+      return "DecodeStatus::UNKNOWN_ERROR";
   }
 
   NOTREACHED();
   return "";
 }
 
-std::ostream& operator<<(std::ostream& os, const DecodeStatus& status) {
-  os << GetDecodeStatusString(status);
-  return os;
-}
-
 // static
 bool ScopedDecodeTrace::IsEnabled() {
   bool enable_decode_traces = false;
@@ -59,11 +59,11 @@
     EndTrace(DecodeStatus::ABORTED);
 }
 
-void ScopedDecodeTrace::EndTrace(DecodeStatus status) {
+void ScopedDecodeTrace::EndTrace(const Status& status) {
   DCHECK(!closed_);
   closed_ = true;
   TRACE_EVENT_ASYNC_END1("media", trace_name_, this, "status",
-                         GetDecodeStatusString(status));
+                         GetDecodeStatusString(status.code()));
 }
 
 }  // namespace media
diff --git a/media/base/decode_status.h b/media/base/decode_status.h
index 0271668..d17d8573 100644
--- a/media/base/decode_status.h
+++ b/media/base/decode_status.h
@@ -9,23 +9,18 @@
 
 #include "media/base/decoder_buffer.h"
 #include "media/base/media_export.h"
+#include "media/base/status_codes.h"
 
 namespace media {
 
-enum class DecodeStatus {
-  OK = 0,        // Everything went as planned.
-  ABORTED,       // Read aborted due to Reset() during pending read.
-  DECODE_ERROR,  // Decoder returned decode error. Note: Prefixed by DECODE_
-                 // since ERROR is a reserved name (special macro) on Windows.
-  DECODE_STATUS_MAX = DECODE_ERROR
-};
+class Status;
+
+// TODO(crbug.com/1129662): This is temporary, to allow DecodeStatus::OK to
+// work, while we replace DecodeStatus with actual status codes.
+using DecodeStatus = StatusCode;
 
 MEDIA_EXPORT const char* GetDecodeStatusString(DecodeStatus status);
 
-// Helper function so that DecodeStatus can be printed easily.
-MEDIA_EXPORT std::ostream& operator<<(std::ostream& os,
-                                      const DecodeStatus& status);
-
 // Helper class for ensuring that Decode() traces are properly unique and closed
 // if the Decode is aborted via a WeakPtr invalidation. We use the |this|
 // pointer of the ScopedDecodeTrace object itself as the id. Since the callback
@@ -45,7 +40,7 @@
   ~ScopedDecodeTrace();
 
   // Completes the Decode() trace with the given status.
-  void EndTrace(DecodeStatus status);
+  void EndTrace(const Status& status);
 
  private:
   const char* trace_name_;
diff --git a/media/base/decoder.h b/media/base/decoder.h
index 3c0d6c3..8ebec52 100644
--- a/media/base/decoder.h
+++ b/media/base/decoder.h
@@ -7,8 +7,10 @@
 
 #include <string>
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "media/base/media_export.h"
+#include "media/base/status.h"
 
 namespace media {
 
diff --git a/media/base/ipc/media_param_traits_macros.h b/media/base/ipc/media_param_traits_macros.h
index b81de0e..93799338 100644
--- a/media/base/ipc/media_param_traits_macros.h
+++ b/media/base/ipc/media_param_traits_macros.h
@@ -75,9 +75,6 @@
 
 IPC_ENUM_TRAITS_MAX_VALUE(media::ChannelLayout, media::CHANNEL_LAYOUT_MAX)
 
-IPC_ENUM_TRAITS_MAX_VALUE(media::DecodeStatus,
-                          media::DecodeStatus::DECODE_STATUS_MAX)
-
 IPC_ENUM_TRAITS_MAX_VALUE(media::Decryptor::Status,
                           media::Decryptor::Status::kStatusMax)
 
diff --git a/media/base/status_codes.h b/media/base/status_codes.h
index 24fc929..5c2b7fe 100644
--- a/media/base/status_codes.h
+++ b/media/base/status_codes.h
@@ -27,6 +27,9 @@
 enum class StatusCode : StatusCodeType {
   kOk = 0,
 
+  // General errors: 0x00
+  kAborted = 0x00000001,
+
   // Decoder Errors: 0x01
   kDecoderInitializeNeverCompleted = 0x00000101,
   kDecoderFailedDecode = 0x00000102,
@@ -44,6 +47,9 @@
   kInitializationUnspecifiedFailure = 0x0000010C,
   kDecoderVideoFrameConstructionFailed = 0x0000010D,
   kMakeContextCurrentFailed = 0x0000010E,
+  // This is a temporary error for use only by existing code during the
+  // DecodeStatus => Status conversion.
+  kDecodeErrorDoNotUse = 0x0000010F,
 
   // Windows Errors: 0x02
   kWindowsWrappedHresult = 0x00000201,
@@ -120,6 +126,19 @@
   kH264ParsingError = 0x00000801,
   kH264BufferTooSmall = 0x00000802,
 
+  // DecodeStatus temporary codes.  These names were chosen to match the
+  // DecodeStatus enum, so that un-converted code can DecodeStatus::OK/etc.
+  // Note that OK must result in Status::is_ok(), since converted code will
+  // check for it.  These will be removed when the conversion is complete.
+  //
+  // DO NOT ADD NEW USES OF OK/ABORTED/DECODE_ERROR.
+  OK = kOk,  // Everything went as planned.
+  // Read aborted due to Reset() during pending read.
+  ABORTED = kAborted,  // Read aborted due to Reset() during pending read.
+  // Decoder returned decode error. Note: Prefixed by DECODE_
+  // since ERROR is a reserved name (special macro) on Windows.
+  DECODE_ERROR = kDecodeErrorDoNotUse,
+
   // Special codes
   kGenericErrorPleaseRemove = 0x79999999,
   kCodeOnlyForTesting = std::numeric_limits<StatusCodeType>::max(),
diff --git a/media/base/test_helpers.h b/media/base/test_helpers.h
index cdb6352..3a0df8e 100644
--- a/media/base/test_helpers.h
+++ b/media/base/test_helpers.h
@@ -224,7 +224,7 @@
   return arg.code() == status.code();
 }
 
-// Compares two an |arg| Status to a StatusCode provided
+// Compares an `arg` Status.code() to a test-supplied StatusCode.
 MATCHER_P(HasStatusCode, status_code, "") {
   return arg.code() == status_code;
 }
@@ -233,6 +233,12 @@
   return arg.is_ok();
 }
 
+// True if and only if the Status would be interpreted as an error from a decode
+// callback (not okay, not aborted).
+MATCHER(IsDecodeErrorStatus, "") {
+  return !arg.is_ok() && arg.code() != StatusCode::kAborted;
+}
+
 // Compares two {Audio|Video}DecoderConfigs
 MATCHER_P(DecoderConfigEq, config, "") {
   return arg.Matches(config);
diff --git a/media/base/video_decoder.h b/media/base/video_decoder.h
index 145ee96d..b66186c62 100644
--- a/media/base/video_decoder.h
+++ b/media/base/video_decoder.h
@@ -7,14 +7,12 @@
 
 #include <string>
 
-#include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "media/base/decode_status.h"
 #include "media/base/decoder.h"
 #include "media/base/media_export.h"
 #include "media/base/pipeline_status.h"
-#include "media/base/status.h"
 #include "media/base/waiting.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -27,8 +25,8 @@
 
 class MEDIA_EXPORT VideoDecoder : public Decoder {
  public:
-  // Callback for VideoDecoder initialization.
-  using InitCB = base::OnceCallback<void(Status status)>;
+  // Callback for Decoder initialization.
+  using InitCB = base::OnceCallback<void(Status)>;
 
   // Callback for VideoDecoder to return a decoded frame whenever it becomes
   // available. Only non-EOS frames should be returned via this callback.
@@ -36,8 +34,11 @@
 
   // Callback type for Decode(). Called after the decoder has completed decoding
   // corresponding DecoderBuffer, indicating that it's ready to accept another
-  // buffer to decode.
-  using DecodeCB = base::OnceCallback<void(DecodeStatus)>;
+  // buffer to decode.  |kOk| implies success, |kAborted| implies that the
+  // decode was aborted, which does not necessarily indicate an error.  For
+  // example, a Reset() can trigger this.  Any other status code indicates that
+  // the decoder encountered an error, and must be reset.
+  using DecodeCB = base::OnceCallback<void(Status)>;
 
   VideoDecoder();
   ~VideoDecoder() override;
diff --git a/media/base/video_thumbnail_decoder.cc b/media/base/video_thumbnail_decoder.cc
index 130813a..e1ba856 100644
--- a/media/base/video_thumbnail_decoder.cc
+++ b/media/base/video_thumbnail_decoder.cc
@@ -50,8 +50,8 @@
                                   weak_factory_.GetWeakPtr()));
 }
 
-void VideoThumbnailDecoder::OnVideoBufferDecoded(DecodeStatus status) {
-  if (status != DecodeStatus::OK) {
+void VideoThumbnailDecoder::OnVideoBufferDecoded(Status status) {
+  if (!status.is_ok()) {
     NotifyComplete(nullptr);
     return;
   }
@@ -62,8 +62,8 @@
                                   weak_factory_.GetWeakPtr()));
 }
 
-void VideoThumbnailDecoder::OnEosBufferDecoded(DecodeStatus status) {
-  if (status != DecodeStatus::OK)
+void VideoThumbnailDecoder::OnEosBufferDecoded(Status status) {
+  if (!status.is_ok())
     NotifyComplete(nullptr);
 }
 
diff --git a/media/base/video_thumbnail_decoder.h b/media/base/video_thumbnail_decoder.h
index 69f0c4f..409ec23 100644
--- a/media/base/video_thumbnail_decoder.h
+++ b/media/base/video_thumbnail_decoder.h
@@ -39,8 +39,8 @@
 
  private:
   void OnVideoDecoderInitialized(Status status);
-  void OnVideoBufferDecoded(DecodeStatus status);
-  void OnEosBufferDecoded(DecodeStatus status);
+  void OnVideoBufferDecoded(Status status);
+  void OnEosBufferDecoded(Status status);
 
   // Called when the output frame is generated.
   void OnVideoFrameDecoded(scoped_refptr<VideoFrame> frame);
diff --git a/media/cast/sender/h264_vt_encoder_unittest.cc b/media/cast/sender/h264_vt_encoder_unittest.cc
index 769d8ba..e91ef8f3 100644
--- a/media/cast/sender/h264_vt_encoder_unittest.cc
+++ b/media/cast/sender/h264_vt_encoder_unittest.cc
@@ -157,7 +157,7 @@
     ++count_frames_checked_;
   }
 
-  void DecodeDone(DecodeStatus status) { EXPECT_EQ(DecodeStatus::OK, status); }
+  void DecodeDone(Status status) { EXPECT_TRUE(status.is_ok()); }
 
   int count_frames_checked() const { return count_frames_checked_; }
 
diff --git a/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc b/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc
index c52f6c4..fd52b40 100644
--- a/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc
+++ b/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc
@@ -233,11 +233,12 @@
     auto decode_status = last_decode_status_.value();
     last_decode_status_.reset();
 
-    if (decode_status == DecodeStatus::DECODE_ERROR)
-      return cdm::kDecodeError;
+    // "kAborted" shouldn't happen during a sync decode, so treat it as an
+    // error.
+    DCHECK_NE(decode_status.code(), StatusCode::kAborted);
 
-    // "ABORTED" shouldn't happen during a sync decode, so treat it as an error.
-    DCHECK_EQ(decode_status, DecodeStatus::OK);
+    if (!decode_status.is_ok())
+      return cdm::kDecodeError;
 
     if (decoded_video_frames_.empty())
       return cdm::kNeedMoreData;
@@ -272,9 +273,9 @@
     std::move(quit_closure).Run();
   }
 
-  void OnDecoded(base::OnceClosure quit_closure, DecodeStatus decode_status) {
+  void OnDecoded(base::OnceClosure quit_closure, Status decode_status) {
     DCHECK(!last_decode_status_.has_value());
-    last_decode_status_ = decode_status;
+    last_decode_status_ = std::move(decode_status);
     std::move(quit_closure).Run();
   }
 
@@ -284,7 +285,7 @@
   // Results of |video_decoder_| operations. Set iff the callback of the
   // operation has been called.
   base::Optional<Status> last_init_result_;
-  base::Optional<DecodeStatus> last_decode_status_;
+  base::Optional<Status> last_decode_status_;
 
   // Queue of decoded video frames.
   using VideoFrameQueue = base::queue<scoped_refptr<VideoFrame>>;
diff --git a/media/filters/audio_decoder_unittest.cc b/media/filters/audio_decoder_unittest.cc
index d46d4c6..72f5e2a 100644
--- a/media/filters/audio_decoder_unittest.cc
+++ b/media/filters/audio_decoder_unittest.cc
@@ -301,11 +301,11 @@
     decoded_audio_.push_back(std::move(buffer));
   }
 
-  void DecodeFinished(const base::Closure& quit_closure, DecodeStatus status) {
+  void DecodeFinished(const base::Closure& quit_closure, Status status) {
     EXPECT_TRUE(pending_decode_);
     EXPECT_FALSE(pending_reset_);
     pending_decode_ = false;
-    last_decode_status_ = status;
+    last_decode_status_ = std::move(status);
     quit_closure.Run();
   }
 
@@ -389,7 +389,7 @@
   const scoped_refptr<AudioBuffer>& decoded_audio(size_t i) {
     return decoded_audio_[i];
   }
-  DecodeStatus last_decode_status() const { return last_decode_status_; }
+  const Status& last_decode_status() const { return last_decode_status_; }
 
  private:
   const AudioDecoderType decoder_type_;
@@ -409,7 +409,7 @@
   std::unique_ptr<AudioDecoder> decoder_;
   bool pending_decode_;
   bool pending_reset_;
-  DecodeStatus last_decode_status_;
+  Status last_decode_status_;
 
   base::circular_deque<scoped_refptr<AudioBuffer>> decoded_audio_;
   base::TimeDelta start_timestamp_;
@@ -599,7 +599,7 @@
     // (i.e. decoding EOS).
     do {
       ASSERT_NO_FATAL_FAILURE(Decode());
-      ASSERT_EQ(last_decode_status(), DecodeStatus::OK);
+      ASSERT_TRUE(last_decode_status().is_ok());
     } while (decoded_audio_size() < kDecodeRuns);
 
     // With MediaCodecAudioDecoder the output buffers might appear after
@@ -631,7 +631,7 @@
   SKIP_TEST_IF_NOT_SUPPORTED();
   ASSERT_NO_FATAL_FAILURE(Initialize());
   Decode();
-  EXPECT_EQ(DecodeStatus::OK, last_decode_status());
+  EXPECT_TRUE(last_decode_status().is_ok());
 }
 
 TEST_P(AudioDecoderTest, Reset) {
@@ -646,7 +646,7 @@
   scoped_refptr<DecoderBuffer> buffer(new DecoderBuffer(0));
   buffer->set_timestamp(kNoTimestamp);
   DecodeBuffer(std::move(buffer));
-  EXPECT_EQ(DecodeStatus::DECODE_ERROR, last_decode_status());
+  EXPECT_THAT(last_decode_status(), IsDecodeErrorStatus());
 }
 
 INSTANTIATE_TEST_SUITE_P(FFmpeg,
diff --git a/media/filters/dav1d_video_decoder_unittest.cc b/media/filters/dav1d_video_decoder_unittest.cc
index 69640df..93b53b7 100644
--- a/media/filters/dav1d_video_decoder_unittest.cc
+++ b/media/filters/dav1d_video_decoder_unittest.cc
@@ -85,15 +85,14 @@
   // Sets up expectations and actions to put Dav1dVideoDecoder in an active
   // decoding state.
   void ExpectDecodingState() {
-    EXPECT_EQ(DecodeStatus::OK, DecodeSingleFrame(i_frame_buffer_));
+    EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
     ASSERT_EQ(1U, output_frames_.size());
   }
 
   // Sets up expectations and actions to put Dav1dVideoDecoder in an end
   // of stream state.
   void ExpectEndOfStreamState() {
-    EXPECT_EQ(DecodeStatus::OK,
-              DecodeSingleFrame(DecoderBuffer::CreateEOSBuffer()));
+    EXPECT_TRUE(DecodeSingleFrame(DecoderBuffer::CreateEOSBuffer()).is_ok());
     ASSERT_FALSE(output_frames_.empty());
   }
 
@@ -103,26 +102,26 @@
   // Decodes all buffers in |input_buffers| and push all successfully decoded
   // output frames into |output_frames|. Returns the last decode status returned
   // by the decoder.
-  DecodeStatus DecodeMultipleFrames(const InputBuffers& input_buffers) {
+  Status DecodeMultipleFrames(const InputBuffers& input_buffers) {
     for (auto iter = input_buffers.begin(); iter != input_buffers.end();
          ++iter) {
-      DecodeStatus status = Decode(*iter);
-      switch (status) {
-        case DecodeStatus::OK:
+      Status status = Decode(*iter);
+      switch (status.code()) {
+        case StatusCode::kOk:
           break;
-        case DecodeStatus::ABORTED:
+        case StatusCode::kAborted:
           NOTREACHED();
           FALLTHROUGH;
-        case DecodeStatus::DECODE_ERROR:
+        default:
           DCHECK(output_frames_.empty());
           return status;
       }
     }
-    return DecodeStatus::OK;
+    return StatusCode::kOk;
   }
 
   // Decodes the single compressed frame in |buffer|.
-  DecodeStatus DecodeSingleFrame(scoped_refptr<DecoderBuffer> buffer) {
+  Status DecodeSingleFrame(scoped_refptr<DecoderBuffer> buffer) {
     InputBuffers input_buffers;
     input_buffers.push_back(std::move(buffer));
     return DecodeMultipleFrames(input_buffers);
@@ -141,9 +140,9 @@
     input_buffers.push_back(buffer);
     input_buffers.push_back(DecoderBuffer::CreateEOSBuffer());
 
-    DecodeStatus status = DecodeMultipleFrames(input_buffers);
+    Status status = DecodeMultipleFrames(input_buffers);
 
-    EXPECT_EQ(DecodeStatus::OK, status);
+    EXPECT_TRUE(status.is_ok());
     ASSERT_EQ(2U, output_frames_.size());
 
     gfx::Size original_size = TestVideoConfig::NormalCodedSize();
@@ -157,8 +156,8 @@
               output_frames_[1]->visible_rect().size().height());
   }
 
-  DecodeStatus Decode(scoped_refptr<DecoderBuffer> buffer) {
-    DecodeStatus status;
+  Status Decode(scoped_refptr<DecoderBuffer> buffer) {
+    Status status;
     EXPECT_CALL(*this, DecodeDone(_)).WillOnce(testing::SaveArg<0>(&status));
 
     decoder_->Decode(std::move(buffer),
@@ -183,7 +182,7 @@
     return base::MD5DigestToBase16(digest);
   }
 
-  MOCK_METHOD1(DecodeDone, void(DecodeStatus));
+  MOCK_METHOD1(DecodeDone, void(Status));
 
   testing::StrictMock<MockMediaLog> media_log_;
 
@@ -223,7 +222,7 @@
   Initialize();
 
   // Simulate decoding a single frame.
-  EXPECT_EQ(DecodeStatus::OK, DecodeSingleFrame(i_frame_buffer_));
+  EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
   ASSERT_EQ(1U, output_frames_.size());
 
   const auto& frame = output_frames_.front();
@@ -233,8 +232,9 @@
 
 TEST_F(Dav1dVideoDecoderTest, DecodeFrame_8bitMono) {
   Initialize();
-  EXPECT_EQ(DecodeStatus::OK, DecodeSingleFrame(ReadTestDataFile(
-                                  "av1-monochrome-I-frame-320x240-8bpp")));
+  EXPECT_TRUE(
+      DecodeSingleFrame(ReadTestDataFile("av1-monochrome-I-frame-320x240-8bpp"))
+          .is_ok());
   ASSERT_EQ(1U, output_frames_.size());
 
   const auto& frame = output_frames_.front();
@@ -245,8 +245,9 @@
 
 TEST_F(Dav1dVideoDecoderTest, DecodeFrame_10bitMono) {
   Initialize();
-  EXPECT_EQ(DecodeStatus::OK, DecodeSingleFrame(ReadTestDataFile(
-                                  "av1-monochrome-I-frame-320x240-10bpp")));
+  EXPECT_TRUE(DecodeSingleFrame(
+                  ReadTestDataFile("av1-monochrome-I-frame-320x240-10bpp"))
+                  .is_ok());
   ASSERT_EQ(1U, output_frames_.size());
 
   const auto& frame = output_frames_.front();
@@ -257,8 +258,9 @@
 
 TEST_F(Dav1dVideoDecoderTest, DecodeFrame_12bitMono) {
   Initialize();
-  EXPECT_EQ(DecodeStatus::OK, DecodeSingleFrame(ReadTestDataFile(
-                                  "av1-monochrome-I-frame-320x240-12bpp")));
+  EXPECT_TRUE(DecodeSingleFrame(
+                  ReadTestDataFile("av1-monochrome-I-frame-320x240-12bpp"))
+                  .is_ok());
   ASSERT_EQ(1U, output_frames_.size());
 
   const auto& frame = output_frames_.front();
diff --git a/media/filters/decoder_stream.cc b/media/filters/decoder_stream.cc
index 0c3e5cf..f1f45c9 100644
--- a/media/filters/decoder_stream.cc
+++ b/media/filters/decoder_stream.cc
@@ -520,8 +520,8 @@
     int buffer_size,
     bool end_of_stream,
     std::unique_ptr<ScopedDecodeTrace> trace_event,
-    DecodeStatus status) {
-  FUNCTION_DVLOG(3) << ": " << status;
+    Status status) {
+  FUNCTION_DVLOG(status.is_ok() ? 3 : 1) << ": " << status.code();
   DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER ||
          state_ == STATE_ERROR)
       << state_;
@@ -534,7 +534,7 @@
   if (end_of_stream) {
     DCHECK(!pending_decode_requests_);
     decoding_eos_ = false;
-    if (status == DecodeStatus::OK) {
+    if (status.is_ok()) {
       // Even if no frames were decoded, completing a flush counts as
       // successfully selecting a decoder. This allows back-to-back config
       // changes to select from all decoders.
@@ -552,8 +552,37 @@
   if (reset_cb_)
     return;
 
-  switch (status) {
-    case DecodeStatus::DECODE_ERROR:
+  switch (status.code()) {
+    case StatusCode::kAborted:
+      // Decoder can return kAborted during Reset() or during
+      // destruction.
+      return;
+
+    case StatusCode::kOk:
+      // Any successful decode counts!
+      if (buffer_size > 0)
+        traits_->ReportStatistics(statistics_cb_, buffer_size);
+
+      if (state_ == STATE_NORMAL) {
+        if (end_of_stream) {
+          state_ = STATE_END_OF_STREAM;
+          if (ready_outputs_.empty() && unprepared_outputs_.empty() && read_cb_)
+            SatisfyRead(OK, StreamTraits::CreateEOSOutput());
+          return;
+        }
+
+        if (CanDecodeMore())
+          ReadFromDemuxerStream();
+        return;
+      }
+
+      if (state_ == STATE_FLUSHING_DECODER && !pending_decode_requests_)
+        ReinitializeDecoder();
+      return;
+
+    default:
+      // TODO(liberato): Use |status| better, since it might not be a generic
+      // error anymore.
       if (!decoder_produced_a_frame_ &&
           base::FeatureList::IsEnabled(kFallbackAfterDecodeError)) {
         pending_decode_requests_ = 0;
@@ -579,33 +608,6 @@
           SatisfyRead(DECODE_ERROR, nullptr);
       }
       return;
-
-    case DecodeStatus::ABORTED:
-      // Decoder can return DecodeStatus::ABORTED during Reset() or during
-      // destruction.
-      return;
-
-    case DecodeStatus::OK:
-      // Any successful decode counts!
-      if (buffer_size > 0)
-        traits_->ReportStatistics(statistics_cb_, buffer_size);
-
-      if (state_ == STATE_NORMAL) {
-        if (end_of_stream) {
-          state_ = STATE_END_OF_STREAM;
-          if (ready_outputs_.empty() && unprepared_outputs_.empty() && read_cb_)
-            SatisfyRead(OK, StreamTraits::CreateEOSOutput());
-          return;
-        }
-
-        if (CanDecodeMore())
-          ReadFromDemuxerStream();
-        return;
-      }
-
-      if (state_ == STATE_FLUSHING_DECODER && !pending_decode_requests_)
-        ReinitializeDecoder();
-      return;
   }
 }
 
diff --git a/media/filters/decoder_stream.h b/media/filters/decoder_stream.h
index b130828..cbea02b 100644
--- a/media/filters/decoder_stream.h
+++ b/media/filters/decoder_stream.h
@@ -203,7 +203,7 @@
   void OnDecodeDone(int buffer_size,
                     bool end_of_stream,
                     std::unique_ptr<ScopedDecodeTrace> trace_event,
-                    DecodeStatus status);
+                    media::Status status);
 
   // Output callback passed to Decoder::Initialize().
   void OnDecodeOutputReady(scoped_refptr<Output> output);
diff --git a/media/filters/decrypting_audio_decoder_unittest.cc b/media/filters/decrypting_audio_decoder_unittest.cc
index 25717ca..7772462 100644
--- a/media/filters/decrypting_audio_decoder_unittest.cc
+++ b/media/filters/decrypting_audio_decoder_unittest.cc
@@ -136,9 +136,8 @@
   }
 
   // Decode |buffer| and expect DecodeDone to get called with |status|.
-  void DecodeAndExpect(scoped_refptr<DecoderBuffer> buffer,
-                       DecodeStatus status) {
-    EXPECT_CALL(*this, DecodeDone(status));
+  void DecodeAndExpect(scoped_refptr<DecoderBuffer> buffer, StatusCode status) {
+    EXPECT_CALL(*this, DecodeDone(HasStatusCode(status)));
     decoder_->Decode(buffer, base::Bind(&DecryptingAudioDecoderTest::DecodeDone,
                                         base::Unretained(this)));
     base::RunLoop().RunUntilIdle();
@@ -247,7 +246,7 @@
   }
 
   MOCK_METHOD1(FrameReady, void(scoped_refptr<AudioBuffer>));
-  MOCK_METHOD1(DecodeDone, void(DecodeStatus));
+  MOCK_METHOD1(DecodeDone, void(Status));
 
   MOCK_METHOD1(OnWaiting, void(WaitingReason));
 
@@ -414,7 +413,7 @@
   EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
       .WillRepeatedly(RunCallback<1>(Decryptor::kSuccess, decoded_frame_list_));
   EXPECT_CALL(*this, FrameReady(decoded_frame_));
-  EXPECT_CALL(*this, DecodeDone(DecodeStatus::OK));
+  EXPECT_CALL(*this, DecodeDone(IsOkStatus()));
   event_cb_.Run(CdmContext::Event::kHasAdditionalUsableKey);
   base::RunLoop().RunUntilIdle();
 }
@@ -428,7 +427,7 @@
   EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
       .WillRepeatedly(RunCallback<1>(Decryptor::kSuccess, decoded_frame_list_));
   EXPECT_CALL(*this, FrameReady(decoded_frame_));
-  EXPECT_CALL(*this, DecodeDone(DecodeStatus::OK));
+  EXPECT_CALL(*this, DecodeDone(IsOkStatus()));
   // The audio decode callback is returned after the correct decryption key is
   // added.
   event_cb_.Run(CdmContext::Event::kHasAdditionalUsableKey);
@@ -457,7 +456,7 @@
   Initialize();
   EnterPendingDecodeState();
 
-  EXPECT_CALL(*this, DecodeDone(DecodeStatus::ABORTED));
+  EXPECT_CALL(*this, DecodeDone(HasStatusCode(StatusCode::kAborted)));
 
   Reset();
 }
@@ -467,7 +466,7 @@
   Initialize();
   EnterWaitingForKeyState();
 
-  EXPECT_CALL(*this, DecodeDone(DecodeStatus::ABORTED));
+  EXPECT_CALL(*this, DecodeDone(HasStatusCode(StatusCode::kAborted)));
 
   Reset();
 }
diff --git a/media/filters/decrypting_video_decoder_unittest.cc b/media/filters/decrypting_video_decoder_unittest.cc
index 47c9f3d..caa4221 100644
--- a/media/filters/decrypting_video_decoder_unittest.cc
+++ b/media/filters/decrypting_video_decoder_unittest.cc
@@ -114,9 +114,17 @@
   }
 
   // Decode |buffer| and expect DecodeDone to get called with |status|.
-  void DecodeAndExpect(scoped_refptr<DecoderBuffer> buffer,
-                       DecodeStatus status) {
-    EXPECT_CALL(*this, DecodeDone(status));
+  void DecodeAndExpect(scoped_refptr<DecoderBuffer> buffer, StatusCode status) {
+    EXPECT_CALL(*this, DecodeDone(HasStatusCode(status)));
+    decoder_->Decode(buffer,
+                     base::BindOnce(&DecryptingVideoDecoderTest::DecodeDone,
+                                    base::Unretained(this)));
+    base::RunLoop().RunUntilIdle();
+  }
+
+  // Decode |buffer| and expect DecodeDone to get called with an error.
+  void DecodeAndExpectError(scoped_refptr<DecoderBuffer> buffer) {
+    EXPECT_CALL(*this, DecodeDone(IsDecodeErrorStatus()));
     decoder_->Decode(buffer,
                      base::BindOnce(&DecryptingVideoDecoderTest::DecodeDone,
                                     base::Unretained(this)));
@@ -224,7 +232,7 @@
   }
 
   MOCK_METHOD1(FrameReady, void(scoped_refptr<VideoFrame>));
-  MOCK_METHOD1(DecodeDone, void(DecodeStatus));
+  MOCK_METHOD1(DecodeDone, void(Status));
 
   MOCK_METHOD1(OnWaiting, void(WaitingReason));
 
@@ -313,10 +321,10 @@
       .WillRepeatedly(RunCallback<1>(Decryptor::kError,
                                      scoped_refptr<VideoFrame>(nullptr)));
 
-  DecodeAndExpect(encrypted_buffer_, DecodeStatus::DECODE_ERROR);
+  DecodeAndExpectError(encrypted_buffer_);
 
   // After a decode error occurred, all following decodes return DECODE_ERROR.
-  DecodeAndExpect(encrypted_buffer_, DecodeStatus::DECODE_ERROR);
+  DecodeAndExpectError(encrypted_buffer_);
 }
 
 // Test the case where the decryptor receives end-of-stream buffer.
@@ -336,7 +344,7 @@
       .WillRepeatedly(
           RunCallback<1>(Decryptor::kSuccess, decoded_video_frame_));
   EXPECT_CALL(*this, FrameReady(decoded_video_frame_));
-  EXPECT_CALL(*this, DecodeDone(DecodeStatus::OK));
+  EXPECT_CALL(*this, DecodeDone(IsOkStatus()));
   event_cb_.Run(CdmContext::Event::kHasAdditionalUsableKey);
   base::RunLoop().RunUntilIdle();
 }
@@ -351,7 +359,7 @@
       .WillRepeatedly(
           RunCallback<1>(Decryptor::kSuccess, decoded_video_frame_));
   EXPECT_CALL(*this, FrameReady(decoded_video_frame_));
-  EXPECT_CALL(*this, DecodeDone(DecodeStatus::OK));
+  EXPECT_CALL(*this, DecodeDone(IsOkStatus()));
   // The video decode callback is returned after the correct decryption key is
   // added.
   event_cb_.Run(CdmContext::Event::kHasAdditionalUsableKey);
@@ -379,7 +387,7 @@
   Initialize();
   EnterPendingDecodeState();
 
-  EXPECT_CALL(*this, DecodeDone(DecodeStatus::ABORTED));
+  EXPECT_CALL(*this, DecodeDone(HasStatusCode(StatusCode::kAborted)));
 
   Reset();
 }
@@ -389,7 +397,7 @@
   Initialize();
   EnterWaitingForKeyState();
 
-  EXPECT_CALL(*this, DecodeDone(DecodeStatus::ABORTED));
+  EXPECT_CALL(*this, DecodeDone(HasStatusCode(StatusCode::kAborted)));
 
   Reset();
 }
@@ -449,7 +457,7 @@
   Initialize();
   EnterPendingDecodeState();
 
-  EXPECT_CALL(*this, DecodeDone(DecodeStatus::ABORTED));
+  EXPECT_CALL(*this, DecodeDone(HasStatusCode(StatusCode::kAborted)));
 
   Destroy();
 }
@@ -459,7 +467,7 @@
   Initialize();
   EnterWaitingForKeyState();
 
-  EXPECT_CALL(*this, DecodeDone(DecodeStatus::ABORTED));
+  EXPECT_CALL(*this, DecodeDone(HasStatusCode(StatusCode::kAborted)));
 
   Destroy();
 }
@@ -481,7 +489,7 @@
   EnterPendingDecodeState();
 
   EXPECT_CALL(*decryptor_, ResetDecoder(Decryptor::kVideo));
-  EXPECT_CALL(*this, DecodeDone(DecodeStatus::ABORTED));
+  EXPECT_CALL(*this, DecodeDone(HasStatusCode(StatusCode::kAborted)));
 
   decoder_->Reset(NewExpectedClosure());
   Destroy();
diff --git a/media/filters/fake_video_decoder.cc b/media/filters/fake_video_decoder.cc
index 5ef6326..cfdd7ba4f 100644
--- a/media/filters/fake_video_decoder.cc
+++ b/media/filters/fake_video_decoder.cc
@@ -233,15 +233,15 @@
 
 void FakeVideoDecoder::OnFrameDecoded(int buffer_size,
                                       DecodeCB decode_cb,
-                                      DecodeStatus status) {
+                                      Status status) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  if (status == DecodeStatus::OK) {
+  if (status.is_ok()) {
     total_bytes_decoded_ += buffer_size;
     if (bytes_decoded_cb_)
       bytes_decoded_cb_.Run(buffer_size);
   }
-  std::move(decode_cb).Run(status);
+  std::move(decode_cb).Run(std::move(status));
 }
 
 void FakeVideoDecoder::RunOrHoldDecode(DecodeCB decode_cb) {
diff --git a/media/filters/fake_video_decoder.h b/media/filters/fake_video_decoder.h
index 2b134049..e846717 100644
--- a/media/filters/fake_video_decoder.h
+++ b/media/filters/fake_video_decoder.h
@@ -95,7 +95,7 @@
   virtual scoped_refptr<VideoFrame> MakeVideoFrame(const DecoderBuffer& buffer);
 
   // Callback for updating |total_bytes_decoded_|.
-  void OnFrameDecoded(int buffer_size, DecodeCB decode_cb, DecodeStatus status);
+  void OnFrameDecoded(int buffer_size, DecodeCB decode_cb, Status status);
 
   // Runs |decode_cb| or puts it to |held_decode_callbacks_| depending on
   // current value of |hold_decode_|.
diff --git a/media/filters/fake_video_decoder_unittest.cc b/media/filters/fake_video_decoder_unittest.cc
index ec68971..1c7fa61 100644
--- a/media/filters/fake_video_decoder_unittest.cc
+++ b/media/filters/fake_video_decoder_unittest.cc
@@ -81,10 +81,10 @@
   }
 
   // Callback for VideoDecoder::Decode().
-  void DecodeDone(DecodeStatus status) {
+  void DecodeDone(Status status) {
     DCHECK_GT(pending_decode_requests_, 0);
     --pending_decode_requests_;
-    last_decode_status_ = status;
+    last_decode_status_ = std::move(status);
   }
 
   void FrameReady(scoped_refptr<VideoFrame> frame) {
@@ -111,17 +111,17 @@
         break;
       case OK:
         EXPECT_EQ(0, pending_decode_requests_);
-        ASSERT_EQ(DecodeStatus::OK, last_decode_status_);
+        ASSERT_TRUE(last_decode_status_.is_ok());
         ASSERT_TRUE(last_decoded_frame_.get());
         break;
       case NOT_ENOUGH_DATA:
         EXPECT_EQ(0, pending_decode_requests_);
-        ASSERT_EQ(DecodeStatus::OK, last_decode_status_);
+        ASSERT_TRUE(last_decode_status_.is_ok());
         ASSERT_FALSE(last_decoded_frame_.get());
         break;
       case ABORTED:
         EXPECT_EQ(0, pending_decode_requests_);
-        ASSERT_EQ(DecodeStatus::ABORTED, last_decode_status_);
+        ASSERT_EQ(StatusCode::kAborted, last_decode_status_.code());
         EXPECT_FALSE(last_decoded_frame_.get());
         break;
     }
@@ -237,7 +237,7 @@
   int total_bytes_in_buffers_;
 
   // Callback result/status.
-  DecodeStatus last_decode_status_;
+  Status last_decode_status_;
   scoped_refptr<VideoFrame> last_decoded_frame_;
   int pending_decode_requests_;
   bool is_reset_pending_;
@@ -263,7 +263,7 @@
   decoder_->SimulateFailureToInit();
   InitializeWithConfigAndExpectResult(TestVideoConfig::Normal(), false);
   Decode();
-  EXPECT_EQ(last_decode_status_, DecodeStatus::DECODE_ERROR);
+  EXPECT_THAT(last_decode_status_, IsDecodeErrorStatus());
 }
 
 TEST_P(FakeVideoDecoderTest, Read_AllFrames) {
@@ -364,7 +364,7 @@
   decoder_->SimulateFailureToInit();
   InitializeWithConfigAndExpectResult(TestVideoConfig::Normal(), false);
   Decode();
-  EXPECT_EQ(last_decode_status_, DecodeStatus::DECODE_ERROR);
+  EXPECT_THAT(last_decode_status_, IsDecodeErrorStatus());
 }
 
 // Reinitializing the decoder during the middle of the decoding process can
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc
index 7c705bd..2d9be601 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -107,14 +107,14 @@
   // Sets up expectations and actions to put FFmpegVideoDecoder in an active
   // decoding state.
   void EnterDecodingState() {
-    EXPECT_EQ(DecodeStatus::OK, DecodeSingleFrame(i_frame_buffer_));
+    EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
     ASSERT_EQ(1U, output_frames_.size());
   }
 
   // Sets up expectations and actions to put FFmpegVideoDecoder in an end
   // of stream state.
   void EnterEndOfStreamState() {
-    EXPECT_EQ(DecodeStatus::OK, DecodeSingleFrame(end_of_stream_buffer_));
+    EXPECT_TRUE(DecodeSingleFrame(end_of_stream_buffer_).is_ok());
     ASSERT_FALSE(output_frames_.empty());
   }
 
@@ -124,29 +124,29 @@
   // Decodes all buffers in |input_buffers| and push all successfully decoded
   // output frames into |output_frames|.
   // Returns the last decode status returned by the decoder.
-  DecodeStatus DecodeMultipleFrames(const InputBuffers& input_buffers) {
+  Status DecodeMultipleFrames(const InputBuffers& input_buffers) {
     for (auto iter = input_buffers.begin(); iter != input_buffers.end();
          ++iter) {
-      DecodeStatus status = Decode(*iter);
-      switch (status) {
-        case DecodeStatus::OK:
+      Status status = Decode(*iter);
+      switch (status.code()) {
+        case StatusCode::kOk:
           break;
-        case DecodeStatus::ABORTED:
+        case StatusCode::kAborted:
           NOTREACHED();
           FALLTHROUGH;
-        case DecodeStatus::DECODE_ERROR:
+        default:
           DCHECK(output_frames_.empty());
           return status;
       }
     }
-    return DecodeStatus::OK;
+    return StatusCode::kOk;
   }
 
   // Decodes the single compressed frame in |buffer| and writes the
   // uncompressed output to |video_frame|. This method works with single
   // and multithreaded decoders. End of stream buffers are used to trigger
   // the frame to be returned in the multithreaded decoder case.
-  DecodeStatus DecodeSingleFrame(scoped_refptr<DecoderBuffer> buffer) {
+  Status DecodeSingleFrame(scoped_refptr<DecoderBuffer> buffer) {
     InputBuffers input_buffers;
     input_buffers.push_back(buffer);
     input_buffers.push_back(end_of_stream_buffer_);
@@ -168,9 +168,9 @@
     input_buffers.push_back(buffer);
     input_buffers.push_back(end_of_stream_buffer_);
 
-    DecodeStatus status = DecodeMultipleFrames(input_buffers);
+    Status status = DecodeMultipleFrames(input_buffers);
 
-    EXPECT_EQ(DecodeStatus::OK, status);
+    EXPECT_TRUE(status.is_ok());
     ASSERT_EQ(2U, output_frames_.size());
 
     gfx::Size original_size = kVisibleRect.size();
@@ -184,8 +184,8 @@
               output_frames_[1]->visible_rect().size().height());
   }
 
-  DecodeStatus Decode(scoped_refptr<DecoderBuffer> buffer) {
-    DecodeStatus status;
+  Status Decode(scoped_refptr<DecoderBuffer> buffer) {
+    Status status;
     EXPECT_CALL(*this, DecodeDone(_)).WillOnce(SaveArg<0>(&status));
 
     decoder_->Decode(buffer, base::BindOnce(&FFmpegVideoDecoderTest::DecodeDone,
@@ -201,7 +201,7 @@
     output_frames_.push_back(std::move(frame));
   }
 
-  MOCK_METHOD1(DecodeDone, void(DecodeStatus));
+  MOCK_METHOD1(DecodeDone, void(Status));
 
   StrictMock<MockMediaLog> media_log_;
 
@@ -256,7 +256,7 @@
   Initialize();
 
   // Simulate decoding a single frame.
-  EXPECT_EQ(DecodeStatus::OK, DecodeSingleFrame(i_frame_buffer_));
+  EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
   ASSERT_EQ(1U, output_frames_.size());
 }
 
@@ -268,14 +268,14 @@
   // The error is only raised on the second decode attempt, so we expect at
   // least one successful decode but we don't expect valid frame to be decoded.
   // During the second decode attempt an error is raised.
-  EXPECT_EQ(DecodeStatus::OK, Decode(corrupt_i_frame_buffer_));
+  EXPECT_TRUE(Decode(corrupt_i_frame_buffer_).is_ok());
   EXPECT_TRUE(output_frames_.empty());
-  EXPECT_EQ(DecodeStatus::DECODE_ERROR, Decode(i_frame_buffer_));
+  EXPECT_THAT(Decode(i_frame_buffer_), IsDecodeErrorStatus());
   EXPECT_TRUE(output_frames_.empty());
 
   // After a decode error occurred, all following decodes will return
   // DecodeStatus::DECODE_ERROR.
-  EXPECT_EQ(DecodeStatus::DECODE_ERROR, Decode(i_frame_buffer_));
+  EXPECT_THAT(Decode(i_frame_buffer_), IsDecodeErrorStatus());
   EXPECT_TRUE(output_frames_.empty());
 }
 
@@ -285,8 +285,8 @@
 
   EXPECT_MEDIA_LOG(ContainsFailedToSendLog());
 
-  EXPECT_EQ(DecodeStatus::DECODE_ERROR,
-            DecodeSingleFrame(corrupt_i_frame_buffer_));
+  EXPECT_THAT(DecodeSingleFrame(corrupt_i_frame_buffer_),
+              IsDecodeErrorStatus());
 }
 
 // Decode |i_frame_buffer_| and then a frame with a larger width and verify
diff --git a/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc b/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc
index 61144c2f..e50a856 100644
--- a/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc
+++ b/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc
@@ -260,10 +260,10 @@
     DecodeBuffer(ReadTestDataFile(name));
   }
 
-  void OnFrameDecoded(size_t frame_pos, DecodeStatus status) {
+  void OnFrameDecoded(size_t frame_pos, Status status) {
     EXPECT_EQ(frame_pos, num_decoded_buffers_);
     num_decoded_buffers_ += 1;
-    last_decode_status_ = status;
+    last_decode_status_ = std::move(status);
     if (run_loop_)
       run_loop_->Quit();
   }
@@ -276,7 +276,7 @@
       run_loop_ = &run_loop;
       run_loop.Run();
       run_loop_ = nullptr;
-      ASSERT_EQ(last_decode_status_, DecodeStatus::OK);
+      ASSERT_TRUE(last_decode_status_.is_ok());
     }
   }
 
@@ -298,7 +298,7 @@
   std::list<scoped_refptr<VideoFrame>> output_frames_;
   size_t num_output_frames_ = 0;
 
-  DecodeStatus last_decode_status_ = DecodeStatus::OK;
+  Status last_decode_status_;
   base::RunLoop* run_loop_ = nullptr;
 
   // Number of frames that OnVideoFrame() should keep in |output_frames_|.
diff --git a/media/filters/gav1_video_decoder_unittest.cc b/media/filters/gav1_video_decoder_unittest.cc
index 5a4d2fd..c12a6be4 100644
--- a/media/filters/gav1_video_decoder_unittest.cc
+++ b/media/filters/gav1_video_decoder_unittest.cc
@@ -110,15 +110,14 @@
   // Sets up expectations and actions to put Gav1VideoDecoder in an active
   // decoding state.
   void ExpectDecodingState() {
-    EXPECT_EQ(DecodeStatus::OK, DecodeSingleFrame(i_frame_buffer_));
+    EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
     ASSERT_EQ(1U, output_frames_.size());
   }
 
   // Sets up expectations and actions to put Gav1VideoDecoder in an end
   // of stream state.
   void ExpectEndOfStreamState() {
-    EXPECT_EQ(DecodeStatus::OK,
-              DecodeSingleFrame(DecoderBuffer::CreateEOSBuffer()));
+    EXPECT_TRUE(DecodeSingleFrame(DecoderBuffer::CreateEOSBuffer()).is_ok());
     ASSERT_FALSE(output_frames_.empty());
   }
 
@@ -128,26 +127,26 @@
   // Decodes all buffers in |input_buffers| and push all successfully decoded
   // output frames into |output_frames|. Returns the last decode status returned
   // by the decoder.
-  DecodeStatus DecodeMultipleFrames(const InputBuffers& input_buffers) {
+  Status DecodeMultipleFrames(const InputBuffers& input_buffers) {
     for (auto iter = input_buffers.begin(); iter != input_buffers.end();
          ++iter) {
-      DecodeStatus status = Decode(*iter);
-      switch (status) {
-        case DecodeStatus::OK:
+      Status status = Decode(*iter);
+      switch (status.code()) {
+        case StatusCode::kOk:
           break;
-        case DecodeStatus::ABORTED:
+        case StatusCode::kAborted:
           NOTREACHED();
           FALLTHROUGH;
-        case DecodeStatus::DECODE_ERROR:
+        default:
           DCHECK(output_frames_.empty());
           return status;
       }
     }
-    return DecodeStatus::OK;
+    return StatusCode::kOk;
   }
 
   // Decodes the single compressed frame in |buffer|.
-  DecodeStatus DecodeSingleFrame(scoped_refptr<DecoderBuffer> buffer) {
+  Status DecodeSingleFrame(scoped_refptr<DecoderBuffer> buffer) {
     InputBuffers input_buffers;
     input_buffers.push_back(std::move(buffer));
     return DecodeMultipleFrames(input_buffers);
@@ -166,9 +165,9 @@
     input_buffers.push_back(buffer);
     input_buffers.push_back(DecoderBuffer::CreateEOSBuffer());
 
-    DecodeStatus status = DecodeMultipleFrames(input_buffers);
+    Status status = DecodeMultipleFrames(input_buffers);
 
-    EXPECT_EQ(DecodeStatus::OK, status);
+    EXPECT_TRUE(status.is_ok());
     ASSERT_EQ(2U, output_frames_.size());
 
     gfx::Size original_size = TestVideoConfig::NormalCodedSize();
@@ -182,8 +181,8 @@
               output_frames_[1]->visible_rect().size().height());
   }
 
-  DecodeStatus Decode(scoped_refptr<DecoderBuffer> buffer) {
-    DecodeStatus status;
+  Status Decode(scoped_refptr<DecoderBuffer> buffer) {
+    Status status;
     EXPECT_CALL(*this, DecodeDone(_)).WillOnce(testing::SaveArg<0>(&status));
 
     decoder_->Decode(std::move(buffer),
@@ -208,7 +207,7 @@
     return base::MD5DigestToBase16(digest);
   }
 
-  MOCK_METHOD1(DecodeDone, void(DecodeStatus));
+  MOCK_METHOD1(DecodeDone, void(Status));
 
   testing::StrictMock<MockMediaLog> media_log_;
 
@@ -248,7 +247,7 @@
   Initialize();
 
   // Simulate decoding a single frame.
-  EXPECT_EQ(DecodeStatus::OK, DecodeSingleFrame(i_frame_buffer_));
+  EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
   ASSERT_EQ(1U, output_frames_.size());
 
   const auto& frame = output_frames_.front();
@@ -258,8 +257,9 @@
 
 TEST_F(Gav1VideoDecoderTest, DecodeFrame_8bitMono) {
   Initialize();
-  EXPECT_EQ(DecodeStatus::OK, DecodeSingleFrame(ReadTestDataFile(
-                                  "av1-monochrome-I-frame-320x240-8bpp")));
+  EXPECT_TRUE(
+      DecodeSingleFrame(ReadTestDataFile("av1-monochrome-I-frame-320x240-8bpp"))
+          .is_ok());
   ASSERT_EQ(1U, output_frames_.size());
 
   const auto& frame = output_frames_.front();
@@ -269,8 +269,9 @@
 
 TEST_F(Gav1VideoDecoderTest, DecodeFrame_10bitMono) {
   Initialize();
-  EXPECT_EQ(DecodeStatus::OK, DecodeSingleFrame(ReadTestDataFile(
-                                  "av1-monochrome-I-frame-320x240-10bpp")));
+  EXPECT_TRUE(DecodeSingleFrame(
+                  ReadTestDataFile("av1-monochrome-I-frame-320x240-10bpp"))
+                  .is_ok());
   ASSERT_EQ(1U, output_frames_.size());
 
   const auto& frame = output_frames_.front();
@@ -281,8 +282,9 @@
 // libgav1 does not support bit depth 12.
 TEST_F(Gav1VideoDecoderTest, DISABLED_DecodeFrame_12bitMono) {
   Initialize();
-  EXPECT_EQ(DecodeStatus::OK, DecodeSingleFrame(ReadTestDataFile(
-                                  "av1-monochrome-I-frame-320x240-12bpp")));
+  EXPECT_TRUE(DecodeSingleFrame(
+                  ReadTestDataFile("av1-monochrome-I-frame-320x240-12bpp"))
+                  .is_ok());
   ASSERT_EQ(1U, output_frames_.size());
 
   const auto& frame = output_frames_.front();
diff --git a/media/filters/offloading_video_decoder_unittest.cc b/media/filters/offloading_video_decoder_unittest.cc
index 925bd7c0..53b4354 100644
--- a/media/filters/offloading_video_decoder_unittest.cc
+++ b/media/filters/offloading_video_decoder_unittest.cc
@@ -95,8 +95,8 @@
                       base::Unretained(this));
   }
 
-  VideoDecoder::DecodeCB ExpectDecodeCB(DecodeStatus status) {
-    EXPECT_CALL(*this, DecodeDone(status))
+  VideoDecoder::DecodeCB ExpectDecodeCB(StatusCode status) {
+    EXPECT_CALL(*this, DecodeDone(HasStatusCode(status)))
         .WillOnce(VerifyOn(task_env_.GetMainThreadTaskRunner()));
     return base::BindOnce(&OffloadingVideoDecoderTest::DecodeDone,
                           base::Unretained(this));
@@ -190,7 +190,7 @@
 
   MOCK_METHOD1(InitDone, void(bool));
   MOCK_METHOD1(OutputDone, void(scoped_refptr<VideoFrame>));
-  MOCK_METHOD1(DecodeDone, void(DecodeStatus));
+  MOCK_METHOD1(DecodeDone, void(Status));
   MOCK_METHOD0(ResetDone, void(void));
 
   base::test::TaskEnvironment task_env_;
@@ -297,7 +297,7 @@
       .WillRepeatedly(DoAll(VerifyNotOn(task_env_.GetMainThreadTaskRunner()),
                             RunClosure(base::BindRepeating(output_cb, nullptr)),
                             RunOnceCallback<1>(DecodeStatus::OK)));
-  EXPECT_CALL(*this, DecodeDone(DecodeStatus::OK))
+  EXPECT_CALL(*this, DecodeDone(IsOkStatus()))
       .Times(2)
       .WillRepeatedly(VerifyOn(task_env_.GetMainThreadTaskRunner()));
   EXPECT_CALL(*this, OutputDone(_))
@@ -344,7 +344,7 @@
                      base::Unretained(this)));
 
   EXPECT_CALL(*decoder_, Decode_(_, _)).Times(0);
-  EXPECT_CALL(*this, DecodeDone(DecodeStatus::ABORTED))
+  EXPECT_CALL(*this, DecodeDone(HasStatusCode(StatusCode::kAborted)))
       .Times(2)
       .WillRepeatedly(VerifyOn(task_env_.GetMainThreadTaskRunner()));
   offloading_decoder_->Reset(ExpectResetCB());
diff --git a/media/filters/vpx_video_decoder_fuzzertest.cc b/media/filters/vpx_video_decoder_fuzzertest.cc
index c66304e..577fa38 100644
--- a/media/filters/vpx_video_decoder_fuzzertest.cc
+++ b/media/filters/vpx_video_decoder_fuzzertest.cc
@@ -30,8 +30,7 @@
   base::test::SingleThreadTaskEnvironment task_environment;
 };
 
-void OnDecodeComplete(const base::Closure& quit_closure,
-                      media::DecodeStatus status) {
+void OnDecodeComplete(const base::Closure& quit_closure, media::Status status) {
   quit_closure.Run();
 }
 
diff --git a/media/filters/vpx_video_decoder_unittest.cc b/media/filters/vpx_video_decoder_unittest.cc
index f889357..379f2f8 100644
--- a/media/filters/vpx_video_decoder_unittest.cc
+++ b/media/filters/vpx_video_decoder_unittest.cc
@@ -71,15 +71,14 @@
   // Sets up expectations and actions to put VpxVideoDecoder in an active
   // decoding state.
   void ExpectDecodingState() {
-    EXPECT_EQ(DecodeStatus::OK, DecodeSingleFrame(i_frame_buffer_));
+    EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
     ASSERT_EQ(1U, output_frames_.size());
   }
 
   // Sets up expectations and actions to put VpxVideoDecoder in an end
   // of stream state.
   void ExpectEndOfStreamState() {
-    EXPECT_EQ(DecodeStatus::OK,
-              DecodeSingleFrame(DecoderBuffer::CreateEOSBuffer()));
+    EXPECT_TRUE(DecodeSingleFrame(DecoderBuffer::CreateEOSBuffer()).is_ok());
     ASSERT_FALSE(output_frames_.empty());
   }
 
@@ -89,29 +88,29 @@
   // Decodes all buffers in |input_buffers| and push all successfully decoded
   // output frames into |output_frames|.
   // Returns the last decode status returned by the decoder.
-  DecodeStatus DecodeMultipleFrames(const InputBuffers& input_buffers) {
+  Status DecodeMultipleFrames(const InputBuffers& input_buffers) {
     for (auto iter = input_buffers.begin(); iter != input_buffers.end();
          ++iter) {
-      DecodeStatus status = Decode(*iter);
-      switch (status) {
-        case DecodeStatus::OK:
+      Status status = Decode(*iter);
+      switch (status.code()) {
+        case StatusCode::kOk:
           break;
-        case DecodeStatus::ABORTED:
+        case StatusCode::kAborted:
           NOTREACHED();
           FALLTHROUGH;
-        case DecodeStatus::DECODE_ERROR:
+        default:
           DCHECK(output_frames_.empty());
           return status;
       }
     }
-    return DecodeStatus::OK;
+    return OkStatus();
   }
 
   // Decodes the single compressed frame in |buffer| and writes the
   // uncompressed output to |video_frame|. This method works with single
   // and multithreaded decoders. End of stream buffers are used to trigger
   // the frame to be returned in the multithreaded decoder case.
-  DecodeStatus DecodeSingleFrame(scoped_refptr<DecoderBuffer> buffer) {
+  Status DecodeSingleFrame(scoped_refptr<DecoderBuffer> buffer) {
     InputBuffers input_buffers;
     input_buffers.push_back(std::move(buffer));
     input_buffers.push_back(DecoderBuffer::CreateEOSBuffer());
@@ -132,9 +131,9 @@
     input_buffers.push_back(buffer);
     input_buffers.push_back(DecoderBuffer::CreateEOSBuffer());
 
-    DecodeStatus status = DecodeMultipleFrames(input_buffers);
+    Status status = DecodeMultipleFrames(input_buffers);
 
-    EXPECT_EQ(DecodeStatus::OK, status);
+    EXPECT_TRUE(status.is_ok());
     ASSERT_EQ(2U, output_frames_.size());
 
     gfx::Size original_size = TestVideoConfig::NormalCodedSize();
@@ -148,8 +147,8 @@
               output_frames_[1]->visible_rect().size().height());
   }
 
-  DecodeStatus Decode(scoped_refptr<DecoderBuffer> buffer) {
-    DecodeStatus status;
+  Status Decode(scoped_refptr<DecoderBuffer> buffer) {
+    Status status;
     EXPECT_CALL(*this, DecodeDone(_)).WillOnce(testing::SaveArg<0>(&status));
 
     decoder_->Decode(std::move(buffer),
@@ -165,7 +164,7 @@
     output_frames_.push_back(std::move(frame));
   }
 
-  MOCK_METHOD1(DecodeDone, void(DecodeStatus));
+  MOCK_METHOD1(DecodeDone, void(Status));
 
   base::test::TaskEnvironment task_env_;
   std::unique_ptr<VideoDecoder> decoder_;
@@ -192,7 +191,7 @@
   Initialize();
 
   // Simulate decoding a single frame.
-  EXPECT_EQ(DecodeStatus::OK, DecodeSingleFrame(i_frame_buffer_));
+  EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
   ASSERT_EQ(1U, output_frames_.size());
 }
 
@@ -318,10 +317,10 @@
 
   AVPacket packet = {};
   while (av_read_frame(glue.format_context(), &packet) >= 0) {
-    DecodeStatus decode_status =
+    Status decode_status =
         Decode(DecoderBuffer::CopyFrom(packet.data, packet.size));
     av_packet_unref(&packet);
-    if (decode_status != DecodeStatus::OK)
+    if (!decode_status.is_ok())
       break;
   }
 
diff --git a/media/gpu/android/media_codec_video_decoder_unittest.cc b/media/gpu/android/media_codec_video_decoder_unittest.cc
index 21591dd26e..190ccee 100644
--- a/media/gpu/android/media_codec_video_decoder_unittest.cc
+++ b/media/gpu/android/media_codec_video_decoder_unittest.cc
@@ -396,7 +396,7 @@
   Initialize(TestVideoConfig::Large(codec_));
   ON_CALL(*video_frame_factory_, Initialize(ExpectedOverlayMode(), _))
       .WillByDefault(RunCallback<1>(nullptr));
-  EXPECT_CALL(decode_cb_, Run(DecodeStatus::DECODE_ERROR)).Times(1);
+  EXPECT_CALL(decode_cb_, Run(IsDecodeErrorStatus())).Times(1);
   EXPECT_CALL(*surface_chooser_, MockUpdateState()).Times(0);
   mcvd_->Decode(fake_decoder_buffer_, decode_cb_.Get());
 }
@@ -404,7 +404,7 @@
 TEST_P(MediaCodecVideoDecoderTest, CodecCreationFailureIsAnError) {
   InitializeWithTextureOwner_OneDecodePending(TestVideoConfig::Large(codec_));
   mcvd_->Decode(fake_decoder_buffer_, decode_cb_.Get());
-  EXPECT_CALL(decode_cb_, Run(DecodeStatus::DECODE_ERROR)).Times(2);
+  EXPECT_CALL(decode_cb_, Run(IsDecodeErrorStatus())).Times(2);
   // Failing to create a codec should put MCVD into an error state.
   codec_allocator_->ProvideNullCodecAsync();
 }
@@ -414,7 +414,7 @@
       InitializeFully_OneDecodePending(TestVideoConfig::Large(codec_));
   EXPECT_CALL(*codec, DequeueInputBuffer(_, _))
       .WillOnce(Return(MEDIA_CODEC_ERROR));
-  EXPECT_CALL(decode_cb_, Run(DecodeStatus::DECODE_ERROR));
+  EXPECT_CALL(decode_cb_, Run(IsDecodeErrorStatus()));
   PumpCodec();
 }
 
@@ -553,7 +553,7 @@
 
   surface_chooser_->ProvideTextureOwner();
   EXPECT_CALL(*codec, SetSurface(_)).WillOnce(Return(false));
-  EXPECT_CALL(decode_cb_, Run(DecodeStatus::DECODE_ERROR)).Times(2);
+  EXPECT_CALL(decode_cb_, Run(IsDecodeErrorStatus())).Times(2);
   EXPECT_CALL(*codec_allocator_, MockReleaseMediaCodec(codec));
   mcvd_->Decode(fake_decoder_buffer_, decode_cb_.Get());
   // Verify expectations before we delete the MCVD.
@@ -599,7 +599,7 @@
 
 TEST_P(MediaCodecVideoDecoderTest, ResetAbortsPendingDecodes) {
   InitializeWithTextureOwner_OneDecodePending(TestVideoConfig::Large(codec_));
-  EXPECT_CALL(decode_cb_, Run(DecodeStatus::ABORTED));
+  EXPECT_CALL(decode_cb_, Run(HasStatusCode(StatusCode::kAborted)));
   DoReset();
   testing::Mock::VerifyAndClearExpectations(&decode_cb_);
 }
@@ -617,7 +617,7 @@
   codec->AcceptOneInput(MockMediaCodecBridge::kEos);
   PumpCodec();
 
-  EXPECT_CALL(eos_decode_cb, Run(DecodeStatus::ABORTED));
+  EXPECT_CALL(eos_decode_cb, Run(HasStatusCode(StatusCode::kAborted)));
   DoReset();
   // Should be run before |mcvd_| is destroyed.
   testing::Mock::VerifyAndClearExpectations(&eos_decode_cb);
@@ -766,7 +766,7 @@
   codec->ProduceOneOutput(MockMediaCodecBridge::kEos);
   PumpCodec();
 
-  EXPECT_CALL(eos_decode_cb, Run(DecodeStatus::OK));
+  EXPECT_CALL(eos_decode_cb, Run(IsOkStatus()));
   std::move(video_frame_factory_->last_closure_).Run();
 }
 
diff --git a/media/gpu/chromeos/vd_video_decode_accelerator.cc b/media/gpu/chromeos/vd_video_decode_accelerator.cc
index 2c1cb0b..fb085cba 100644
--- a/media/gpu/chromeos/vd_video_decode_accelerator.cc
+++ b/media/gpu/chromeos/vd_video_decode_accelerator.cc
@@ -190,12 +190,12 @@
 }
 
 void VdVideoDecodeAccelerator::OnDecodeDone(int32_t bitstream_buffer_id,
-                                            DecodeStatus status) {
-  DVLOGF(4) << "status: " << status;
+                                            Status status) {
+  DVLOGF(4) << "status: " << status.code();
   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
   DCHECK(client_);
 
-  if (status == DecodeStatus::DECODE_ERROR) {
+  if (!status.is_ok() && status.code() != StatusCode::kAborted) {
     OnError(FROM_HERE, PLATFORM_FAILURE);
     return;
   }
@@ -241,19 +241,19 @@
       base::BindOnce(&VdVideoDecodeAccelerator::OnFlushDone, weak_this_));
 }
 
-void VdVideoDecodeAccelerator::OnFlushDone(DecodeStatus status) {
-  DVLOGF(3) << "status: " << status;
+void VdVideoDecodeAccelerator::OnFlushDone(Status status) {
+  DVLOGF(3) << "status: " << status.code();
   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
   DCHECK(client_);
 
-  switch (status) {
-    case DecodeStatus::OK:
+  switch (status.code()) {
+    case StatusCode::kOk:
       client_->NotifyFlushDone();
       break;
-    case DecodeStatus::ABORTED:
+    case StatusCode::kAborted:
       // Do nothing.
       break;
-    case DecodeStatus::DECODE_ERROR:
+    default:
       OnError(FROM_HERE, PLATFORM_FAILURE);
       break;
   }
diff --git a/media/gpu/chromeos/vd_video_decode_accelerator.h b/media/gpu/chromeos/vd_video_decode_accelerator.h
index ffdb43c..f4ea148 100644
--- a/media/gpu/chromeos/vd_video_decode_accelerator.h
+++ b/media/gpu/chromeos/vd_video_decode_accelerator.h
@@ -94,9 +94,9 @@
 
   // Callback methods of |vd_|.
   void OnInitializeDone(Status status);
-  void OnDecodeDone(int32_t bitstream_buffer_id, DecodeStatus status);
+  void OnDecodeDone(int32_t bitstream_buffer_id, Status status);
   void OnFrameReady(scoped_refptr<VideoFrame> frame);
-  void OnFlushDone(DecodeStatus status);
+  void OnFlushDone(Status status);
   void OnResetDone();
 
   // Get Picture instance that represents the same buffer as |frame|. Return
diff --git a/media/gpu/chromeos/video_decoder_pipeline.cc b/media/gpu/chromeos/video_decoder_pipeline.cc
index dd1544f..7c52f3c 100644
--- a/media/gpu/chromeos/video_decoder_pipeline.cc
+++ b/media/gpu/chromeos/video_decoder_pipeline.cc
@@ -365,21 +365,21 @@
 
 void VideoDecoderPipeline::OnDecodeDone(bool is_flush,
                                         DecodeCB decode_cb,
-                                        DecodeStatus status) {
+                                        Status status) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DVLOGF(4) << "is_flush: " << is_flush << ", status: " << status;
+  DVLOGF(4) << "is_flush: " << is_flush << ", status: " << status.code();
 
   if (has_error_)
-    status = DecodeStatus::DECODE_ERROR;
+    status = Status(DecodeStatus::DECODE_ERROR);
 
-  if (is_flush && status == DecodeStatus::OK) {
+  if (is_flush && status.is_ok()) {
     client_flush_cb_ = std::move(decode_cb);
     CallFlushCbIfNeeded(DecodeStatus::OK);
     return;
   }
 
-  client_task_runner_->PostTask(FROM_HERE,
-                                base::BindOnce(std::move(decode_cb), status));
+  client_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(std::move(decode_cb), std::move(status)));
 }
 
 void VideoDecoderPipeline::OnFrameDecoded(scoped_refptr<VideoFrame> frame) {
diff --git a/media/gpu/chromeos/video_decoder_pipeline.h b/media/gpu/chromeos/video_decoder_pipeline.h
index 16287e243..c3af61a 100644
--- a/media/gpu/chromeos/video_decoder_pipeline.h
+++ b/media/gpu/chromeos/video_decoder_pipeline.h
@@ -42,7 +42,7 @@
   // TODO(crbug.com/998413): Replace VideoFrame to GpuMemoryBuffer-based
   // instance.
   using OutputCB = base::RepeatingCallback<void(scoped_refptr<VideoFrame>)>;
-  using DecodeCB = base::OnceCallback<void(DecodeStatus)>;
+  using DecodeCB = VideoDecoder::DecodeCB;
 
   // Client interface of DecoderInterface.
   class MEDIA_GPU_EXPORT Client {
@@ -190,7 +190,7 @@
                         Status parent_error,
                         Status status);
 
-  void OnDecodeDone(bool eos_buffer, DecodeCB decode_cb, DecodeStatus status);
+  void OnDecodeDone(bool eos_buffer, DecodeCB decode_cb, Status status);
   void OnResetDone();
   void OnError(const std::string& msg);
 
diff --git a/media/gpu/ipc/service/vda_video_decoder_unittest.cc b/media/gpu/ipc/service/vda_video_decoder_unittest.cc
index 6bff33cd..1d887b20 100644
--- a/media/gpu/ipc/service/vda_video_decoder_unittest.cc
+++ b/media/gpu/ipc/service/vda_video_decoder_unittest.cc
@@ -176,7 +176,7 @@
   }
 
   void NotifyEndOfBitstreamBuffer(int32_t bitstream_id) {
-    EXPECT_CALL(decode_cb_, Run(DecodeStatus::OK));
+    EXPECT_CALL(decode_cb_, Run(HasStatusCode(DecodeStatus::OK)));
     if (GetParam()) {
       // TODO(sandersd): The VDA could notify on either thread. Test both.
       client_->NotifyEndOfBitstreamBuffer(bitstream_id);
@@ -375,7 +375,7 @@
   vdavd_->Reset(reset_cb_.Get());
   RunUntilIdle();
 
-  EXPECT_CALL(decode_cb_, Run(DecodeStatus::ABORTED));
+  EXPECT_CALL(decode_cb_, Run(HasStatusCode(DecodeStatus::ABORTED)));
   EXPECT_CALL(reset_cb_, Run());
   NotifyResetDone();
 }
@@ -384,7 +384,7 @@
   Initialize();
   Decode(base::TimeDelta());
 
-  EXPECT_CALL(decode_cb_, Run(DecodeStatus::DECODE_ERROR));
+  EXPECT_CALL(decode_cb_, Run(IsDecodeErrorStatus()));
   NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
 }
 
@@ -461,7 +461,7 @@
   vdavd_->Decode(DecoderBuffer::CreateEOSBuffer(), decode_cb_.Get());
   RunUntilIdle();
 
-  EXPECT_CALL(decode_cb_, Run(DecodeStatus::OK));
+  EXPECT_CALL(decode_cb_, Run(IsOkStatus()));
   NotifyFlushDone();
 }
 
diff --git a/media/gpu/test/video.cc b/media/gpu/test/video.cc
index e2e76a0c..3f85ebe2 100644
--- a/media/gpu/test/video.cc
+++ b/media/gpu/test/video.cc
@@ -487,8 +487,8 @@
          num_decoded_frames < num_frames) {
     if (packet.stream_index == stream_index) {
       media::VideoDecoder::DecodeCB decode_cb = base::BindOnce(
-          [](bool* success, media::DecodeStatus status) {
-            *success = (status == media::DecodeStatus::OK);
+          [](bool* success, media::Status status) {
+            *success = (status.is_ok());
           },
           success);
       decoder.Decode(DecoderBuffer::CopyFrom(packet.data, packet.size),
diff --git a/media/gpu/test/video_encoder/bitstream_validator.cc b/media/gpu/test/video_encoder/bitstream_validator.cc
index 33036172..7e62260 100644
--- a/media/gpu/test/video_encoder/bitstream_validator.cc
+++ b/media/gpu/test/video_encoder/bitstream_validator.cc
@@ -151,14 +151,14 @@
   }
 }
 
-void BitstreamValidator::DecodeDone(int64_t timestamp, DecodeStatus status) {
+void BitstreamValidator::DecodeDone(int64_t timestamp, Status status) {
   SEQUENCE_CHECKER(validator_thread_sequence_checker_);
-  if (status != DecodeStatus::OK) {
+  if (!status.is_ok()) {
     base::AutoLock lock(validator_lock_);
     if (!decode_error_) {
       decode_error_ = true;
       LOG(ERROR) << "DecodeStatus is not OK, status="
-                 << GetDecodeStatusString(status);
+                 << GetDecodeStatusString(status.code());
     }
   }
   if (timestamp == kEOSTimeStamp) {
diff --git a/media/gpu/test/video_encoder/bitstream_validator.h b/media/gpu/test/video_encoder/bitstream_validator.h
index dcdb84d..10b3d45 100644
--- a/media/gpu/test/video_encoder/bitstream_validator.h
+++ b/media/gpu/test/video_encoder/bitstream_validator.h
@@ -67,7 +67,7 @@
                             size_t frame_index);
 
   // Functions for media::VideoDecoder.
-  void DecodeDone(int64_t timestamp, DecodeStatus status);
+  void DecodeDone(int64_t timestamp, Status status);
   void VerifyOutputFrame(scoped_refptr<VideoFrame> frame);
 
   // Validator components touched by validator_thread_ only.
diff --git a/media/gpu/test/video_player/video_decoder_client.cc b/media/gpu/test/video_player/video_decoder_client.cc
index 3c2978f..da475de 100644
--- a/media/gpu/test/video_player/video_decoder_client.cc
+++ b/media/gpu/test/video_player/video_decoder_client.cc
@@ -316,7 +316,7 @@
 
   VideoDecoder::DecodeCB decode_cb = base::BindOnce(
       CallbackThunk<decltype(&VideoDecoderClient::DecodeDoneTask),
-                    media::DecodeStatus>,
+                    media::Status>,
       weak_this_, decoder_client_thread_.task_runner(),
       &VideoDecoderClient::DecodeDoneTask);
   decoder_->Decode(std::move(bitstream_buffer), std::move(decode_cb));
@@ -337,7 +337,7 @@
 
   VideoDecoder::DecodeCB flush_done_cb =
       base::BindOnce(CallbackThunk<decltype(&VideoDecoderClient::FlushDoneTask),
-                                   media::DecodeStatus>,
+                                   media::Status>,
                      weak_this_, decoder_client_thread_.task_runner(),
                      &VideoDecoderClient::FlushDoneTask);
   decoder_->Decode(DecoderBuffer::CreateEOSBuffer(), std::move(flush_done_cb));
@@ -371,10 +371,10 @@
   FireEvent(VideoPlayerEvent::kInitialized);
 }
 
-void VideoDecoderClient::DecodeDoneTask(media::DecodeStatus status) {
+void VideoDecoderClient::DecodeDoneTask(media::Status status) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_client_sequence_checker_);
   DCHECK_NE(VideoDecoderClientState::kIdle, decoder_client_state_);
-  ASSERT_TRUE(status != media::DecodeStatus::ABORTED ||
+  ASSERT_TRUE(status.code() != media::StatusCode::kAborted ||
               decoder_client_state_ == VideoDecoderClientState::kResetting);
   DVLOGF(4);
 
@@ -403,7 +403,7 @@
   current_frame_index_++;
 }
 
-void VideoDecoderClient::FlushDoneTask(media::DecodeStatus status) {
+void VideoDecoderClient::FlushDoneTask(media::Status status) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_client_sequence_checker_);
   DCHECK_EQ(0u, num_outstanding_decode_requests_);
 
diff --git a/media/gpu/test/video_player/video_decoder_client.h b/media/gpu/test/video_player/video_decoder_client.h
index 232205c8..87e81b43 100644
--- a/media/gpu/test/video_player/video_decoder_client.h
+++ b/media/gpu/test/video_player/video_decoder_client.h
@@ -150,11 +150,11 @@
   // Called by the decoder when initialization has completed.
   void DecoderInitializedTask(Status status);
   // Called by the decoder when a fragment has been decoded.
-  void DecodeDoneTask(media::DecodeStatus status);
+  void DecodeDoneTask(media::Status status);
   // Called by the decoder when a video frame is ready.
   void FrameReadyTask(scoped_refptr<VideoFrame> video_frame);
   // Called by the decoder when flushing has completed.
-  void FlushDoneTask(media::DecodeStatus status);
+  void FlushDoneTask(media::Status status);
   // Called by the decoder when resetting has completed.
   void ResetDoneTask();
 
diff --git a/media/gpu/video_encode_accelerator_unittest.cc b/media/gpu/video_encode_accelerator_unittest.cc
index 23320bdc..da750bc6 100644
--- a/media/gpu/video_encode_accelerator_unittest.cc
+++ b/media/gpu/video_encode_accelerator_unittest.cc
@@ -1087,8 +1087,8 @@
 
  private:
   void InitializeCB(Status status);
-  void DecodeDone(DecodeStatus status);
-  void FlushDone(DecodeStatus status);
+  void DecodeDone(Status status);
+  void FlushDone(Status status);
   void VerifyOutputFrame(scoped_refptr<VideoFrame> output_frame);
   void Decode();
   void WriteFrameStats();
@@ -1196,20 +1196,21 @@
   original_frames_.push(frame);
 }
 
-void VideoFrameQualityValidator::DecodeDone(DecodeStatus status) {
+void VideoFrameQualityValidator::DecodeDone(Status status) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  if (status == DecodeStatus::OK) {
+  if (status.is_ok()) {
     decoder_state_ = INITIALIZED;
     Decode();
   } else {
     decoder_state_ = DECODER_ERROR;
     decode_error_cb_.Run();
-    FAIL() << "Unexpected decode status = " << status << ". Stop decoding.";
+    FAIL() << "Unexpected decode status = " << status.code()
+           << ". Stop decoding.";
   }
 }
 
-void VideoFrameQualityValidator::FlushDone(DecodeStatus status) {
+void VideoFrameQualityValidator::FlushDone(Status status) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   WriteFrameStats();
diff --git a/media/mojo/clients/mojo_audio_decoder.cc b/media/mojo/clients/mojo_audio_decoder.cc
index ddfe31c0..fad002c 100644
--- a/media/mojo/clients/mojo_audio_decoder.cc
+++ b/media/mojo/clients/mojo_audio_decoder.cc
@@ -217,8 +217,8 @@
   std::move(init_cb_).Run(std::move(status));
 }
 
-void MojoAudioDecoder::OnDecodeStatus(DecodeStatus status) {
-  DVLOG(1) << __func__ << ": status:" << status;
+void MojoAudioDecoder::OnDecodeStatus(const Status& status) {
+  DVLOG(1) << __func__ << ": status:" << status.code();
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   DCHECK(decode_cb_);
diff --git a/media/mojo/clients/mojo_audio_decoder.h b/media/mojo/clients/mojo_audio_decoder.h
index a7db243..b3b17b5 100644
--- a/media/mojo/clients/mojo_audio_decoder.h
+++ b/media/mojo/clients/mojo_audio_decoder.h
@@ -67,7 +67,7 @@
   void OnInitialized(const Status& status, bool needs_bitstream_conversion);
 
   // Called when |remote_decoder_| accepted or rejected DecoderBuffer.
-  void OnDecodeStatus(DecodeStatus decode_status);
+  void OnDecodeStatus(const Status& decode_status);
 
   // called when |remote_decoder_| finished Reset() sequence.
   void OnResetDone();
diff --git a/media/mojo/clients/mojo_audio_decoder_unittest.cc b/media/mojo/clients/mojo_audio_decoder_unittest.cc
index 17d5d19..f699b14 100644
--- a/media/mojo/clients/mojo_audio_decoder_unittest.cc
+++ b/media/mojo/clients/mojo_audio_decoder_unittest.cc
@@ -83,7 +83,7 @@
   MOCK_METHOD1(OnInitialized, void(Status));
   MOCK_METHOD1(OnOutput, void(scoped_refptr<AudioBuffer>));
   MOCK_METHOD1(OnWaiting, void(WaitingReason));
-  MOCK_METHOD1(OnDecoded, void(DecodeStatus));
+  MOCK_METHOD1(OnDecoded, void(Status));
   MOCK_METHOD0(OnReset, void());
 
   // Always create a new RunLoop (and destroy the old loop if it exists) before
@@ -206,7 +206,7 @@
 
     InSequence s;  // Make sure OnOutput() and OnDecoded() are called in order.
     EXPECT_CALL(*this, OnOutput(_)).Times(kOutputPerDecode);
-    EXPECT_CALL(*this, OnDecoded(DecodeStatus::OK))
+    EXPECT_CALL(*this, OnDecoded(IsOkStatus()))
         .WillOnce(
             InvokeWithoutArgs(this, &MojoAudioDecoderTest::KeepDecodingOrQuit));
     Decode();
@@ -215,7 +215,7 @@
   void DecodeAndReset() {
     InSequence s;  // Make sure all callbacks are fired in order.
     EXPECT_CALL(*this, OnOutput(_)).Times(kOutputPerDecode);
-    EXPECT_CALL(*this, OnDecoded(DecodeStatus::OK));
+    EXPECT_CALL(*this, OnDecoded(IsOkStatus()));
     EXPECT_CALL(*this, OnReset())
         .WillOnce(InvokeWithoutArgs(this, &MojoAudioDecoderTest::QuitLoop));
     Decode();
@@ -297,7 +297,7 @@
         std::move(decode_cb).Run(DecodeStatus::OK);
       });
   EXPECT_CALL(*this, OnWaiting(WaitingReason::kNoDecryptionKey)).Times(1);
-  EXPECT_CALL(*this, OnDecoded(DecodeStatus::OK))
+  EXPECT_CALL(*this, OnDecoded(IsOkStatus()))
       .WillOnce(InvokeWithoutArgs(this, &MojoAudioDecoderTest::QuitLoop));
   Decode();
   RunLoop();
diff --git a/media/mojo/clients/mojo_video_decoder.cc b/media/mojo/clients/mojo_video_decoder.cc
index fb9169b5..524f979 100644
--- a/media/mojo/clients/mojo_video_decoder.cc
+++ b/media/mojo/clients/mojo_video_decoder.cc
@@ -294,7 +294,7 @@
   }
 }
 
-void MojoVideoDecoder::OnDecodeDone(uint64_t decode_id, DecodeStatus status) {
+void MojoVideoDecoder::OnDecodeDone(uint64_t decode_id, const Status& status) {
   DVLOG(3) << __func__;
   DCHECK(task_runner_->BelongsToCurrentThread());
 
@@ -305,7 +305,7 @@
     return;
   }
 
-  if (status == DecodeStatus::DECODE_ERROR)
+  if (!status.is_ok() && status.code() != StatusCode::kAborted)
     ReportInitialPlaybackErrorUMA();
 
   DecodeCB decode_cb = std::move(it->second);
diff --git a/media/mojo/clients/mojo_video_decoder.h b/media/mojo/clients/mojo_video_decoder.h
index 87f6989..6d7fc9b 100644
--- a/media/mojo/clients/mojo_video_decoder.h
+++ b/media/mojo/clients/mojo_video_decoder.h
@@ -91,7 +91,7 @@
   void OnInitializeDone(const Status& status,
                         bool needs_bitstream_conversion,
                         int32_t max_decode_requests);
-  void OnDecodeDone(uint64_t decode_id, DecodeStatus status);
+  void OnDecodeDone(uint64_t decode_id, const Status& status);
   void OnResetDone();
 
   void BindRemoteDecoder();
diff --git a/media/mojo/mojom/audio_decoder.mojom b/media/mojo/mojom/audio_decoder.mojom
index 27222222..599834e8 100644
--- a/media/mojo/mojom/audio_decoder.mojom
+++ b/media/mojo/mojom/audio_decoder.mojom
@@ -33,7 +33,7 @@
   // pending buffers should be processed, the corresponding decoded buffers
   // should be returned to the proxy, and only then the service should return
   // DecoderStatus.
-  Decode(DecoderBuffer buffer) => (DecodeStatus status);
+  Decode(DecoderBuffer buffer) => (Status status);
 
   // Resets decoder state. Should be called only if Initialize() succeeds.
   // All pending Decode() requests will be finished or aborted, then the method
diff --git a/media/mojo/mojom/video_decoder.mojom b/media/mojo/mojom/video_decoder.mojom
index 719c226..1ff471e 100644
--- a/media/mojo/mojom/video_decoder.mojom
+++ b/media/mojo/mojom/video_decoder.mojom
@@ -142,7 +142,7 @@
   // If |buffer| is an EOS buffer, implementations must execute all other
   // pending Decode() callbacks and output all pending frames before executing
   // the Decode(EOS) callback. (That is, they must flush.)
-  Decode(DecoderBuffer buffer) => (DecodeStatus status);
+  Decode(DecoderBuffer buffer) => (Status status);
 
   // Reset the decoder. All ongoing Decode() requests must be completed or
   // aborted before executing the callback. This must not be called while there
diff --git a/media/mojo/services/mojo_audio_decoder_service.cc b/media/mojo/services/mojo_audio_decoder_service.cc
index 8edf30d..66157cd1 100644
--- a/media/mojo/services/mojo_audio_decoder_service.cc
+++ b/media/mojo/services/mojo_audio_decoder_service.cc
@@ -140,9 +140,9 @@
 }
 
 void MojoAudioDecoderService::OnDecodeStatus(DecodeCallback callback,
-                                             media::DecodeStatus status) {
-  DVLOG(3) << __func__ << " status:" << status;
-  std::move(callback).Run(status);
+                                             const Status status) {
+  DVLOG(3) << __func__ << " status:" << status.code();
+  std::move(callback).Run(std::move(status));
 }
 
 void MojoAudioDecoderService::OnResetDone(ResetCallback callback) {
diff --git a/media/mojo/services/mojo_audio_decoder_service.h b/media/mojo/services/mojo_audio_decoder_service.h
index 6dcb2f4..d827174 100644
--- a/media/mojo/services/mojo_audio_decoder_service.h
+++ b/media/mojo/services/mojo_audio_decoder_service.h
@@ -13,6 +13,7 @@
 #include "base/memory/weak_ptr.h"
 #include "media/base/audio_decoder.h"
 #include "media/base/cdm_context.h"
+#include "media/base/status.h"
 #include "media/mojo/mojom/audio_decoder.mojom.h"
 #include "media/mojo/services/media_mojo_export.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
@@ -54,7 +55,7 @@
   void OnReaderFlushDone(ResetCallback callback);
 
   // Called by |decoder_| when DecoderBuffer is accepted or rejected.
-  void OnDecodeStatus(DecodeCallback callback, media::DecodeStatus status);
+  void OnDecodeStatus(DecodeCallback callback, media::Status status);
 
   // Called by |decoder_| when reset sequence is finished.
   void OnResetDone(ResetCallback callback);
diff --git a/media/mojo/services/mojo_video_decoder_service.cc b/media/mojo/services/mojo_video_decoder_service.cc
index 8ef9c58..c0d9729 100644
--- a/media/mojo/services/mojo_video_decoder_service.cc
+++ b/media/mojo/services/mojo_video_decoder_service.cc
@@ -316,7 +316,7 @@
 void MojoVideoDecoderService::OnDecoderDecoded(
     DecodeCallback callback,
     std::unique_ptr<ScopedDecodeTrace> trace_event,
-    DecodeStatus status) {
+    media::Status status) {
   DVLOG(3) << __func__;
   if (trace_event) {
     TRACE_EVENT_ASYNC_STEP_PAST0("media", kDecodeTraceName, trace_event.get(),
@@ -324,7 +324,7 @@
     trace_event->EndTrace(status);
   }
 
-  std::move(callback).Run(status);
+  std::move(callback).Run(std::move(status));
 }
 
 void MojoVideoDecoderService::OnDecoderReset() {
diff --git a/media/mojo/services/mojo_video_decoder_service.h b/media/mojo/services/mojo_video_decoder_service.h
index ee80356..da0ff47 100644
--- a/media/mojo/services/mojo_video_decoder_service.h
+++ b/media/mojo/services/mojo_video_decoder_service.h
@@ -72,7 +72,7 @@
                     scoped_refptr<DecoderBuffer> buffer);
   void OnDecoderDecoded(DecodeCallback callback,
                         std::unique_ptr<ScopedDecodeTrace> trace_event,
-                        DecodeStatus status);
+                        media::Status status);
 
   // Called by |mojo_decoder_buffer_reader_| when reset is finished.
   void OnReaderFlushed();
diff --git a/media/mojo/test/mojo_video_decoder_integration_test.cc b/media/mojo/test/mojo_video_decoder_integration_test.cc
index 3b67d0f..90de9ab 100644
--- a/media/mojo/test/mojo_video_decoder_integration_test.cc
+++ b/media/mojo/test/mojo_video_decoder_integration_test.cc
@@ -257,10 +257,10 @@
     return result.is_ok();
   }
 
-  DecodeStatus Decode(scoped_refptr<DecoderBuffer> buffer,
-                      VideoFrame::ReleaseMailboxCB release_cb =
-                          VideoFrame::ReleaseMailboxCB()) {
-    DecodeStatus result = DecodeStatus::DECODE_ERROR;
+  Status Decode(scoped_refptr<DecoderBuffer> buffer,
+                VideoFrame::ReleaseMailboxCB release_cb =
+                    VideoFrame::ReleaseMailboxCB()) {
+    Status result(DecodeStatus::DECODE_ERROR);
 
     if (!buffer->end_of_stream()) {
       decoder_->release_mailbox_cb = std::move(release_cb);
@@ -432,7 +432,7 @@
 
   EXPECT_CALL(*decoder_, Decode_(_, _));
   EXPECT_CALL(waiting_cb_, Run(WaitingReason::kNoDecryptionKey));
-  EXPECT_CALL(decode_cb, Run(DecodeStatus::OK));
+  EXPECT_CALL(decode_cb, Run(IsOkStatus()));
 
   client_->Decode(buffer, decode_cb.Get());
   RunUntilIdle();
@@ -442,10 +442,10 @@
   ASSERT_TRUE(Initialize());
 
   EXPECT_CALL(output_cb_, Run(_));
-  ASSERT_EQ(Decode(CreateKeyframe(0)), DecodeStatus::OK);
+  ASSERT_TRUE(Decode(CreateKeyframe(0)).is_ok());
   Mock::VerifyAndClearExpectations(&output_cb_);
 
-  ASSERT_EQ(Decode(DecoderBuffer::CreateEOSBuffer()), DecodeStatus::OK);
+  ASSERT_TRUE(Decode(DecoderBuffer::CreateEOSBuffer()).is_ok());
 }
 
 TEST_F(MojoVideoDecoderIntegrationTest, Release) {
@@ -455,7 +455,7 @@
   scoped_refptr<VideoFrame> frame;
 
   EXPECT_CALL(output_cb_, Run(_)).WillOnce(SaveArg<0>(&frame));
-  ASSERT_EQ(Decode(CreateKeyframe(0), release_cb.Get()), DecodeStatus::OK);
+  ASSERT_TRUE(Decode(CreateKeyframe(0), release_cb.Get()).is_ok());
   Mock::VerifyAndClearExpectations(&output_cb_);
 
   EXPECT_CALL(release_cb, Run(_));
@@ -470,7 +470,7 @@
   scoped_refptr<VideoFrame> frame;
 
   EXPECT_CALL(output_cb_, Run(_)).WillOnce(SaveArg<0>(&frame));
-  ASSERT_EQ(Decode(CreateKeyframe(0), release_cb.Get()), DecodeStatus::OK);
+  ASSERT_TRUE(Decode(CreateKeyframe(0), release_cb.Get()).is_ok());
   Mock::VerifyAndClearExpectations(&output_cb_);
 
   client_.reset();
@@ -546,7 +546,7 @@
   EXPECT_CALL(output_cb_, Run(_)).Times(frames_to_decode);
   EXPECT_CALL(*decoder_, Decode_(_, _)).Times(frames_to_decode);
 
-  EXPECT_CALL(decode_cb, Run(DecodeStatus::OK)).Times(frames_to_decode);
+  EXPECT_CALL(decode_cb, Run(IsOkStatus())).Times(frames_to_decode);
 
   for (int i = 0; i < frames_to_decode - 1; i++)
     client_->Decode(CreateKeyframe(i * 16), decode_cb.Get());
@@ -574,9 +574,9 @@
   EXPECT_CALL(output_cb_, Run(_)).Times(frames_to_decode - 1);
   EXPECT_CALL(*decoder_, Decode_(_, _)).Times(frames_to_decode);
 
-  EXPECT_CALL(decode_cb, Run(DecodeStatus::OK)).Times(frames_to_decode - 1);
+  EXPECT_CALL(decode_cb, Run(IsOkStatus())).Times(frames_to_decode - 1);
 
-  EXPECT_CALL(decode_cb, Run(DecodeStatus::DECODE_ERROR)).Times(1);
+  EXPECT_CALL(decode_cb, Run(IsDecodeErrorStatus())).Times(1);
 
   for (int i = 0; i < frames_to_decode - 1; i++)
     client_->Decode(CreateKeyframe(i * 16), decode_cb.Get());
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.cc b/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.cc
index 419bc929..4b9f7fa 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.cc
+++ b/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.cc
@@ -64,7 +64,7 @@
       WTF::CrossThreadOnceFunction<void(media::Status status,
                                         base::Optional<DecoderDetails>)>;
   using CrossThreadOnceDecodeCB =
-      WTF::CrossThreadOnceFunction<void(media::DecodeStatus)>;
+      WTF::CrossThreadOnceFunction<void(media::Status)>;
   using CrossThreadOnceResetCB = WTF::CrossThreadOnceClosure;
 
   MediaAudioTaskWrapper(
@@ -217,13 +217,13 @@
                                  weak_client_, std::move(buffer)));
   }
 
-  void OnDecodeDone(int cb_id, media::DecodeStatus status) {
+  void OnDecodeDone(int cb_id, media::Status status) {
     DVLOG(2) << __func__;
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     PostCrossThreadTask(
         *main_task_runner_, FROM_HERE,
         WTF::CrossThreadBindOnce(&CrossThreadAudioDecoderClient::OnDecodeDone,
-                                 weak_client_, cb_id, status));
+                                 weak_client_, cb_id, std::move(status)));
   }
 
   void OnReset(int cb_id) {
@@ -347,7 +347,7 @@
                                buffer, callback_id));
 }
 
-void AudioDecoderBroker::OnDecodeDone(int cb_id, media::DecodeStatus status) {
+void AudioDecoderBroker::OnDecodeDone(int cb_id, media::Status status) {
   DVLOG(2) << __func__;
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(pending_decode_cb_map_.Contains(cb_id));
@@ -358,7 +358,7 @@
 
   // Do this last. Caller may destruct |this| in response to the callback while
   // this method is still on the stack.
-  std::move(decode_cb).Run(status);
+  std::move(decode_cb).Run(std::move(status));
 }
 
 void AudioDecoderBroker::Reset(base::OnceClosure reset_cb) {
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.h b/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.h
index 1bae54e..c99ade4 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.h
+++ b/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.h
@@ -41,7 +41,7 @@
   virtual void OnInitialize(media::Status status,
                             base::Optional<DecoderDetails> details) = 0;
 
-  virtual void OnDecodeDone(int cb_id, media::DecodeStatus status) = 0;
+  virtual void OnDecodeDone(int cb_id, media::Status status) = 0;
 
   virtual void OnDecodeOutput(scoped_refptr<media::AudioBuffer> buffer) = 0;
 
@@ -91,7 +91,7 @@
   // MediaAudioTaskWrapper::CrossThreadAudioDecoderClient
   void OnInitialize(media::Status status,
                     base::Optional<DecoderDetails> details) override;
-  void OnDecodeDone(int cb_id, media::DecodeStatus status) override;
+  void OnDecodeDone(int cb_id, media::Status status) override;
   void OnDecodeOutput(scoped_refptr<media::AudioBuffer> buffer) override;
   void OnReset(int cb_id) override;
 
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker_test.cc b/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker_test.cc
index 1c941199..3d7115a 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker_test.cc
+++ b/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker_test.cc
@@ -160,8 +160,8 @@
     done_cb.Run();
   }
   void OnDecodeDoneWithClosure(base::RepeatingClosure done_cb,
-                               media::DecodeStatus status) {
-    OnDecodeDone(status);
+                               media::Status status) {
+    OnDecodeDone(std::move(status));
     done_cb.Run();
   }
 
@@ -171,7 +171,7 @@
   }
 
   MOCK_METHOD1(OnInit, void(media::Status status));
-  MOCK_METHOD1(OnDecodeDone, void(media::DecodeStatus));
+  MOCK_METHOD1(OnDecodeDone, void(media::Status));
   MOCK_METHOD0(OnResetDone, void());
 
   void OnOutput(scoped_refptr<media::AudioBuffer> buffer) {
@@ -210,9 +210,9 @@
 
   void DecodeBuffer(
       scoped_refptr<media::DecoderBuffer> buffer,
-      media::DecodeStatus expected_status = media::DecodeStatus::OK) {
+      media::StatusCode expected_status = media::StatusCode::kOk) {
     base::RunLoop run_loop;
-    EXPECT_CALL(*this, OnDecodeDone(expected_status));
+    EXPECT_CALL(*this, OnDecodeDone(HasStatusCode(expected_status)));
     decoder_broker_->Decode(
         buffer, WTF::Bind(&AudioDecoderBrokerTest::OnDecodeDoneWithClosure,
                           WTF::Unretained(this), run_loop.QuitClosure()));
diff --git a/third_party/blink/renderer/modules/webcodecs/decoder_template.cc b/third_party/blink/renderer/modules/webcodecs/decoder_template.cc
index 47772f51..533c72d 100644
--- a/third_party/blink/renderer/modules/webcodecs/decoder_template.cc
+++ b/third_party/blink/renderer/modules/webcodecs/decoder_template.cc
@@ -382,7 +382,7 @@
 }
 
 template <typename Traits>
-void DecoderTemplate<Traits>::OnConfigureFlushDone(media::DecodeStatus status) {
+void DecoderTemplate<Traits>::OnConfigureFlushDone(media::Status status) {
   DVLOG(3) << __func__;
   if (IsClosed())
     return;
@@ -390,7 +390,7 @@
   DCHECK(pending_request_);
   DCHECK_EQ(pending_request_->type, Request::Type::kConfigure);
 
-  if (status != media::DecodeStatus::OK) {
+  if (!status.is_ok()) {
     HandleError();
     return;
   }
@@ -425,14 +425,12 @@
 }
 
 template <typename Traits>
-void DecoderTemplate<Traits>::OnDecodeDone(uint32_t id,
-                                           media::DecodeStatus status) {
+void DecoderTemplate<Traits>::OnDecodeDone(uint32_t id, media::Status status) {
   DVLOG(3) << __func__;
   if (IsClosed())
     return;
 
-  if (status != media::DecodeStatus::OK &&
-      status != media::DecodeStatus::ABORTED) {
+  if (!status.is_ok() && status.code() != media::StatusCode::kAborted) {
     HandleError();
     return;
   }
@@ -444,7 +442,7 @@
 }
 
 template <typename Traits>
-void DecoderTemplate<Traits>::OnFlushDone(media::DecodeStatus status) {
+void DecoderTemplate<Traits>::OnFlushDone(media::Status status) {
   DVLOG(3) << __func__;
   if (IsClosed())
     return;
@@ -452,7 +450,7 @@
   DCHECK(pending_request_);
   DCHECK_EQ(pending_request_->type, Request::Type::kFlush);
 
-  if (status != media::DecodeStatus::OK) {
+  if (!status.is_ok()) {
     HandleError();
     return;
   }
diff --git a/third_party/blink/renderer/modules/webcodecs/decoder_template.h b/third_party/blink/renderer/modules/webcodecs/decoder_template.h
index 6369944e..6ec9641 100644
--- a/third_party/blink/renderer/modules/webcodecs/decoder_template.h
+++ b/third_party/blink/renderer/modules/webcodecs/decoder_template.h
@@ -99,9 +99,9 @@
 
   // Called by |decoder_|.
   void OnInitializeDone(media::Status status);
-  void OnDecodeDone(uint32_t id, media::DecodeStatus);
-  void OnFlushDone(media::DecodeStatus);
-  void OnConfigureFlushDone(media::DecodeStatus);
+  void OnDecodeDone(uint32_t id, media::Status);
+  void OnFlushDone(media::Status);
+  void OnConfigureFlushDone(media::Status);
   void OnResetDone();
   void OnOutput(scoped_refptr<MediaOutputType>);
 
diff --git a/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.cc b/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.cc
index 3e138124..4b333995 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.cc
@@ -70,7 +70,7 @@
       WTF::CrossThreadOnceFunction<void(media::Status status,
                                         base::Optional<DecoderDetails>)>;
   using CrossThreadOnceDecodeCB =
-      WTF::CrossThreadOnceFunction<void(media::DecodeStatus)>;
+      WTF::CrossThreadOnceFunction<void(const media::Status&)>;
   using CrossThreadOnceResetCB = WTF::CrossThreadOnceClosure;
 
   MediaVideoTaskWrapper(
@@ -244,14 +244,14 @@
                                  decoder_->CanReadWithoutStalling()));
   }
 
-  void OnDecodeDone(int cb_id, media::DecodeStatus status) {
+  void OnDecodeDone(int cb_id, media::Status status) {
     DVLOG(2) << __func__;
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
     PostCrossThreadTask(
         *main_task_runner_, FROM_HERE,
         WTF::CrossThreadBindOnce(&CrossThreadVideoDecoderClient::OnDecodeDone,
-                                 weak_client_, cb_id, status));
+                                 weak_client_, cb_id, std::move(status)));
   }
 
   void OnReset(int cb_id) {
@@ -390,7 +390,7 @@
                                buffer, callback_id));
 }
 
-void VideoDecoderBroker::OnDecodeDone(int cb_id, media::DecodeStatus status) {
+void VideoDecoderBroker::OnDecodeDone(int cb_id, media::Status status) {
   DVLOG(2) << __func__;
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(pending_decode_cb_map_.Contains(cb_id));
@@ -401,7 +401,7 @@
 
   // Do this last. Caller may destruct |this| in response to the callback while
   // this method is still on the stack.
-  std::move(decode_cb).Run(status);
+  std::move(decode_cb).Run(std::move(status));
 }
 
 void VideoDecoderBroker::Reset(base::OnceClosure reset_cb) {
diff --git a/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.h b/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.h
index a2e461c..62115c4b 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.h
+++ b/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.h
@@ -50,7 +50,7 @@
   virtual void OnInitialize(media::Status status,
                             base::Optional<DecoderDetails> details) = 0;
 
-  virtual void OnDecodeDone(int cb_id, media::DecodeStatus status) = 0;
+  virtual void OnDecodeDone(int cb_id, media::Status status) = 0;
 
   virtual void OnDecodeOutput(scoped_refptr<media::VideoFrame> frame,
                               bool can_read_without_stalling) = 0;
@@ -107,7 +107,7 @@
   // MediaVideoTaskWrapper::CrossThreadVideoDecoderClient
   void OnInitialize(media::Status status,
                     base::Optional<DecoderDetails> details) override;
-  void OnDecodeDone(int cb_id, media::DecodeStatus status) override;
+  void OnDecodeDone(int cb_id, media::Status status) override;
   void OnDecodeOutput(scoped_refptr<media::VideoFrame> frame,
                       bool can_read_without_stalling) override;
   void OnReset(int cb_id) override;
diff --git a/third_party/blink/renderer/modules/webcodecs/video_decoder_broker_test.cc b/third_party/blink/renderer/modules/webcodecs/video_decoder_broker_test.cc
index 8c26091..97ec506 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_decoder_broker_test.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_decoder_broker_test.cc
@@ -169,8 +169,8 @@
     done_cb.Run();
   }
   void OnDecodeDoneWithClosure(base::RepeatingClosure done_cb,
-                               media::DecodeStatus status) {
-    OnDecodeDone(status);
+                               media::Status status) {
+    OnDecodeDone(std::move(status));
     done_cb.Run();
   }
 
@@ -180,7 +180,7 @@
   }
 
   MOCK_METHOD1(OnInit, void(media::Status status));
-  MOCK_METHOD1(OnDecodeDone, void(media::DecodeStatus));
+  MOCK_METHOD1(OnDecodeDone, void(media::Status));
   MOCK_METHOD0(OnResetDone, void());
 
   void OnOutput(scoped_refptr<media::VideoFrame> frame) {
@@ -238,9 +238,9 @@
 
   void DecodeBuffer(
       scoped_refptr<media::DecoderBuffer> buffer,
-      media::DecodeStatus expected_status = media::DecodeStatus::OK) {
+      media::StatusCode expected_status = media::StatusCode::kOk) {
     base::RunLoop run_loop;
-    EXPECT_CALL(*this, OnDecodeDone(expected_status));
+    EXPECT_CALL(*this, OnDecodeDone(HasStatusCode(expected_status)));
     decoder_broker_->Decode(
         buffer, WTF::Bind(&VideoDecoderBrokerTest::OnDecodeDoneWithClosure,
                           WTF::Unretained(this), run_loop.QuitClosure()));
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc
index 2794082..ce7e7d6a 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc
@@ -471,13 +471,13 @@
   }
 }
 
-void RTCVideoDecoderAdapter::OnDecodeDone(media::DecodeStatus status) {
-  DVLOG(3) << __func__ << "(" << status << ")";
+void RTCVideoDecoderAdapter::OnDecodeDone(media::Status status) {
+  DVLOG(3) << __func__ << "(" << status.code() << ")";
   DCHECK(media_task_runner_->BelongsToCurrentThread());
 
   outstanding_decode_requests_--;
 
-  if (status == media::DecodeStatus::DECODE_ERROR) {
+  if (!status.is_ok() && status.code() != media::StatusCode::kAborted) {
     DVLOG(2) << "Entering permanent error state";
     UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoDecoderError",
                               media::VideoDecodeAccelerator::PLATFORM_FAILURE,
@@ -583,8 +583,8 @@
       media::DecoderBuffer::CreateEOSBuffer(),
       WTF::BindRepeating(
           [](FlushDoneCB flush_success, FlushDoneCB flush_fail,
-             media::DecodeStatus status) {
-            if (status == media::DecodeStatus::OK)
+             media::Status status) {
+            if (status.is_ok())
               std::move(flush_success).Run();
             else
               std::move(flush_fail).Run();
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h
index ded3110..82ab3ae 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h
@@ -104,7 +104,7 @@
   static void OnInitializeDone(base::OnceCallback<void(bool)> cb,
                                media::Status status);
   void DecodeOnMediaThread();
-  void OnDecodeDone(media::DecodeStatus status);
+  void OnDecodeDone(media::Status status);
   void OnOutput(scoped_refptr<media::VideoFrame> frame);
 
   bool ShouldReinitializeForSettingHDRColorSpace(