Commit 8b444f9f authored by Khushal's avatar Khushal Committed by Commit Bot

media/android: Add plumbing for secure media using AImageReader.

Make sure we use the correct format/usage bits when using AImageReader
with videos requiring a secure surface.

R=liberato@chromium.org

Change-Id: I898535f38e1d2e8d1693c52e1e4c2aa01486cca8
Bug: 889328
Reviewed-on: https://chromium-review.googlesource.com/c/1428407Reviewed-by: default avatarFrank Liberato <liberato@chromium.org>
Reviewed-by: default avatarTommy Nyquist <nyquist@chromium.org>
Commit-Queue: Khushal <khushalsagar@chromium.org>
Auto-Submit: Khushal <khushalsagar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#626255}
parent 9f72579d
...@@ -84,6 +84,9 @@ using pAImageReader_delete = void (*)(AImageReader* reader); ...@@ -84,6 +84,9 @@ using pAImageReader_delete = void (*)(AImageReader* reader);
using pAImageReader_getWindow = media_status_t (*)(AImageReader* reader, using pAImageReader_getWindow = media_status_t (*)(AImageReader* reader,
ANativeWindow** window); ANativeWindow** window);
using pAImageReader_getFormat = media_status_t (*)(const AImageReader* reader,
int32_t* format);
using pAImageReader_acquireLatestImageAsync = using pAImageReader_acquireLatestImageAsync =
media_status_t (*)(AImageReader* reader, media_status_t (*)(AImageReader* reader,
AImage** image, AImage** image,
......
...@@ -70,6 +70,7 @@ bool AndroidImageReader::LoadFunctions() { ...@@ -70,6 +70,7 @@ bool AndroidImageReader::LoadFunctions() {
LOAD_FUNCTION(libmediandk, AImageReader_newWithUsage); LOAD_FUNCTION(libmediandk, AImageReader_newWithUsage);
LOAD_FUNCTION(libmediandk, AImageReader_setImageListener); LOAD_FUNCTION(libmediandk, AImageReader_setImageListener);
LOAD_FUNCTION(libmediandk, AImageReader_delete); LOAD_FUNCTION(libmediandk, AImageReader_delete);
LOAD_FUNCTION(libmediandk, AImageReader_getFormat);
LOAD_FUNCTION(libmediandk, AImageReader_getWindow); LOAD_FUNCTION(libmediandk, AImageReader_getWindow);
LOAD_FUNCTION(libmediandk, AImageReader_acquireLatestImageAsync); LOAD_FUNCTION(libmediandk, AImageReader_acquireLatestImageAsync);
...@@ -129,6 +130,12 @@ void AndroidImageReader::AImageReader_delete(AImageReader* reader) { ...@@ -129,6 +130,12 @@ void AndroidImageReader::AImageReader_delete(AImageReader* reader) {
AImageReader_delete_(reader); AImageReader_delete_(reader);
} }
media_status_t AndroidImageReader::AImageReader_getFormat(
const AImageReader* reader,
int32_t* format) {
return AImageReader_getFormat_(reader, format);
}
media_status_t AndroidImageReader::AImageReader_getWindow( media_status_t AndroidImageReader::AImageReader_getWindow(
AImageReader* reader, AImageReader* reader,
ANativeWindow** window) { ANativeWindow** window) {
......
...@@ -48,6 +48,8 @@ class BASE_EXPORT AndroidImageReader { ...@@ -48,6 +48,8 @@ class BASE_EXPORT AndroidImageReader {
AImageReader* reader, AImageReader* reader,
AImageReader_ImageListener* listener); AImageReader_ImageListener* listener);
void AImageReader_delete(AImageReader* reader); void AImageReader_delete(AImageReader* reader);
media_status_t AImageReader_getFormat(const AImageReader* reader,
int32_t* format);
media_status_t AImageReader_getWindow(AImageReader* reader, media_status_t AImageReader_getWindow(AImageReader* reader,
ANativeWindow** window); ANativeWindow** window);
media_status_t AImageReader_acquireLatestImageAsync(AImageReader* reader, media_status_t AImageReader_acquireLatestImageAsync(AImageReader* reader,
...@@ -71,6 +73,7 @@ class BASE_EXPORT AndroidImageReader { ...@@ -71,6 +73,7 @@ class BASE_EXPORT AndroidImageReader {
pAImageReader_newWithUsage AImageReader_newWithUsage_; pAImageReader_newWithUsage AImageReader_newWithUsage_;
pAImageReader_setImageListener AImageReader_setImageListener_; pAImageReader_setImageListener AImageReader_setImageListener_;
pAImageReader_delete AImageReader_delete_; pAImageReader_delete AImageReader_delete_;
pAImageReader_getFormat AImageReader_getFormat_;
pAImageReader_getWindow AImageReader_getWindow_; pAImageReader_getWindow AImageReader_getWindow_;
pAImageReader_acquireLatestImageAsync AImageReader_acquireLatestImageAsync_; pAImageReader_acquireLatestImageAsync AImageReader_acquireLatestImageAsync_;
pANativeWindow_toSurface ANativeWindow_toSurface_; pANativeWindow_toSurface ANativeWindow_toSurface_;
......
...@@ -63,7 +63,8 @@ bool AVDAPictureBufferManager::Initialize( ...@@ -63,7 +63,8 @@ bool AVDAPictureBufferManager::Initialize(
1, // depth 1, // depth
0, // border 0, // border
GL_RGBA, GL_UNSIGNED_BYTE); GL_RGBA, GL_UNSIGNED_BYTE);
texture_owner_ = TextureOwner::Create(std::move(texture)); texture_owner_ = TextureOwner::Create(std::move(texture),
TextureOwner::SecureMode::kInsecure);
if (!texture_owner_) if (!texture_owner_)
return false; return false;
......
...@@ -69,7 +69,8 @@ class ImageReaderGLOwner::ScopedHardwareBufferImpl ...@@ -69,7 +69,8 @@ class ImageReaderGLOwner::ScopedHardwareBufferImpl
}; };
ImageReaderGLOwner::ImageReaderGLOwner( ImageReaderGLOwner::ImageReaderGLOwner(
std::unique_ptr<gpu::gles2::AbstractTexture> texture) std::unique_ptr<gpu::gles2::AbstractTexture> texture,
SecureMode secure_mode)
: TextureOwner(std::move(texture)), : TextureOwner(std::move(texture)),
current_image_(nullptr), current_image_(nullptr),
loader_(base::android::AndroidImageReader::GetInstance()), loader_(base::android::AndroidImageReader::GetInstance()),
...@@ -79,18 +80,19 @@ ImageReaderGLOwner::ImageReaderGLOwner( ...@@ -79,18 +80,19 @@ ImageReaderGLOwner::ImageReaderGLOwner(
DCHECK(context_); DCHECK(context_);
DCHECK(surface_); DCHECK(surface_);
// TODO(khushalsagar): Need plumbing here to select the correct format and
// usage for secure media.
// Set the width, height and format to some default value. This parameters // Set the width, height and format to some default value. This parameters
// are/maybe overriden by the producer sending buffers to this imageReader's // are/maybe overriden by the producer sending buffers to this imageReader's
// Surface. // Surface.
int32_t width = 1, height = 1, max_images = 3; int32_t width = 1, height = 1, max_images = 3;
AIMAGE_FORMATS format = AIMAGE_FORMAT_YUV_420_888; AIMAGE_FORMATS format = secure_mode == SecureMode::kSecure
? AIMAGE_FORMAT_PRIVATE
: AIMAGE_FORMAT_YUV_420_888;
AImageReader* reader = nullptr; AImageReader* reader = nullptr;
// The usage flag below should be used when the buffer will be read from by // The usage flag below should be used when the buffer will be read from by
// the GPU as a texture. // the GPU as a texture.
const uint64_t usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; const uint64_t usage = secure_mode == SecureMode::kSecure
? AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT
: AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
// Create a new reader for images of the desired size and format. // Create a new reader for images of the desired size and format.
media_status_t return_code = loader_.AImageReader_newWithUsage( media_status_t return_code = loader_.AImageReader_newWithUsage(
......
...@@ -44,6 +44,8 @@ class MEDIA_GPU_EXPORT ImageReaderGLOwner : public TextureOwner { ...@@ -44,6 +44,8 @@ class MEDIA_GPU_EXPORT ImageReaderGLOwner : public TextureOwner {
std::unique_ptr<base::android::ScopedHardwareBufferFenceSync> std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
GetAHardwareBuffer() override; GetAHardwareBuffer() override;
const AImageReader* image_reader_for_testing() const { return image_reader_; }
protected: protected:
void OnTextureDestroyed(gpu::gles2::AbstractTexture*) override; void OnTextureDestroyed(gpu::gles2::AbstractTexture*) override;
...@@ -52,7 +54,8 @@ class MEDIA_GPU_EXPORT ImageReaderGLOwner : public TextureOwner { ...@@ -52,7 +54,8 @@ class MEDIA_GPU_EXPORT ImageReaderGLOwner : public TextureOwner {
class ScopedHardwareBufferImpl; class ScopedHardwareBufferImpl;
ImageReaderGLOwner(std::unique_ptr<gpu::gles2::AbstractTexture> texture); ImageReaderGLOwner(std::unique_ptr<gpu::gles2::AbstractTexture> texture,
SecureMode secure_mode);
~ImageReaderGLOwner() override; ~ImageReaderGLOwner() override;
// Deletes the current image if it has no pending refs. Returns false on // Deletes the current image if it has no pending refs. Returns false on
......
...@@ -6,11 +6,13 @@ ...@@ -6,11 +6,13 @@
#include <stdint.h> #include <stdint.h>
#include <memory> #include <memory>
#include <utility>
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "gpu/command_buffer/service/abstract_texture.h" #include "gpu/command_buffer/service/abstract_texture.h"
#include "media/base/media_switches.h" #include "media/base/media_switches.h"
#include "media/gpu/android/image_reader_gl_owner.h"
#include "media/gpu/android/mock_abstract_texture.h" #include "media/gpu/android/mock_abstract_texture.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/gl_bindings.h" #include "ui/gl/gl_bindings.h"
...@@ -27,6 +29,9 @@ class ImageReaderGLOwnerTest : public testing::Test { ...@@ -27,6 +29,9 @@ class ImageReaderGLOwnerTest : public testing::Test {
protected: protected:
void SetUp() override { void SetUp() override {
if (!IsImageReaderSupported())
return;
scoped_feature_list_.InitAndEnableFeature(media::kAImageReaderVideoOutput); scoped_feature_list_.InitAndEnableFeature(media::kAImageReaderVideoOutput);
gl::init::InitializeGLOneOffImplementation(gl::kGLImplementationEGLGLES2, gl::init::InitializeGLOneOffImplementation(gl::kGLImplementationEGLGLES2,
false, false, false, true); false, false, false, true);
...@@ -44,7 +49,11 @@ class ImageReaderGLOwnerTest : public testing::Test { ...@@ -44,7 +49,11 @@ class ImageReaderGLOwnerTest : public testing::Test {
std::unique_ptr<MockAbstractTexture> texture = std::unique_ptr<MockAbstractTexture> texture =
std::make_unique<MockAbstractTexture>(texture_id_); std::make_unique<MockAbstractTexture>(texture_id_);
abstract_texture_ = texture->AsWeakPtr(); abstract_texture_ = texture->AsWeakPtr();
image_reader_ = TextureOwner::Create(std::move(texture)); image_reader_ = TextureOwner::Create(std::move(texture), SecureMode());
}
virtual TextureOwner::SecureMode SecureMode() {
return TextureOwner::SecureMode::kInsecure;
} }
void TearDown() override { void TearDown() override {
...@@ -57,6 +66,10 @@ class ImageReaderGLOwnerTest : public testing::Test { ...@@ -57,6 +66,10 @@ class ImageReaderGLOwnerTest : public testing::Test {
gl::init::ShutdownGL(false); gl::init::ShutdownGL(false);
} }
bool IsImageReaderSupported() const {
return base::android::AndroidImageReader::GetInstance().IsSupported();
}
base::test::ScopedFeatureList scoped_feature_list_; base::test::ScopedFeatureList scoped_feature_list_;
scoped_refptr<TextureOwner> image_reader_; scoped_refptr<TextureOwner> image_reader_;
GLuint texture_id_ = 0; GLuint texture_id_ = 0;
...@@ -70,10 +83,16 @@ class ImageReaderGLOwnerTest : public testing::Test { ...@@ -70,10 +83,16 @@ class ImageReaderGLOwnerTest : public testing::Test {
}; };
TEST_F(ImageReaderGLOwnerTest, ImageReaderObjectCreation) { TEST_F(ImageReaderGLOwnerTest, ImageReaderObjectCreation) {
if (!IsImageReaderSupported())
return;
ASSERT_TRUE(image_reader_); ASSERT_TRUE(image_reader_);
} }
TEST_F(ImageReaderGLOwnerTest, ScopedJavaSurfaceCreation) { TEST_F(ImageReaderGLOwnerTest, ScopedJavaSurfaceCreation) {
if (!IsImageReaderSupported())
return;
gl::ScopedJavaSurface temp = image_reader_->CreateJavaSurface(); gl::ScopedJavaSurface temp = image_reader_->CreateJavaSurface();
ASSERT_TRUE(temp.IsValid()); ASSERT_TRUE(temp.IsValid());
} }
...@@ -81,6 +100,9 @@ TEST_F(ImageReaderGLOwnerTest, ScopedJavaSurfaceCreation) { ...@@ -81,6 +100,9 @@ TEST_F(ImageReaderGLOwnerTest, ScopedJavaSurfaceCreation) {
// Verify that ImageReaderGLOwner creates a bindable GL texture, and deletes // Verify that ImageReaderGLOwner creates a bindable GL texture, and deletes
// it during destruction. // it during destruction.
TEST_F(ImageReaderGLOwnerTest, GLTextureIsCreatedAndDestroyed) { TEST_F(ImageReaderGLOwnerTest, GLTextureIsCreatedAndDestroyed) {
if (!IsImageReaderSupported())
return;
// |texture_id| should not work anymore after we delete image_reader_. // |texture_id| should not work anymore after we delete image_reader_.
image_reader_ = nullptr; image_reader_ = nullptr;
EXPECT_FALSE(abstract_texture_); EXPECT_FALSE(abstract_texture_);
...@@ -88,12 +110,18 @@ TEST_F(ImageReaderGLOwnerTest, GLTextureIsCreatedAndDestroyed) { ...@@ -88,12 +110,18 @@ TEST_F(ImageReaderGLOwnerTest, GLTextureIsCreatedAndDestroyed) {
// Make sure that image_reader_ remembers the correct context and surface. // Make sure that image_reader_ remembers the correct context and surface.
TEST_F(ImageReaderGLOwnerTest, ContextAndSurfaceAreCaptured) { TEST_F(ImageReaderGLOwnerTest, ContextAndSurfaceAreCaptured) {
if (!IsImageReaderSupported())
return;
ASSERT_EQ(context_, image_reader_->GetContext()); ASSERT_EQ(context_, image_reader_->GetContext());
ASSERT_EQ(surface_, image_reader_->GetSurface()); ASSERT_EQ(surface_, image_reader_->GetSurface());
} }
// Verify that destruction works even if some other context is current. // Verify that destruction works even if some other context is current.
TEST_F(ImageReaderGLOwnerTest, DestructionWorksWithWrongContext) { TEST_F(ImageReaderGLOwnerTest, DestructionWorksWithWrongContext) {
if (!IsImageReaderSupported())
return;
scoped_refptr<gl::GLSurface> new_surface( scoped_refptr<gl::GLSurface> new_surface(
new gl::PbufferGLSurfaceEGL(gfx::Size(320, 240))); new gl::PbufferGLSurfaceEGL(gfx::Size(320, 240)));
new_surface->Initialize(); new_surface->Initialize();
...@@ -115,4 +143,24 @@ TEST_F(ImageReaderGLOwnerTest, DestructionWorksWithWrongContext) { ...@@ -115,4 +143,24 @@ TEST_F(ImageReaderGLOwnerTest, DestructionWorksWithWrongContext) {
new_surface = nullptr; new_surface = nullptr;
} }
class ImageReaderGLOwnerSecureTest : public ImageReaderGLOwnerTest {
public:
TextureOwner::SecureMode SecureMode() final {
return TextureOwner::SecureMode::kSecure;
}
};
TEST_F(ImageReaderGLOwnerSecureTest, CreatesSecureAImageReader) {
if (!IsImageReaderSupported())
return;
ASSERT_TRUE(image_reader_);
auto* a_image_reader = static_cast<ImageReaderGLOwner*>(image_reader_.get())
->image_reader_for_testing();
int32_t format = AIMAGE_FORMAT_YUV_420_888;
base::android::AndroidImageReader::GetInstance().AImageReader_getFormat(
a_image_reader, &format);
EXPECT_EQ(format, AIMAGE_FORMAT_PRIVATE);
}
} // namespace media } // namespace media
...@@ -388,19 +388,26 @@ void MediaCodecVideoDecoder::StartLazyInit() { ...@@ -388,19 +388,26 @@ void MediaCodecVideoDecoder::StartLazyInit() {
lazy_init_pending_ = false; lazy_init_pending_ = false;
codec_allocator_->StartThread(this); codec_allocator_->StartThread(this);
// SurfaceControl allows TextureOwner to be promoted to an overlay in the
// compositing pipeline itself.
const bool use_texture_owner_as_overlays = is_surface_control_enabled_;
// Only ask for promotion hints if we can actually switch surfaces, since we // Only ask for promotion hints if we can actually switch surfaces, since we
// wouldn't be able to do anything with them. Also, if threaded texture // wouldn't be able to do anything with them. Also, if threaded texture
// mailboxes are enabled, then we turn off overlays anyway. And if texture // mailboxes are enabled, then we turn off overlays anyway.
// owner can be used as an overlay, no promotion hints are necessary.
const bool want_promotion_hints = const bool want_promotion_hints =
device_info_->IsSetOutputSurfaceSupported() && device_info_->IsSetOutputSurfaceSupported() &&
!enable_threaded_texture_mailboxes_ && !use_texture_owner_as_overlays; !enable_threaded_texture_mailboxes_;
VideoFrameFactory::OverlayMode overlay_mode =
VideoFrameFactory::OverlayMode::kDontRequestPromotionHints;
if (is_surface_control_enabled_) {
overlay_mode =
requires_secure_codec_
? VideoFrameFactory::OverlayMode::kSurfaceControlSecure
: VideoFrameFactory::OverlayMode::kSurfaceControlInsecure;
} else if (want_promotion_hints) {
overlay_mode = VideoFrameFactory::OverlayMode::kRequestPromotionHints;
}
video_frame_factory_->Initialize( video_frame_factory_->Initialize(
want_promotion_hints, use_texture_owner_as_overlays, overlay_mode,
base::Bind(&MediaCodecVideoDecoder::OnVideoFrameFactoryInitialized, base::Bind(&MediaCodecVideoDecoder::OnVideoFrameFactoryInitialized,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
} }
......
...@@ -58,10 +58,7 @@ struct DestructionObservableMCVD : public DestructionObservable, ...@@ -58,10 +58,7 @@ struct DestructionObservableMCVD : public DestructionObservable,
class MockVideoFrameFactory : public VideoFrameFactory { class MockVideoFrameFactory : public VideoFrameFactory {
public: public:
MOCK_METHOD3(Initialize, MOCK_METHOD2(Initialize, void(OverlayMode overlay_mode, InitCb init_cb));
void(bool wants_promotion_hint,
bool use_texture_owner_as_overlay,
InitCb init_cb));
MOCK_METHOD1(MockSetSurfaceBundle, void(scoped_refptr<AVDASurfaceBundle>)); MOCK_METHOD1(MockSetSurfaceBundle, void(scoped_refptr<AVDASurfaceBundle>));
MOCK_METHOD5( MOCK_METHOD5(
MockCreateVideoFrame, MockCreateVideoFrame,
...@@ -143,10 +140,8 @@ class MediaCodecVideoDecoderTest : public testing::TestWithParam<VideoCodec> { ...@@ -143,10 +140,8 @@ class MediaCodecVideoDecoderTest : public testing::TestWithParam<VideoCodec> {
std::make_unique<NiceMock<MockVideoFrameFactory>>(); std::make_unique<NiceMock<MockVideoFrameFactory>>();
video_frame_factory_ = video_frame_factory.get(); video_frame_factory_ = video_frame_factory.get();
// Set up VFF to pass |texture_owner_| via its InitCb. // Set up VFF to pass |texture_owner_| via its InitCb.
const bool want_promotion_hint = ON_CALL(*video_frame_factory_, Initialize(ExpectedOverlayMode(), _))
device_info_->IsSetOutputSurfaceSupported(); .WillByDefault(RunCallback<1>(texture_owner));
ON_CALL(*video_frame_factory_, Initialize(want_promotion_hint, _, _))
.WillByDefault(RunCallback<2>(texture_owner));
auto* observable_mcvd = new DestructionObservableMCVD( auto* observable_mcvd = new DestructionObservableMCVD(
gpu_preferences_, gpu_feature_info_, device_info_.get(), gpu_preferences_, gpu_feature_info_, device_info_.get(),
...@@ -162,6 +157,14 @@ class MediaCodecVideoDecoderTest : public testing::TestWithParam<VideoCodec> { ...@@ -162,6 +157,14 @@ class MediaCodecVideoDecoderTest : public testing::TestWithParam<VideoCodec> {
destruction_observer_->ExpectDestruction(); destruction_observer_->ExpectDestruction();
} }
VideoFrameFactory::OverlayMode ExpectedOverlayMode() const {
const bool want_promotion_hint =
device_info_->IsSetOutputSurfaceSupported();
return want_promotion_hint
? VideoFrameFactory::OverlayMode::kRequestPromotionHints
: VideoFrameFactory::OverlayMode::kDontRequestPromotionHints;
}
void CreateCdm(bool has_media_crypto_context, void CreateCdm(bool has_media_crypto_context,
bool require_secure_video_decoder) { bool require_secure_video_decoder) {
cdm_ = std::make_unique<MockMediaCryptoContext>(has_media_crypto_context); cdm_ = std::make_unique<MockMediaCryptoContext>(has_media_crypto_context);
...@@ -309,7 +312,8 @@ TEST_P(MediaCodecVideoDecoderVp8Test, SmallVp8IsRejected) { ...@@ -309,7 +312,8 @@ TEST_P(MediaCodecVideoDecoderVp8Test, SmallVp8IsRejected) {
TEST_P(MediaCodecVideoDecoderTest, InitializeDoesntInitSurfaceOrCodec) { TEST_P(MediaCodecVideoDecoderTest, InitializeDoesntInitSurfaceOrCodec) {
CreateMcvd(); CreateMcvd();
EXPECT_CALL(*video_frame_factory_, Initialize(_, _, _)).Times(0); EXPECT_CALL(*video_frame_factory_, Initialize(ExpectedOverlayMode(), _))
.Times(0);
EXPECT_CALL(*surface_chooser_, MockUpdateState()).Times(0); EXPECT_CALL(*surface_chooser_, MockUpdateState()).Times(0);
EXPECT_CALL(*codec_allocator_, MockCreateMediaCodecAsync(_, _)).Times(0); EXPECT_CALL(*codec_allocator_, MockCreateMediaCodecAsync(_, _)).Times(0);
Initialize(TestVideoConfig::Large(codec_)); Initialize(TestVideoConfig::Large(codec_));
...@@ -317,7 +321,7 @@ TEST_P(MediaCodecVideoDecoderTest, InitializeDoesntInitSurfaceOrCodec) { ...@@ -317,7 +321,7 @@ TEST_P(MediaCodecVideoDecoderTest, InitializeDoesntInitSurfaceOrCodec) {
TEST_P(MediaCodecVideoDecoderTest, FirstDecodeTriggersFrameFactoryInit) { TEST_P(MediaCodecVideoDecoderTest, FirstDecodeTriggersFrameFactoryInit) {
Initialize(TestVideoConfig::Large(codec_)); Initialize(TestVideoConfig::Large(codec_));
EXPECT_CALL(*video_frame_factory_, Initialize(_, _, _)); EXPECT_CALL(*video_frame_factory_, Initialize(ExpectedOverlayMode(), _));
mcvd_->Decode(fake_decoder_buffer_, decode_cb_.Get()); mcvd_->Decode(fake_decoder_buffer_, decode_cb_.Get());
} }
...@@ -371,8 +375,8 @@ TEST_P(MediaCodecVideoDecoderTest, CodecIsCreatedAfterSurfaceChosen) { ...@@ -371,8 +375,8 @@ TEST_P(MediaCodecVideoDecoderTest, CodecIsCreatedAfterSurfaceChosen) {
TEST_P(MediaCodecVideoDecoderTest, FrameFactoryInitFailureIsAnError) { TEST_P(MediaCodecVideoDecoderTest, FrameFactoryInitFailureIsAnError) {
Initialize(TestVideoConfig::Large(codec_)); Initialize(TestVideoConfig::Large(codec_));
ON_CALL(*video_frame_factory_, Initialize(_, _, _)) ON_CALL(*video_frame_factory_, Initialize(ExpectedOverlayMode(), _))
.WillByDefault(RunCallback<2>(nullptr)); .WillByDefault(RunCallback<1>(nullptr));
EXPECT_CALL(decode_cb_, Run(DecodeStatus::DECODE_ERROR)).Times(1); EXPECT_CALL(decode_cb_, Run(DecodeStatus::DECODE_ERROR)).Times(1);
EXPECT_CALL(*surface_chooser_, MockUpdateState()).Times(0); EXPECT_CALL(*surface_chooser_, MockUpdateState()).Times(0);
mcvd_->Decode(fake_decoder_buffer_, decode_cb_.Get()); mcvd_->Decode(fake_decoder_buffer_, decode_cb_.Get());
......
...@@ -50,7 +50,8 @@ class SurfaceTextureGLOwnerTest : public testing::Test { ...@@ -50,7 +50,8 @@ class SurfaceTextureGLOwnerTest : public testing::Test {
std::unique_ptr<MockAbstractTexture> texture = std::unique_ptr<MockAbstractTexture> texture =
std::make_unique<MockAbstractTexture>(texture_id_); std::make_unique<MockAbstractTexture>(texture_id_);
abstract_texture_ = texture->AsWeakPtr(); abstract_texture_ = texture->AsWeakPtr();
surface_texture_ = SurfaceTextureGLOwner::Create(std::move(texture)); surface_texture_ = SurfaceTextureGLOwner::Create(
std::move(texture), TextureOwner::SecureMode::kInsecure);
texture_id_ = surface_texture_->GetTextureId(); texture_id_ = surface_texture_->GetTextureId();
EXPECT_TRUE(abstract_texture_); EXPECT_TRUE(abstract_texture_);
} }
......
...@@ -36,7 +36,8 @@ TextureOwner::~TextureOwner() { ...@@ -36,7 +36,8 @@ TextureOwner::~TextureOwner() {
// static // static
scoped_refptr<TextureOwner> TextureOwner::Create( scoped_refptr<TextureOwner> TextureOwner::Create(
std::unique_ptr<gpu::gles2::AbstractTexture> texture) { std::unique_ptr<gpu::gles2::AbstractTexture> texture,
SecureMode secure_mode) {
// Set the parameters on the texture. // Set the parameters on the texture.
texture->SetParameteri(GL_TEXTURE_MAG_FILTER, GL_LINEAR); texture->SetParameteri(GL_TEXTURE_MAG_FILTER, GL_LINEAR);
texture->SetParameteri(GL_TEXTURE_MIN_FILTER, GL_LINEAR); texture->SetParameteri(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
...@@ -46,10 +47,12 @@ scoped_refptr<TextureOwner> TextureOwner::Create( ...@@ -46,10 +47,12 @@ scoped_refptr<TextureOwner> TextureOwner::Create(
// If AImageReader is supported and is enabled by media flag, use it. // If AImageReader is supported and is enabled by media flag, use it.
if (base::android::AndroidImageReader::GetInstance().IsSupported() && if (base::android::AndroidImageReader::GetInstance().IsSupported() &&
base::FeatureList::IsEnabled(media::kAImageReaderVideoOutput)) { base::FeatureList::IsEnabled(media::kAImageReaderVideoOutput)) {
return new ImageReaderGLOwner(std::move(texture)); return new ImageReaderGLOwner(std::move(texture), secure_mode);
} }
// If not, fall back to legacy path. // If not, fall back to legacy path.
DCHECK_EQ(secure_mode, SecureMode::kInsecure)
<< "Can not use secure mode with SurfaceTexture";
return new SurfaceTextureGLOwner(std::move(texture)); return new SurfaceTextureGLOwner(std::move(texture));
} }
......
...@@ -45,8 +45,12 @@ class MEDIA_GPU_EXPORT TextureOwner ...@@ -45,8 +45,12 @@ class MEDIA_GPU_EXPORT TextureOwner
// new TextureOwner attached to it. Returns null on failure. // new TextureOwner attached to it. Returns null on failure.
// |texture| should be either from CreateAbstractTexture() or a mock. The // |texture| should be either from CreateAbstractTexture() or a mock. The
// corresponding GL context must be current. // corresponding GL context must be current.
// SecureMode indicates whether the video textures created using this owner
// should be hardware protected.
enum class SecureMode { kSecure, kInsecure };
static scoped_refptr<TextureOwner> Create( static scoped_refptr<TextureOwner> Create(
std::unique_ptr<gpu::gles2::AbstractTexture> texture); std::unique_ptr<gpu::gles2::AbstractTexture> texture,
SecureMode secure_mode);
// Create a texture that's appropriate for a TextureOwner. // Create a texture that's appropriate for a TextureOwner.
static std::unique_ptr<gpu::gles2::AbstractTexture> CreateTexture( static std::unique_ptr<gpu::gles2::AbstractTexture> CreateTexture(
......
...@@ -41,13 +41,22 @@ class MEDIA_GPU_EXPORT VideoFrameFactory { ...@@ -41,13 +41,22 @@ class MEDIA_GPU_EXPORT VideoFrameFactory {
// Initializes the factory and runs |init_cb| on the current thread when it's // Initializes the factory and runs |init_cb| on the current thread when it's
// complete. If initialization fails, the returned texture owner will be // complete. If initialization fails, the returned texture owner will be
// null. // null.
// |wants_promotion_hint| tells us whether to mark VideoFrames for compositor enum class OverlayMode {
// overlay promotion hints or not. // When using java overlays, the compositor can provide hints to the media
// |use_texture_owner_as_overlays| tells us whether TextureOwner can be used // pipeline to indicate whether the video can be promoted to an overlay.
// as an overlay, in which case java overlays will never be used. // This indicates whether promotion hints are needed, if framework support
virtual void Initialize(bool wants_promotion_hint, // for overlay promotion is available (requires MediaCodec.setOutputSurface
bool use_texture_owner_as_overlays, // support).
InitCb init_cb) = 0; kDontRequestPromotionHints,
kRequestPromotionHints,
// When using surface control, the factory should always use a TextureOwner
// since it can directly be promoted to an overlay on a frame-by-frame
// basis. The bits below indicate whether the media uses a secure codec.
kSurfaceControlSecure,
kSurfaceControlInsecure
};
virtual void Initialize(OverlayMode overlay_mode, InitCb init_cb) = 0;
// Notify us about the current surface bundle that subsequent video frames // Notify us about the current surface bundle that subsequent video frames
// should use. // should use.
......
...@@ -51,8 +51,7 @@ VideoFrameFactoryImpl::~VideoFrameFactoryImpl() { ...@@ -51,8 +51,7 @@ VideoFrameFactoryImpl::~VideoFrameFactoryImpl() {
gpu_task_runner_->DeleteSoon(FROM_HERE, gpu_video_frame_factory_.release()); gpu_task_runner_->DeleteSoon(FROM_HERE, gpu_video_frame_factory_.release());
} }
void VideoFrameFactoryImpl::Initialize(bool wants_promotion_hint, void VideoFrameFactoryImpl::Initialize(OverlayMode overlay_mode,
bool use_texture_owner_as_overlays,
InitCb init_cb) { InitCb init_cb) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!gpu_video_frame_factory_); DCHECK(!gpu_video_frame_factory_);
...@@ -60,8 +59,7 @@ void VideoFrameFactoryImpl::Initialize(bool wants_promotion_hint, ...@@ -60,8 +59,7 @@ void VideoFrameFactoryImpl::Initialize(bool wants_promotion_hint,
base::PostTaskAndReplyWithResult( base::PostTaskAndReplyWithResult(
gpu_task_runner_.get(), FROM_HERE, gpu_task_runner_.get(), FROM_HERE,
base::Bind(&GpuVideoFrameFactory::Initialize, base::Bind(&GpuVideoFrameFactory::Initialize,
base::Unretained(gpu_video_frame_factory_.get()), base::Unretained(gpu_video_frame_factory_.get()), overlay_mode,
wants_promotion_hint, use_texture_owner_as_overlays,
get_stub_cb_), get_stub_cb_),
std::move(init_cb)); std::move(init_cb));
} }
...@@ -132,12 +130,10 @@ GpuVideoFrameFactory::~GpuVideoFrameFactory() { ...@@ -132,12 +130,10 @@ GpuVideoFrameFactory::~GpuVideoFrameFactory() {
} }
scoped_refptr<TextureOwner> GpuVideoFrameFactory::Initialize( scoped_refptr<TextureOwner> GpuVideoFrameFactory::Initialize(
bool wants_promotion_hint, VideoFrameFactoryImpl::OverlayMode overlay_mode,
bool use_texture_owner_as_overlays,
VideoFrameFactoryImpl::GetStubCb get_stub_cb) { VideoFrameFactoryImpl::GetStubCb get_stub_cb) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
wants_promotion_hint_ = wants_promotion_hint; overlay_mode_ = overlay_mode;
use_texture_owner_as_overlays_ = use_texture_owner_as_overlays;
stub_ = get_stub_cb.Run(); stub_ = get_stub_cb.Run();
if (!MakeContextCurrent(stub_)) if (!MakeContextCurrent(stub_))
return nullptr; return nullptr;
...@@ -147,8 +143,12 @@ scoped_refptr<TextureOwner> GpuVideoFrameFactory::Initialize( ...@@ -147,8 +143,12 @@ scoped_refptr<TextureOwner> GpuVideoFrameFactory::Initialize(
decoder_helper_ = GLES2DecoderHelper::Create(stub_->decoder_context()); decoder_helper_ = GLES2DecoderHelper::Create(stub_->decoder_context());
auto secure_mode =
overlay_mode_ == VideoFrameFactory::OverlayMode::kSurfaceControlSecure
? TextureOwner::SecureMode::kSecure
: TextureOwner::SecureMode::kInsecure;
return TextureOwner::Create( return TextureOwner::Create(
TextureOwner::CreateTexture(stub_->decoder_context())); TextureOwner::CreateTexture(stub_->decoder_context()), secure_mode);
} }
void GpuVideoFrameFactory::CreateVideoFrame( void GpuVideoFrameFactory::CreateVideoFrame(
...@@ -283,21 +283,27 @@ void GpuVideoFrameFactory::CreateVideoFrameInternal( ...@@ -283,21 +283,27 @@ void GpuVideoFrameFactory::CreateVideoFrameInternal(
if (group->gpu_preferences().enable_threaded_texture_mailboxes) if (group->gpu_preferences().enable_threaded_texture_mailboxes)
frame->metadata()->SetBoolean(VideoFrameMetadata::COPY_REQUIRED, true); frame->metadata()->SetBoolean(VideoFrameMetadata::COPY_REQUIRED, true);
const bool is_surface_control =
overlay_mode_ == VideoFrameFactory::OverlayMode::kSurfaceControlSecure ||
overlay_mode_ == VideoFrameFactory::OverlayMode::kSurfaceControlInsecure;
const bool wants_promotion_hints =
overlay_mode_ == VideoFrameFactory::OverlayMode::kRequestPromotionHints;
bool allow_overlay = false; bool allow_overlay = false;
if (use_texture_owner_as_overlays_) { if (is_surface_control) {
DCHECK(texture_owner_); DCHECK(texture_owner_);
allow_overlay = true; allow_overlay = true;
} else { } else {
// We unconditionally mark the picture as overlayable, even if // We unconditionally mark the picture as overlayable, even if
// |!texture_owner_|, if we want to get hints. It's required, else we won't // |!texture_owner_|, if we want to get hints. It's required, else we won't
// get hints. // get hints.
allow_overlay = !texture_owner_ || wants_promotion_hint_; allow_overlay = !texture_owner_ || wants_promotion_hints;
} }
frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY,
allow_overlay); allow_overlay);
frame->metadata()->SetBoolean(VideoFrameMetadata::WANTS_PROMOTION_HINT, frame->metadata()->SetBoolean(VideoFrameMetadata::WANTS_PROMOTION_HINT,
wants_promotion_hint_); wants_promotion_hints);
frame->metadata()->SetBoolean(VideoFrameMetadata::TEXTURE_OWNER, frame->metadata()->SetBoolean(VideoFrameMetadata::TEXTURE_OWNER,
!!texture_owner_); !!texture_owner_);
......
...@@ -38,9 +38,7 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory { ...@@ -38,9 +38,7 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory {
GetStubCb get_stub_cb); GetStubCb get_stub_cb);
~VideoFrameFactoryImpl() override; ~VideoFrameFactoryImpl() override;
void Initialize(bool wants_promotion_hint, void Initialize(OverlayMode overlay_mode, InitCb init_cb) override;
bool use_texture_owner_as_overlays,
InitCb init_cb) override;
void SetSurfaceBundle( void SetSurfaceBundle(
scoped_refptr<AVDASurfaceBundle> surface_bundle) override; scoped_refptr<AVDASurfaceBundle> surface_bundle) override;
void CreateVideoFrame( void CreateVideoFrame(
...@@ -73,8 +71,7 @@ class GpuVideoFrameFactory ...@@ -73,8 +71,7 @@ class GpuVideoFrameFactory
~GpuVideoFrameFactory() override; ~GpuVideoFrameFactory() override;
scoped_refptr<TextureOwner> Initialize( scoped_refptr<TextureOwner> Initialize(
bool wants_promotion_hint, VideoFrameFactory::OverlayMode overlay_mode,
bool use_texture_owner_as_overlays,
VideoFrameFactory::GetStubCb get_stub_cb); VideoFrameFactory::GetStubCb get_stub_cb);
// Creates and returns a VideoFrame with its ReleaseMailboxCB. // Creates and returns a VideoFrame with its ReleaseMailboxCB.
...@@ -111,16 +108,13 @@ class GpuVideoFrameFactory ...@@ -111,16 +108,13 @@ class GpuVideoFrameFactory
// Outstanding images that should be considered for early rendering. // Outstanding images that should be considered for early rendering.
std::vector<CodecImage*> images_; std::vector<CodecImage*> images_;
gpu::CommandBufferStub* stub_; gpu::CommandBufferStub* stub_ = nullptr;
// Callback to notify us that an image has been destroyed. // Callback to notify us that an image has been destroyed.
CodecImage::DestructionCb destruction_cb_; CodecImage::DestructionCb destruction_cb_;
// Do we want promotion hints from the compositor? VideoFrameFactory::OverlayMode overlay_mode_ =
bool wants_promotion_hint_ = false; VideoFrameFactory::OverlayMode::kDontRequestPromotionHints;
// Indicates whether texture owner can be promoted to an overlay.
bool use_texture_owner_as_overlays_ = false;
// A helper for creating textures. Only valid while |stub_| is valid. // A helper for creating textures. Only valid while |stub_| is valid.
std::unique_ptr<GLES2DecoderHelper> decoder_helper_; std::unique_ptr<GLES2DecoderHelper> decoder_helper_;
......
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