Commit 205cc831 authored by Fredrik Hubinette's avatar Fredrik Hubinette Committed by Commit Bot

media: Parse VP9 streams and extract color space when hardware decoding

(on windows)

Bug: 760132
Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: I1c4040a2bff958d79f6e8a1fae90309d3492b29f
Reviewed-on: https://chromium-review.googlesource.com/663939
Commit-Queue: Fredrik Hubinette <hubbe@chromium.org>
Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Cr-Commit-Position: refs/heads/master@{#501449}
parent 576e1ad4
...@@ -53,6 +53,19 @@ bool VideoColorSpace::operator!=(const VideoColorSpace& other) const { ...@@ -53,6 +53,19 @@ bool VideoColorSpace::operator!=(const VideoColorSpace& other) const {
matrix != other.matrix || range != other.range; matrix != other.matrix || range != other.range;
} }
bool VideoColorSpace::IsSpecified() const {
if (primaries != PrimaryID::INVALID && primaries != PrimaryID::UNSPECIFIED)
return true;
if (transfer != TransferID::INVALID && transfer != TransferID::UNSPECIFIED)
return true;
if (matrix != MatrixID::INVALID && matrix != MatrixID::UNSPECIFIED)
return true;
// Note that it's not enough to have a range for a video color space to
// be considered valid, because often the range is just specified with
// a bool, so there is no way to know if it was set specifically or not.
return false;
}
gfx::ColorSpace VideoColorSpace::ToGfxColorSpace() const { gfx::ColorSpace VideoColorSpace::ToGfxColorSpace() const {
gfx::ColorSpace::PrimaryID primary_id = gfx::ColorSpace::PrimaryID::INVALID; gfx::ColorSpace::PrimaryID primary_id = gfx::ColorSpace::PrimaryID::INVALID;
gfx::ColorSpace::TransferID transfer_id = gfx::ColorSpace::TransferID transfer_id =
......
...@@ -82,6 +82,9 @@ class MEDIA_EXPORT VideoColorSpace { ...@@ -82,6 +82,9 @@ class MEDIA_EXPORT VideoColorSpace {
bool operator==(const VideoColorSpace& other) const; bool operator==(const VideoColorSpace& other) const;
bool operator!=(const VideoColorSpace& other) const; bool operator!=(const VideoColorSpace& other) const;
// Returns true if any of the fields have a value other
// than INVALID or UNSPECIFIED.
bool IsSpecified() const;
// These will return INVALID if the number you give it // These will return INVALID if the number you give it
// is not a valid enum value. // is not a valid enum value.
......
...@@ -47,7 +47,9 @@ ...@@ -47,7 +47,9 @@
#include "media/base/media_switches.h" #include "media/base/media_switches.h"
#include "media/base/win/mf_helpers.h" #include "media/base/win/mf_helpers.h"
#include "media/base/win/mf_initializer.h" #include "media/base/win/mf_initializer.h"
#include "media/filters/vp9_parser.h"
#include "media/gpu/dxva_picture_buffer_win.h" #include "media/gpu/dxva_picture_buffer_win.h"
#include "media/video/h264_parser.h"
#include "media/video/video_decode_accelerator.h" #include "media/video/video_decode_accelerator.h"
#include "third_party/angle/include/EGL/egl.h" #include "third_party/angle/include/EGL/egl.h"
#include "third_party/angle/include/EGL/eglext.h" #include "third_party/angle/include/EGL/eglext.h"
...@@ -302,10 +304,43 @@ HRESULT CreateCOMObjectFromDll(HMODULE dll, ...@@ -302,10 +304,43 @@ HRESULT CreateCOMObjectFromDll(HMODULE dll,
return hr; return hr;
} }
ConfigChangeDetector::~ConfigChangeDetector() {}
// Provides functionality to detect H.264 stream configuration changes.
// TODO(ananta)
// Move this to a common place so that all VDA's can use this.
class H264ConfigChangeDetector : public ConfigChangeDetector {
public:
H264ConfigChangeDetector();
~H264ConfigChangeDetector() override;
// Detects stream configuration changes.
// Returns false on failure.
bool DetectConfig(const uint8_t* stream, unsigned int size) override;
VideoColorSpace current_color_space(
const VideoColorSpace& container_color_space) const override;
private:
// These fields are used to track the SPS/PPS in the H.264 bitstream and
// are eventually compared against the SPS/PPS in the bitstream to detect
// a change.
int last_sps_id_;
std::vector<uint8_t> last_sps_;
int last_pps_id_;
std::vector<uint8_t> last_pps_;
// We want to indicate configuration changes only after we see IDR slices.
// This flag tracks that we potentially have a configuration change which
// we want to honor after we see an IDR slice.
bool pending_config_changed_;
std::unique_ptr<H264Parser> parser_;
DISALLOW_COPY_AND_ASSIGN(H264ConfigChangeDetector);
};
H264ConfigChangeDetector::H264ConfigChangeDetector() H264ConfigChangeDetector::H264ConfigChangeDetector()
: last_sps_id_(0), : last_sps_id_(0),
last_pps_id_(0), last_pps_id_(0),
config_changed_(false),
pending_config_changed_(false) {} pending_config_changed_(false) {}
H264ConfigChangeDetector::~H264ConfigChangeDetector() {} H264ConfigChangeDetector::~H264ConfigChangeDetector() {}
...@@ -409,15 +444,84 @@ bool H264ConfigChangeDetector::DetectConfig(const uint8_t* stream, ...@@ -409,15 +444,84 @@ bool H264ConfigChangeDetector::DetectConfig(const uint8_t* stream,
return true; return true;
} }
VideoColorSpace H264ConfigChangeDetector::current_color_space() const { VideoColorSpace H264ConfigChangeDetector::current_color_space(
const VideoColorSpace& container_color_space) const {
if (!parser_) if (!parser_)
return VideoColorSpace(); return container_color_space;
// TODO(hubbe): Is using last_sps_id_ correct here? // TODO(hubbe): Is using last_sps_id_ correct here?
const H264SPS* sps = parser_->GetSPS(last_sps_id_); const H264SPS* sps = parser_->GetSPS(last_sps_id_);
if (sps) if (sps && sps->GetColorSpace().IsSpecified()) {
return sps->GetColorSpace(); return sps->GetColorSpace();
return VideoColorSpace(); }
} return container_color_space;
}
// Doesn't actually detect config changes, only color spaces.
class VP9ConfigChangeDetector : public ConfigChangeDetector {
public:
VP9ConfigChangeDetector() : ConfigChangeDetector(), parser_(false) {}
~VP9ConfigChangeDetector() override {}
// Detects stream configuration changes.
// Returns false on failure.
bool DetectConfig(const uint8_t* stream, unsigned int size) override {
parser_.SetStream(stream, size);
Vp9FrameHeader fhdr;
while (parser_.ParseNextFrame(&fhdr) == Vp9Parser::kOk) {
// TODO(hubbe): move the conversion from Vp9FrameHeader to VideoColorSpace
// into a common, reusable location.
color_space_.range = fhdr.color_range ? gfx::ColorSpace::RangeID::FULL
: gfx::ColorSpace::RangeID::INVALID;
color_space_.primaries = VideoColorSpace::PrimaryID::INVALID;
color_space_.transfer = VideoColorSpace::TransferID::INVALID;
color_space_.matrix = VideoColorSpace::MatrixID::INVALID;
switch (fhdr.color_space) {
case Vp9ColorSpace::RESERVED:
case Vp9ColorSpace::UNKNOWN:
break;
case Vp9ColorSpace::BT_601:
case Vp9ColorSpace::SMPTE_170:
color_space_.primaries = VideoColorSpace::PrimaryID::SMPTE170M;
color_space_.transfer = VideoColorSpace::TransferID::SMPTE170M;
color_space_.matrix = VideoColorSpace::MatrixID::SMPTE170M;
break;
case Vp9ColorSpace::BT_709:
color_space_.primaries = VideoColorSpace::PrimaryID::BT709;
color_space_.transfer = VideoColorSpace::TransferID::BT709;
color_space_.matrix = VideoColorSpace::MatrixID::BT709;
break;
case Vp9ColorSpace::SMPTE_240:
color_space_.primaries = VideoColorSpace::PrimaryID::SMPTE240M;
color_space_.transfer = VideoColorSpace::TransferID::SMPTE240M;
color_space_.matrix = VideoColorSpace::MatrixID::SMPTE240M;
break;
case Vp9ColorSpace::BT_2020:
color_space_.primaries = VideoColorSpace::PrimaryID::BT2020;
color_space_.transfer = VideoColorSpace::TransferID::BT2020_10;
color_space_.matrix = VideoColorSpace::MatrixID::BT2020_NCL;
break;
case Vp9ColorSpace::SRGB:
color_space_.primaries = VideoColorSpace::PrimaryID::BT709;
color_space_.transfer = VideoColorSpace::TransferID::IEC61966_2_1;
color_space_.matrix = VideoColorSpace::MatrixID::BT709;
break;
}
}
return true;
}
VideoColorSpace current_color_space(
const VideoColorSpace& container_color_space) const override {
// For VP9, container color spaces override video stream color spaces.
if (container_color_space.IsSpecified()) {
return container_color_space;
}
return color_space_;
}
private:
VideoColorSpace color_space_;
Vp9Parser parser_;
};
DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo( DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo(
int32_t buffer_id, int32_t buffer_id,
...@@ -603,7 +707,10 @@ bool DXVAVideoDecodeAccelerator::Initialize(const Config& config, ...@@ -603,7 +707,10 @@ bool DXVAVideoDecodeAccelerator::Initialize(const Config& config,
"Send MFT_MESSAGE_NOTIFY_START_OF_STREAM notification failed", "Send MFT_MESSAGE_NOTIFY_START_OF_STREAM notification failed",
PLATFORM_FAILURE, false); PLATFORM_FAILURE, false);
config_change_detector_.reset(new H264ConfigChangeDetector); if (codec_ == kCodecH264)
config_change_detector_.reset(new H264ConfigChangeDetector);
if (codec_ == kCodecVP9)
config_change_detector_.reset(new VP9ConfigChangeDetector);
SetState(kNormal); SetState(kNormal);
...@@ -2179,9 +2286,9 @@ void DXVAVideoDecodeAccelerator::FlushInternal() { ...@@ -2179,9 +2286,9 @@ void DXVAVideoDecodeAccelerator::FlushInternal() {
// Attempt to retrieve an output frame from the decoder. If we have one, // Attempt to retrieve an output frame from the decoder. If we have one,
// return and proceed when the output frame is processed. If we don't have a // return and proceed when the output frame is processed. If we don't have a
// frame then we are done. // frame then we are done.
VideoColorSpace color_space = config_change_detector_->current_color_space(); VideoColorSpace color_space = config_.container_color_space;
if (color_space == VideoColorSpace()) if (config_change_detector_)
color_space = config_.container_color_space; color_space = config_change_detector_->current_color_space(color_space);
DoDecode(color_space.ToGfxColorSpace()); DoDecode(color_space.ToGfxColorSpace());
if (OutputSamplesPresent()) if (OutputSamplesPresent())
return; return;
...@@ -2231,9 +2338,9 @@ void DXVAVideoDecodeAccelerator::DecodeInternal( ...@@ -2231,9 +2338,9 @@ void DXVAVideoDecodeAccelerator::DecodeInternal(
return; return;
} }
VideoColorSpace color_space = config_change_detector_->current_color_space(); VideoColorSpace color_space = config_.container_color_space;
if (color_space == VideoColorSpace()) if (config_change_detector_)
color_space = config_.container_color_space; color_space = config_change_detector_->current_color_space(color_space);
if (!inputs_before_decode_) { if (!inputs_before_decode_) {
TRACE_EVENT_ASYNC_BEGIN0("gpu", "DXVAVideoDecodeAccelerator.Decoding", TRACE_EVENT_ASYNC_BEGIN0("gpu", "DXVAVideoDecodeAccelerator.Decoding",
...@@ -2960,8 +3067,10 @@ bool DXVAVideoDecodeAccelerator::SetTransformOutputType(IMFTransform* transform, ...@@ -2960,8 +3067,10 @@ bool DXVAVideoDecodeAccelerator::SetTransformOutputType(IMFTransform* transform,
HRESULT DXVAVideoDecodeAccelerator::CheckConfigChanged(IMFSample* sample, HRESULT DXVAVideoDecodeAccelerator::CheckConfigChanged(IMFSample* sample,
bool* config_changed) { bool* config_changed) {
if (codec_ != kCodecH264) if (!config_change_detector_) {
return S_FALSE; *config_changed = false;
return S_OK;
}
base::win::ScopedComPtr<IMFMediaBuffer> buffer; base::win::ScopedComPtr<IMFMediaBuffer> buffer;
HRESULT hr = sample->GetBufferByIndex(0, buffer.GetAddressOf()); HRESULT hr = sample->GetBufferByIndex(0, buffer.GetAddressOf());
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include "media/base/video_color_space.h" #include "media/base/video_color_space.h"
#include "media/gpu/gpu_video_decode_accelerator_helpers.h" #include "media/gpu/gpu_video_decode_accelerator_helpers.h"
#include "media/gpu/media_gpu_export.h" #include "media/gpu/media_gpu_export.h"
#include "media/video/h264_parser.h"
#include "media/video/video_decode_accelerator.h" #include "media/video/video_decode_accelerator.h"
#include "ui/gfx/color_space.h" #include "ui/gfx/color_space.h"
...@@ -60,39 +59,17 @@ class EGLStreamCopyPictureBuffer; ...@@ -60,39 +59,17 @@ class EGLStreamCopyPictureBuffer;
class EGLStreamPictureBuffer; class EGLStreamPictureBuffer;
class PbufferPictureBuffer; class PbufferPictureBuffer;
// Provides functionality to detect H.264 stream configuration changes. class ConfigChangeDetector {
// TODO(ananta)
// Move this to a common place so that all VDA's can use this.
class H264ConfigChangeDetector {
public: public:
H264ConfigChangeDetector(); virtual ~ConfigChangeDetector();
~H264ConfigChangeDetector(); virtual bool DetectConfig(const uint8_t* stream, unsigned int size) = 0;
virtual VideoColorSpace current_color_space(
// Detects stream configuration changes. const VideoColorSpace& container_color_space) const = 0;
// Returns false on failure.
bool DetectConfig(const uint8_t* stream, unsigned int size);
bool config_changed() const { return config_changed_; } bool config_changed() const { return config_changed_; }
VideoColorSpace current_color_space() const; protected:
private:
// These fields are used to track the SPS/PPS in the H.264 bitstream and
// are eventually compared against the SPS/PPS in the bitstream to detect
// a change.
int last_sps_id_;
std::vector<uint8_t> last_sps_;
int last_pps_id_;
std::vector<uint8_t> last_pps_;
// Set to true if we detect a stream configuration change. // Set to true if we detect a stream configuration change.
bool config_changed_; bool config_changed_ = false;
// We want to indicate configuration changes only after we see IDR slices.
// This flag tracks that we potentially have a configuration change which
// we want to honor after we see an IDR slice.
bool pending_config_changed_;
std::unique_ptr<H264Parser> parser_;
DISALLOW_COPY_AND_ASSIGN(H264ConfigChangeDetector);
}; };
// Class to provide a DXVA 2.0 based accelerator using the Microsoft Media // Class to provide a DXVA 2.0 based accelerator using the Microsoft Media
...@@ -584,7 +561,7 @@ class MEDIA_GPU_EXPORT DXVAVideoDecodeAccelerator ...@@ -584,7 +561,7 @@ class MEDIA_GPU_EXPORT DXVAVideoDecodeAccelerator
// when these changes occur then, the decoder works fine. The // when these changes occur then, the decoder works fine. The
// H264ConfigChangeDetector class provides functionality to check if the // H264ConfigChangeDetector class provides functionality to check if the
// stream configuration changed. // stream configuration changed.
std::unique_ptr<H264ConfigChangeDetector> config_change_detector_; std::unique_ptr<ConfigChangeDetector> config_change_detector_;
// Contains the initialization parameters for the video. // Contains the initialization parameters for the video.
Config config_; Config config_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment