OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/common/gpu/client/gpu_video_encode_accelerator_host.h" | 5 #include "content/common/gpu/client/gpu_video_encode_accelerator_host.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/message_loop/message_loop_proxy.h" | 8 #include "base/message_loop/message_loop_proxy.h" |
9 #include "content/common/gpu/client/gpu_channel_host.h" | 9 #include "content/common/gpu/client/gpu_channel_host.h" |
10 #include "content/common/gpu/gpu_messages.h" | 10 #include "content/common/gpu/gpu_messages.h" |
11 #include "content/common/gpu/media/gpu_video_encode_accelerator.h" | 11 #include "content/common/gpu/media/gpu_video_encode_accelerator.h" |
12 #include "media/base/video_frame.h" | 12 #include "media/base/video_frame.h" |
13 | 13 |
14 namespace content { | 14 namespace content { |
15 | 15 |
16 #define NOTIFY_ERROR(error) \ | |
17 PostNotifyError(error); \ | |
18 DLOG(ERROR) | |
19 | |
16 GpuVideoEncodeAcceleratorHost::GpuVideoEncodeAcceleratorHost( | 20 GpuVideoEncodeAcceleratorHost::GpuVideoEncodeAcceleratorHost( |
17 const scoped_refptr<GpuChannelHost>& gpu_channel_host, | 21 GpuChannelHost* channel, |
18 int32 route_id) | 22 CommandBufferProxyImpl* impl) |
19 : client_(NULL), | 23 : channel_(channel), |
20 channel_(gpu_channel_host), | 24 encoder_route_id_(-1), |
21 route_id_(route_id), | 25 client_(NULL), |
22 next_frame_id_(0) { | 26 impl_(impl), |
23 channel_->AddRoute(route_id_, AsWeakPtr()); | 27 next_frame_id_(0), |
28 weak_this_factory_(this) { | |
29 DCHECK(channel_); | |
30 DCHECK(impl_); | |
31 impl_->AddDeletionObserver(this); | |
24 } | 32 } |
25 | 33 |
26 GpuVideoEncodeAcceleratorHost::~GpuVideoEncodeAcceleratorHost() { | 34 GpuVideoEncodeAcceleratorHost::~GpuVideoEncodeAcceleratorHost() { |
35 DCHECK(CalledOnValidThread()); | |
27 if (channel_) | 36 if (channel_) |
28 channel_->RemoveRoute(route_id_); | 37 channel_->RemoveRoute(encoder_route_id_); |
38 if (impl_) | |
39 impl_->RemoveDeletionObserver(this); | |
29 } | 40 } |
30 | 41 |
31 // static | 42 // static |
32 std::vector<media::VideoEncodeAccelerator::SupportedProfile> | 43 std::vector<media::VideoEncodeAccelerator::SupportedProfile> |
33 GpuVideoEncodeAcceleratorHost::GetSupportedProfiles() { | 44 GpuVideoEncodeAcceleratorHost::GetSupportedProfiles() { |
34 return GpuVideoEncodeAccelerator::GetSupportedProfiles(); | 45 return GpuVideoEncodeAccelerator::GetSupportedProfiles(); |
35 } | 46 } |
36 | 47 |
37 bool GpuVideoEncodeAcceleratorHost::OnMessageReceived( | 48 bool GpuVideoEncodeAcceleratorHost::OnMessageReceived( |
38 const IPC::Message& message) { | 49 const IPC::Message& message) { |
39 bool handled = true; | 50 bool handled = true; |
40 IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAcceleratorHost, message) | 51 IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAcceleratorHost, message) |
41 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyInitializeDone, | |
42 OnNotifyInitializeDone) | |
43 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers, | 52 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers, |
44 OnRequireBitstreamBuffers) | 53 OnRequireBitstreamBuffers) |
45 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyInputDone, | 54 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyInputDone, |
46 OnNotifyInputDone) | 55 OnNotifyInputDone) |
47 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_BitstreamBufferReady, | 56 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_BitstreamBufferReady, |
48 OnBitstreamBufferReady) | 57 OnBitstreamBufferReady) |
49 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyError, | 58 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyError, |
50 OnNotifyError) | 59 OnNotifyError) |
51 IPC_MESSAGE_UNHANDLED(handled = false) | 60 IPC_MESSAGE_UNHANDLED(handled = false) |
52 IPC_END_MESSAGE_MAP() | 61 IPC_END_MESSAGE_MAP() |
53 DCHECK(handled); | 62 DCHECK(handled); |
54 // See OnNotifyError for why |this| mustn't be used after OnNotifyError might | 63 // See OnNotifyError for why |this| mustn't be used after OnNotifyError might |
55 // have been called above. | 64 // have been called above. |
56 return handled; | 65 return handled; |
57 } | 66 } |
58 | 67 |
59 void GpuVideoEncodeAcceleratorHost::OnChannelError() { | 68 void GpuVideoEncodeAcceleratorHost::OnChannelError() { |
69 DCHECK(CalledOnValidThread()); | |
70 if (channel_) { | |
71 channel_->RemoveRoute(encoder_route_id_); | |
72 channel_ = NULL; | |
73 weak_this_factory_.InvalidateWeakPtrs(); | |
74 } | |
60 DLOG(ERROR) << "OnChannelError()"; | 75 DLOG(ERROR) << "OnChannelError()"; |
Ami GONE FROM CHROMIUM
2014/03/18 23:53:19
Don't you want to notify the client in case of cha
sheu
2014/03/19 20:38:24
Oh, right. I was thinking for some reason this wa
| |
61 if (channel_) { | |
62 channel_->RemoveRoute(route_id_); | |
63 channel_ = NULL; | |
64 } | |
65 // See OnNotifyError for why this needs to be the last thing in this | |
66 // function. | |
67 OnNotifyError(kPlatformFailureError); | |
68 } | 76 } |
69 | 77 |
70 void GpuVideoEncodeAcceleratorHost::Initialize( | 78 bool GpuVideoEncodeAcceleratorHost::Initialize( |
71 media::VideoFrame::Format input_format, | 79 media::VideoFrame::Format input_format, |
72 const gfx::Size& input_visible_size, | 80 const gfx::Size& input_visible_size, |
73 media::VideoCodecProfile output_profile, | 81 media::VideoCodecProfile output_profile, |
74 uint32 initial_bitrate, | 82 uint32 initial_bitrate, |
75 Client* client) { | 83 Client* client) { |
84 DCHECK(CalledOnValidThread()); | |
76 client_ = client; | 85 client_ = client; |
77 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client_)); | 86 if (!impl_) { |
78 Send(new AcceleratedVideoEncoderMsg_Initialize(route_id_, | 87 DLOG(ERROR) << "impl_ destroyed"; |
79 input_format, | 88 return false; |
80 input_visible_size, | 89 } |
81 output_profile, | 90 Send(new GpuCommandBufferMsg_CreateVideoEncoder(impl_->GetRouteID(), |
82 initial_bitrate)); | 91 input_format, |
92 input_visible_size, | |
93 output_profile, | |
94 initial_bitrate, | |
95 &encoder_route_id_)); | |
96 if (encoder_route_id_ < 0) { | |
97 DLOG(ERROR) << "Send(GpuCommandBufferMsg_CreateVideoEncoder()) failed"; | |
98 return false; | |
99 } | |
100 channel_->AddRoute(encoder_route_id_, weak_this_factory_.GetWeakPtr()); | |
101 return true; | |
83 } | 102 } |
84 | 103 |
85 void GpuVideoEncodeAcceleratorHost::Encode( | 104 void GpuVideoEncodeAcceleratorHost::Encode( |
86 const scoped_refptr<media::VideoFrame>& frame, | 105 const scoped_refptr<media::VideoFrame>& frame, |
87 bool force_keyframe) { | 106 bool force_keyframe) { |
107 DCHECK(CalledOnValidThread()); | |
88 if (!channel_) | 108 if (!channel_) |
89 return; | 109 return; |
110 | |
90 if (!base::SharedMemory::IsHandleValid(frame->shared_memory_handle())) { | 111 if (!base::SharedMemory::IsHandleValid(frame->shared_memory_handle())) { |
91 DLOG(ERROR) << "Encode(): cannot encode frame not backed by shared memory"; | 112 NOTIFY_ERROR(kPlatformFailureError) |
92 NotifyError(kPlatformFailureError); | 113 << "Encode(): cannot encode frame not backed by shared memory"; |
93 return; | 114 return; |
94 } | 115 } |
95 base::SharedMemoryHandle handle = | 116 base::SharedMemoryHandle handle = |
96 channel_->ShareToGpuProcess(frame->shared_memory_handle()); | 117 channel_->ShareToGpuProcess(frame->shared_memory_handle()); |
97 if (!base::SharedMemory::IsHandleValid(handle)) { | 118 if (!base::SharedMemory::IsHandleValid(handle)) { |
98 DLOG(ERROR) << "Encode(): failed to duplicate buffer handle for GPU " | 119 NOTIFY_ERROR(kPlatformFailureError) |
99 "process"; | 120 << "Encode(): failed to duplicate buffer handle for GPU process"; |
100 NotifyError(kPlatformFailureError); | |
101 return; | 121 return; |
102 } | 122 } |
103 | 123 |
104 // We assume that planar frame data passed here is packed and contiguous. | 124 // We assume that planar frame data passed here is packed and contiguous. |
105 const size_t plane_count = media::VideoFrame::NumPlanes(frame->format()); | 125 const size_t plane_count = media::VideoFrame::NumPlanes(frame->format()); |
106 size_t frame_size = 0; | 126 size_t frame_size = 0; |
107 for (size_t i = 0; i < plane_count; ++i) { | 127 for (size_t i = 0; i < plane_count; ++i) { |
108 // Cast DCHECK parameters to void* to avoid printing uint8* as a string. | 128 // Cast DCHECK parameters to void* to avoid printing uint8* as a string. |
109 DCHECK_EQ(reinterpret_cast<void*>(frame->data(i)), | 129 DCHECK_EQ(reinterpret_cast<void*>(frame->data(i)), |
110 reinterpret_cast<void*>((frame->data(0) + frame_size))) | 130 reinterpret_cast<void*>((frame->data(0) + frame_size))) |
111 << "plane=" << i; | 131 << "plane=" << i; |
112 frame_size += frame->stride(i) * frame->rows(i); | 132 frame_size += frame->stride(i) * frame->rows(i); |
113 } | 133 } |
114 | 134 |
115 Send(new AcceleratedVideoEncoderMsg_Encode( | 135 Send(new AcceleratedVideoEncoderMsg_Encode( |
116 route_id_, next_frame_id_, handle, frame_size, force_keyframe)); | 136 encoder_route_id_, next_frame_id_, handle, frame_size, force_keyframe)); |
117 frame_map_[next_frame_id_] = frame; | 137 frame_map_[next_frame_id_] = frame; |
118 | 138 |
119 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. | 139 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. |
120 next_frame_id_ = (next_frame_id_ + 1) & 0x3FFFFFFF; | 140 next_frame_id_ = (next_frame_id_ + 1) & 0x3FFFFFFF; |
121 } | 141 } |
122 | 142 |
123 void GpuVideoEncodeAcceleratorHost::UseOutputBitstreamBuffer( | 143 void GpuVideoEncodeAcceleratorHost::UseOutputBitstreamBuffer( |
124 const media::BitstreamBuffer& buffer) { | 144 const media::BitstreamBuffer& buffer) { |
145 DCHECK(CalledOnValidThread()); | |
125 if (!channel_) | 146 if (!channel_) |
126 return; | 147 return; |
148 | |
127 base::SharedMemoryHandle handle = | 149 base::SharedMemoryHandle handle = |
128 channel_->ShareToGpuProcess(buffer.handle()); | 150 channel_->ShareToGpuProcess(buffer.handle()); |
129 if (!base::SharedMemory::IsHandleValid(handle)) { | 151 if (!base::SharedMemory::IsHandleValid(handle)) { |
130 DLOG(ERROR) << "UseOutputBitstreamBuffer(): failed to duplicate buffer " | 152 NOTIFY_ERROR(kPlatformFailureError) |
131 "handle for GPU process: buffer.id()=" << buffer.id(); | 153 << "UseOutputBitstreamBuffer(): failed to duplicate buffer handle " |
132 NotifyError(kPlatformFailureError); | 154 "for GPU process: buffer.id()=" << buffer.id(); |
133 return; | 155 return; |
134 } | 156 } |
135 Send(new AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer( | 157 Send(new AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer( |
136 route_id_, buffer.id(), handle, buffer.size())); | 158 encoder_route_id_, buffer.id(), handle, buffer.size())); |
137 } | 159 } |
138 | 160 |
139 void GpuVideoEncodeAcceleratorHost::RequestEncodingParametersChange( | 161 void GpuVideoEncodeAcceleratorHost::RequestEncodingParametersChange( |
140 uint32 bitrate, | 162 uint32 bitrate, |
141 uint32 framerate) { | 163 uint32 framerate) { |
164 DCHECK(CalledOnValidThread()); | |
165 if (!channel_) | |
166 return; | |
167 | |
142 Send(new AcceleratedVideoEncoderMsg_RequestEncodingParametersChange( | 168 Send(new AcceleratedVideoEncoderMsg_RequestEncodingParametersChange( |
143 route_id_, bitrate, framerate)); | 169 encoder_route_id_, bitrate, framerate)); |
144 } | 170 } |
145 | 171 |
146 void GpuVideoEncodeAcceleratorHost::Destroy() { | 172 void GpuVideoEncodeAcceleratorHost::Destroy() { |
147 Send(new GpuChannelMsg_DestroyVideoEncoder(route_id_)); | 173 DCHECK(CalledOnValidThread()); |
174 if (channel_) | |
175 Send(new AcceleratedVideoEncoderMsg_Destroy(encoder_route_id_)); | |
176 client_ = NULL; | |
148 delete this; | 177 delete this; |
149 } | 178 } |
150 | 179 |
151 void GpuVideoEncodeAcceleratorHost::NotifyError(Error error) { | 180 void GpuVideoEncodeAcceleratorHost::OnWillDeleteImpl() { |
152 DVLOG(2) << "NotifyError(): error=" << error; | 181 DCHECK(CalledOnValidThread()); |
182 impl_ = NULL; | |
183 | |
184 // The CommandBufferProxyImpl is going away; error out this VEA. | |
185 OnChannelError(); | |
186 } | |
187 | |
188 void GpuVideoEncodeAcceleratorHost::PostNotifyError(Error error) { | |
189 DCHECK(CalledOnValidThread()); | |
190 DVLOG(2) << "PostNotifyError(): error=" << error; | |
191 // Post the error notification back to this thread, to avoid re-entrancy. | |
153 base::MessageLoopProxy::current()->PostTask( | 192 base::MessageLoopProxy::current()->PostTask( |
154 FROM_HERE, | 193 FROM_HERE, |
155 base::Bind(&media::VideoEncodeAccelerator::Client::NotifyError, | 194 base::Bind(&GpuVideoEncodeAcceleratorHost::OnNotifyError, |
156 client_ptr_factory_->GetWeakPtr(), | 195 weak_this_factory_.GetWeakPtr(), |
157 error)); | 196 error)); |
158 } | 197 } |
159 | 198 |
160 void GpuVideoEncodeAcceleratorHost::OnNotifyInitializeDone() { | 199 void GpuVideoEncodeAcceleratorHost::Send(IPC::Message* message) { |
161 DVLOG(2) << "OnNotifyInitializeDone()"; | 200 DCHECK(CalledOnValidThread()); |
162 if (client_) | 201 uint32 message_type = message->type(); |
163 client_->NotifyInitializeDone(); | 202 if (!channel_->Send(message)) { |
203 NOTIFY_ERROR(kPlatformFailureError) << "Send(" << message_type | |
204 << ") failed"; | |
205 } | |
164 } | 206 } |
165 | 207 |
166 void GpuVideoEncodeAcceleratorHost::OnRequireBitstreamBuffers( | 208 void GpuVideoEncodeAcceleratorHost::OnRequireBitstreamBuffers( |
167 uint32 input_count, | 209 uint32 input_count, |
168 const gfx::Size& input_coded_size, | 210 const gfx::Size& input_coded_size, |
169 uint32 output_buffer_size) { | 211 uint32 output_buffer_size) { |
212 DCHECK(CalledOnValidThread()); | |
170 DVLOG(2) << "OnRequireBitstreamBuffers(): input_count=" << input_count | 213 DVLOG(2) << "OnRequireBitstreamBuffers(): input_count=" << input_count |
171 << ", input_coded_size=" << input_coded_size.ToString() | 214 << ", input_coded_size=" << input_coded_size.ToString() |
172 << ", output_buffer_size=" << output_buffer_size; | 215 << ", output_buffer_size=" << output_buffer_size; |
173 if (client_) { | 216 if (client_) { |
174 client_->RequireBitstreamBuffers( | 217 client_->RequireBitstreamBuffers( |
175 input_count, input_coded_size, output_buffer_size); | 218 input_count, input_coded_size, output_buffer_size); |
176 } | 219 } |
177 } | 220 } |
178 | 221 |
179 void GpuVideoEncodeAcceleratorHost::OnNotifyInputDone(int32 frame_id) { | 222 void GpuVideoEncodeAcceleratorHost::OnNotifyInputDone(int32 frame_id) { |
223 DCHECK(CalledOnValidThread()); | |
180 DVLOG(3) << "OnNotifyInputDone(): frame_id=" << frame_id; | 224 DVLOG(3) << "OnNotifyInputDone(): frame_id=" << frame_id; |
181 // Fun-fact: std::hash_map is not spec'd to be re-entrant; since freeing a | 225 // Fun-fact: std::hash_map is not spec'd to be re-entrant; since freeing a |
182 // frame can trigger a further encode to be kicked off and thus an .insert() | 226 // frame can trigger a further encode to be kicked off and thus an .insert() |
183 // back into the map, we separate the frame's dtor running from the .erase() | 227 // back into the map, we separate the frame's dtor running from the .erase() |
184 // running by holding on to the frame temporarily. This isn't "just | 228 // running by holding on to the frame temporarily. This isn't "just |
185 // theoretical" - Android's std::hash_map crashes if we don't do this. | 229 // theoretical" - Android's std::hash_map crashes if we don't do this. |
186 scoped_refptr<media::VideoFrame> frame = frame_map_[frame_id]; | 230 scoped_refptr<media::VideoFrame> frame = frame_map_[frame_id]; |
187 if (!frame_map_.erase(frame_id)) { | 231 if (!frame_map_.erase(frame_id)) { |
188 DLOG(ERROR) << "OnNotifyInputDone(): " | 232 DLOG(ERROR) << "OnNotifyInputDone(): " |
189 "invalid frame_id=" << frame_id; | 233 "invalid frame_id=" << frame_id; |
190 // See OnNotifyError for why this needs to be the last thing in this | 234 // See OnNotifyError for why this needs to be the last thing in this |
191 // function. | 235 // function. |
192 OnNotifyError(kPlatformFailureError); | 236 OnNotifyError(kPlatformFailureError); |
193 return; | 237 return; |
194 } | 238 } |
195 frame = NULL; // Not necessary but nice to be explicit; see fun-fact above. | 239 frame = NULL; // Not necessary but nice to be explicit; see fun-fact above. |
196 } | 240 } |
197 | 241 |
198 void GpuVideoEncodeAcceleratorHost::OnBitstreamBufferReady( | 242 void GpuVideoEncodeAcceleratorHost::OnBitstreamBufferReady( |
199 int32 bitstream_buffer_id, | 243 int32 bitstream_buffer_id, |
200 uint32 payload_size, | 244 uint32 payload_size, |
201 bool key_frame) { | 245 bool key_frame) { |
246 DCHECK(CalledOnValidThread()); | |
202 DVLOG(3) << "OnBitstreamBufferReady(): " | 247 DVLOG(3) << "OnBitstreamBufferReady(): " |
203 "bitstream_buffer_id=" << bitstream_buffer_id | 248 "bitstream_buffer_id=" << bitstream_buffer_id |
204 << ", payload_size=" << payload_size | 249 << ", payload_size=" << payload_size |
205 << ", key_frame=" << key_frame; | 250 << ", key_frame=" << key_frame; |
206 if (client_) | 251 if (client_) |
207 client_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame); | 252 client_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame); |
208 } | 253 } |
209 | 254 |
210 void GpuVideoEncodeAcceleratorHost::OnNotifyError(Error error) { | 255 void GpuVideoEncodeAcceleratorHost::OnNotifyError(Error error) { |
256 DCHECK(CalledOnValidThread()); | |
211 DVLOG(2) << "OnNotifyError(): error=" << error; | 257 DVLOG(2) << "OnNotifyError(): error=" << error; |
212 if (!client_) | 258 if (!client_) |
213 return; | 259 return; |
214 client_ptr_factory_.reset(); | |
215 | 260 |
216 // Client::NotifyError() may Destroy() |this|, so calling it needs to be the | 261 // Client::NotifyError() may Destroy() |this|, so calling it needs to be the |
217 // last thing done on this stack! | 262 // last thing done on this stack! |
218 media::VideoEncodeAccelerator::Client* client = NULL; | 263 media::VideoEncodeAccelerator::Client* client = NULL; |
219 std::swap(client_, client); | 264 std::swap(client_, client); |
220 client->NotifyError(error); | 265 client->NotifyError(error); |
221 } | 266 } |
222 | 267 |
223 void GpuVideoEncodeAcceleratorHost::Send(IPC::Message* message) { | |
224 if (!channel_) { | |
225 DLOG(ERROR) << "Send(): no channel"; | |
226 delete message; | |
227 NotifyError(kPlatformFailureError); | |
228 } else if (!channel_->Send(message)) { | |
229 DLOG(ERROR) << "Send(): sending failed: message->type()=" | |
230 << message->type(); | |
231 NotifyError(kPlatformFailureError); | |
232 } | |
233 } | |
234 | |
235 } // namespace content | 268 } // namespace content |
OLD | NEW |