OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/common/gpu/media/android_copying_backing_strategy.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/logging.h" | |
9 #include "base/trace_event/trace_event.h" | |
10 #include "content/common/gpu/media/avda_return_on_failure.h" | |
11 #include "gpu/command_buffer/service/context_group.h" | |
12 #include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h" | |
13 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" | |
14 #include "media/base/limits.h" | |
15 #include "media/video/picture.h" | |
16 #include "ui/gl/android/surface_texture.h" | |
17 #include "ui/gl/gl_bindings.h" | |
18 | |
19 namespace content { | |
20 | |
21 AndroidCopyingBackingStrategy::AndroidCopyingBackingStrategy( | |
22 AVDAStateProvider* state_provider) | |
23 : state_provider_(state_provider), | |
24 surface_texture_id_(0), | |
25 media_codec_(nullptr) {} | |
26 | |
27 AndroidCopyingBackingStrategy::~AndroidCopyingBackingStrategy() {} | |
28 | |
29 gfx::ScopedJavaSurface AndroidCopyingBackingStrategy::Initialize( | |
30 int surface_view_id) { | |
31 if (surface_view_id != media::VideoDecodeAccelerator::Config::kNoSurfaceID) { | |
32 LOG(ERROR) << "The copying strategy should not be initialized with a " | |
33 "surface id."; | |
34 return gfx::ScopedJavaSurface(); | |
35 } | |
36 | |
37 // Create a texture and attach the SurfaceTexture to it. | |
38 glGenTextures(1, &surface_texture_id_); | |
39 glActiveTexture(GL_TEXTURE0); | |
40 glBindTexture(GL_TEXTURE_EXTERNAL_OES, surface_texture_id_); | |
41 | |
42 // Note that the target will be correctly sized, so nearest filtering is all | |
43 // that's needed. | |
44 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
45 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
46 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
47 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
48 | |
49 state_provider_->GetGlDecoder()->RestoreTextureUnitBindings(0); | |
50 state_provider_->GetGlDecoder()->RestoreActiveTexture(); | |
51 | |
52 surface_texture_ = gfx::SurfaceTexture::Create(surface_texture_id_); | |
53 | |
54 return gfx::ScopedJavaSurface(surface_texture_.get()); | |
55 } | |
56 | |
57 void AndroidCopyingBackingStrategy::Cleanup( | |
58 bool have_context, | |
59 const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) { | |
60 DCHECK(state_provider_->ThreadChecker().CalledOnValidThread()); | |
61 | |
62 if (copier_) | |
63 copier_->Destroy(); | |
64 | |
65 if (surface_texture_id_ && have_context) | |
66 glDeleteTextures(1, &surface_texture_id_); | |
67 } | |
68 | |
69 scoped_refptr<gfx::SurfaceTexture> | |
70 AndroidCopyingBackingStrategy::GetSurfaceTexture() const { | |
71 return surface_texture_; | |
72 } | |
73 | |
74 uint32_t AndroidCopyingBackingStrategy::GetTextureTarget() const { | |
75 return GL_TEXTURE_2D; | |
76 } | |
77 | |
78 gfx::Size AndroidCopyingBackingStrategy::GetPictureBufferSize() const { | |
79 return state_provider_->GetSize(); | |
80 } | |
81 | |
82 void AndroidCopyingBackingStrategy::UseCodecBufferForPictureBuffer( | |
83 int32_t codec_buf_index, | |
84 const media::PictureBuffer& picture_buffer) { | |
85 // Make sure that the decoder is available. | |
86 RETURN_ON_FAILURE(state_provider_, state_provider_->GetGlDecoder().get(), | |
87 "Failed to get gles2 decoder instance.", ILLEGAL_STATE); | |
88 | |
89 // Render the codec buffer into |surface_texture_|, and switch it to be | |
90 // the front buffer. | |
91 // This ignores the emitted ByteBuffer and instead relies on rendering to | |
92 // the codec's SurfaceTexture and then copying from that texture to the | |
93 // client's PictureBuffer's texture. This means that each picture's data | |
94 // is written three times: once to the ByteBuffer, once to the | |
95 // SurfaceTexture, and once to the client's texture. It would be nicer to | |
96 // either: | |
97 // 1) Render directly to the client's texture from MediaCodec (one write); | |
98 // or | |
99 // 2) Upload the ByteBuffer to the client's texture (two writes). | |
100 // Unfortunately neither is possible: | |
101 // 1) MediaCodec's use of SurfaceTexture is a singleton, and the texture | |
102 // written to can't change during the codec's lifetime. b/11990461 | |
103 // 2) The ByteBuffer is likely to contain the pixels in a vendor-specific, | |
104 // opaque/non-standard format. It's not possible to negotiate the | |
105 // decoder to emit a specific colorspace, even using HW CSC. b/10706245 | |
106 // So, we live with these two extra copies per picture :( | |
107 { | |
108 TRACE_EVENT0("media", "AVDA::ReleaseOutputBuffer"); | |
109 media_codec_->ReleaseOutputBuffer(codec_buf_index, true); | |
110 } | |
111 | |
112 { | |
113 TRACE_EVENT0("media", "AVDA::UpdateTexImage"); | |
114 surface_texture_->UpdateTexImage(); | |
115 } | |
116 | |
117 float transform_matrix[16]; | |
118 surface_texture_->GetTransformMatrix(transform_matrix); | |
119 | |
120 DCHECK_LE(1u, picture_buffer.texture_ids().size()); | |
121 uint32_t picture_buffer_texture_id = picture_buffer.texture_ids()[0]; | |
122 | |
123 // Defer initializing the CopyTextureCHROMIUMResourceManager until it is | |
124 // needed because it takes 10s of milliseconds to initialize. | |
125 if (!copier_) { | |
126 copier_.reset(new gpu::CopyTextureCHROMIUMResourceManager()); | |
127 copier_->Initialize(state_provider_->GetGlDecoder().get(), | |
128 state_provider_->GetGlDecoder()->GetContextGroup()-> | |
129 feature_info()->feature_flags()); | |
130 } | |
131 | |
132 // Here, we copy |surface_texture_id_| to the picture buffer instead of | |
133 // setting new texture to |surface_texture_| by calling attachToGLContext() | |
134 // because: | |
135 // 1. Once we call detachFrameGLContext(), it deletes the texture previously | |
136 // attached. | |
137 // 2. SurfaceTexture requires us to apply a transform matrix when we show | |
138 // the texture. | |
139 copier_->DoCopyTextureWithTransform( | |
140 state_provider_->GetGlDecoder().get(), GL_TEXTURE_EXTERNAL_OES, | |
141 surface_texture_id_, GL_TEXTURE_2D, picture_buffer_texture_id, | |
142 state_provider_->GetSize().width(), state_provider_->GetSize().height(), | |
143 true, false, false, transform_matrix); | |
144 } | |
145 | |
146 void AndroidCopyingBackingStrategy::CodecChanged( | |
147 media::VideoCodecBridge* codec) { | |
148 media_codec_ = codec; | |
149 } | |
150 | |
151 void AndroidCopyingBackingStrategy::OnFrameAvailable() { | |
152 // TODO(liberato): crbug.com/574948 . The OnFrameAvailable logic can be | |
153 // moved into AVDA, and we should wait for it before doing the copy. | |
154 // Because there were some test failures, we don't do this now but | |
155 // instead preserve the old behavior. | |
156 } | |
157 | |
158 bool AndroidCopyingBackingStrategy::ArePicturesOverlayable() { | |
159 return false; | |
160 } | |
161 | |
162 void AndroidCopyingBackingStrategy::UpdatePictureBufferSize( | |
163 media::PictureBuffer* picture_buffer, | |
164 const gfx::Size& new_size) { | |
165 // This strategy uses 2D textures who's allocated memory is dependent on the | |
166 // size. To update size in all places, we must: | |
167 // 1) Update the PictureBuffer meta-data | |
168 picture_buffer->set_size(new_size); | |
169 | |
170 // 2) Update the GL texture via glTexImage2D. This step assumes the caller | |
171 // has made our GL context current. | |
172 DCHECK_LE(1u, picture_buffer->texture_ids().size()); | |
173 glBindTexture(GL_TEXTURE_2D, picture_buffer->texture_ids()[0]); | |
174 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, new_size.width(), new_size.height(), | |
175 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); | |
176 state_provider_->GetGlDecoder()->RestoreActiveTextureUnitBinding( | |
177 GL_TEXTURE_2D); | |
178 | |
179 // 3) Update the CHROMIUM Texture's size. | |
180 gpu::gles2::TextureRef* texture_ref = | |
181 state_provider_->GetTextureForPicture(*picture_buffer); | |
182 RETURN_IF_NULL(texture_ref); | |
183 gpu::gles2::TextureManager* texture_manager = | |
184 state_provider_->GetGlDecoder()->GetContextGroup()->texture_manager(); | |
185 RETURN_IF_NULL(texture_manager); | |
186 texture_manager->SetLevelInfo(texture_ref, GetTextureTarget(), 0, GL_RGBA, | |
187 new_size.width(), new_size.height(), 1, 0, | |
188 GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(new_size)); | |
189 } | |
190 | |
191 } // namespace content | |
OLD | NEW |