Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(135)

Side by Side Diff: chrome/renderer/gpu_video_decoder_host.cc

Issue 6713005: Move a bunch of gpu/worker/plugin renderer code to content. I temporarily disabled the sad plugi... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "chrome/renderer/gpu_video_decoder_host.h"
6
7 #include "content/common/gpu_messages.h"
8 #include "content/common/message_router.h"
9 #include "media/base/pipeline.h"
10 #include "media/video/video_decode_context.h"
11
12 GpuVideoDecoderHost::GpuVideoDecoderHost(MessageRouter* router,
13 IPC::Message::Sender* ipc_sender,
14 int context_route_id,
15 int32 decoder_host_id)
16 : router_(router),
17 ipc_sender_(ipc_sender),
18 context_route_id_(context_route_id),
19 message_loop_(NULL),
20 event_handler_(NULL),
21 context_(NULL),
22 width_(0),
23 height_(0),
24 state_(kStateUninitialized),
25 decoder_host_id_(decoder_host_id),
26 decoder_id_(0),
27 input_buffer_busy_(false),
28 current_frame_id_(0) {
29 }
30
31 GpuVideoDecoderHost::~GpuVideoDecoderHost() {}
32
33 void GpuVideoDecoderHost::OnChannelError() {
34 ipc_sender_ = NULL;
35 }
36
37 bool GpuVideoDecoderHost::OnMessageReceived(const IPC::Message& msg) {
38 bool handled = true;
39 IPC_BEGIN_MESSAGE_MAP(GpuVideoDecoderHost, msg)
40 IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_CreateVideoDecoderDone,
41 OnCreateVideoDecoderDone)
42 IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_InitializeACK,
43 OnInitializeDone)
44 IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_DestroyACK,
45 OnUninitializeDone)
46 IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_FlushACK,
47 OnFlushDone)
48 IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_PrerollDone,
49 OnPrerollDone)
50 IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_EmptyThisBufferACK,
51 OnEmptyThisBufferACK)
52 IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_EmptyThisBufferDone,
53 OnProduceVideoSample)
54 IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_ConsumeVideoFrame,
55 OnConsumeVideoFrame)
56 IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_AllocateVideoFrames,
57 OnAllocateVideoFrames)
58 IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_ReleaseAllVideoFrames,
59 OnReleaseAllVideoFrames)
60 IPC_MESSAGE_UNHANDLED(handled = false)
61 IPC_END_MESSAGE_MAP()
62 DCHECK(handled);
63 return handled;
64 }
65
66 void GpuVideoDecoderHost::Initialize(
67 MessageLoop* message_loop, VideoDecodeEngine::EventHandler* event_handler,
68 media::VideoDecodeContext* context, const media::VideoCodecConfig& config) {
69 DCHECK_EQ(kStateUninitialized, state_);
70 DCHECK(!message_loop_);
71 message_loop_ = message_loop;
72 event_handler_ = event_handler;
73 context_ = context;
74 width_ = config.width();
75 height_ = config.height();
76
77 if (MessageLoop::current() != message_loop) {
78 message_loop->PostTask(
79 FROM_HERE,
80 NewRunnableMethod(this, &GpuVideoDecoderHost::CreateVideoDecoder));
81 return;
82 }
83 CreateVideoDecoder();
84 }
85
86 void GpuVideoDecoderHost::ConsumeVideoSample(scoped_refptr<Buffer> buffer) {
87 if (MessageLoop::current() != message_loop_) {
88 message_loop_->PostTask(
89 FROM_HERE,
90 NewRunnableMethod(
91 this, &GpuVideoDecoderHost::ConsumeVideoSample, buffer));
92 return;
93 }
94
95 DCHECK_NE(state_, kStateUninitialized);
96 DCHECK_NE(state_, kStateFlushing);
97
98 // We never own input buffers, therefore when client in flush state, it
99 // never call us with EmptyThisBuffer.
100 if (state_ != kStateNormal)
101 return;
102
103 input_buffer_queue_.push_back(buffer);
104 SendConsumeVideoSample();
105 }
106
107 void GpuVideoDecoderHost::ProduceVideoFrame(scoped_refptr<VideoFrame> frame) {
108 if (MessageLoop::current() != message_loop_) {
109 message_loop_->PostTask(
110 FROM_HERE,
111 NewRunnableMethod(
112 this, &GpuVideoDecoderHost::ProduceVideoFrame, frame));
113 return;
114 }
115
116 DCHECK_NE(state_, kStateUninitialized);
117
118 // During flush client of this object will call this method to return all
119 // video frames. We should only ignore such method calls if we are in error
120 // state.
121 if (state_ == kStateError)
122 return;
123
124 // Check that video frame is valid.
125 if (!frame || frame->format() == media::VideoFrame::EMPTY ||
126 frame->IsEndOfStream()) {
127 return;
128 }
129
130 SendProduceVideoFrame(frame);
131 }
132
133 void GpuVideoDecoderHost::Uninitialize() {
134 if (MessageLoop::current() != message_loop_) {
135 message_loop_->PostTask(
136 FROM_HERE,
137 NewRunnableMethod(this, &GpuVideoDecoderHost::Uninitialize));
138 return;
139 }
140
141 if (!ipc_sender_->Send(new GpuVideoDecoderMsg_Destroy(decoder_id_))) {
142 LOG(ERROR) << "GpuVideoDecoderMsg_Destroy failed";
143 event_handler_->OnError();
144 }
145 }
146
147 void GpuVideoDecoderHost::Flush() {
148 if (MessageLoop::current() != message_loop_) {
149 message_loop_->PostTask(
150 FROM_HERE, NewRunnableMethod(this, &GpuVideoDecoderHost::Flush));
151 return;
152 }
153
154 state_ = kStateFlushing;
155 if (!ipc_sender_->Send(new GpuVideoDecoderMsg_Flush(decoder_id_))) {
156 LOG(ERROR) << "GpuVideoDecoderMsg_Flush failed";
157 event_handler_->OnError();
158 return;
159 }
160
161 input_buffer_queue_.clear();
162 // TODO(jiesun): because GpuVideoDeocder/GpuVideoDecoder are asynchronously.
163 // We need a way to make flush logic more clear. but I think ring buffer
164 // should make the busy flag obsolete, therefore I will leave it for now.
165 input_buffer_busy_ = false;
166 }
167
168 void GpuVideoDecoderHost::Seek() {
169 if (MessageLoop::current() != message_loop_) {
170 message_loop_->PostTask(
171 FROM_HERE, NewRunnableMethod(this, &GpuVideoDecoderHost::Seek));
172 return;
173 }
174
175 if (!ipc_sender_->Send(new GpuVideoDecoderMsg_Preroll(decoder_id_))) {
176 LOG(ERROR) << "GpuVideoDecoderMsg_Preroll failed";
177 event_handler_->OnError();
178 return;
179 }
180 }
181
182 void GpuVideoDecoderHost::CreateVideoDecoder() {
183 DCHECK_EQ(message_loop_, MessageLoop::current());
184
185 // Add the route so we'll receive messages.
186 router_->AddRoute(decoder_host_id_, this);
187
188 if (!ipc_sender_->Send(
189 new GpuChannelMsg_CreateVideoDecoder(context_route_id_,
190 decoder_host_id_))) {
191 LOG(ERROR) << "GpuChannelMsg_CreateVideoDecoder failed";
192 event_handler_->OnError();
193 return;
194 }
195 }
196
197 void GpuVideoDecoderHost::OnCreateVideoDecoderDone(int32 decoder_id) {
198 DCHECK_EQ(message_loop_, MessageLoop::current());
199 decoder_id_ = decoder_id;
200
201 // TODO(hclam): Initialize |param| with the right values.
202 GpuVideoDecoderInitParam param;
203 param.width = width_;
204 param.height = height_;
205
206 if (!ipc_sender_->Send(
207 new GpuVideoDecoderMsg_Initialize(decoder_id, param))) {
208 LOG(ERROR) << "GpuVideoDecoderMsg_Initialize failed";
209 event_handler_->OnError();
210 }
211 }
212
213 void GpuVideoDecoderHost::OnInitializeDone(
214 const GpuVideoDecoderInitDoneParam& param) {
215 DCHECK_EQ(message_loop_, MessageLoop::current());
216
217 bool success = param.success &&
218 base::SharedMemory::IsHandleValid(param.input_buffer_handle);
219
220 if (success) {
221 input_transfer_buffer_.reset(
222 new base::SharedMemory(param.input_buffer_handle, false));
223 success = input_transfer_buffer_->Map(param.input_buffer_size);
224 }
225 state_ = success ? kStateNormal : kStateError;
226
227 // TODO(hclam): There's too many unnecessary copies for width and height!
228 // Need to clean it up.
229 // TODO(hclam): Need to fill in more information.
230 media::VideoCodecInfo info;
231 info.success = success;
232 info.stream_info.surface_width = width_;
233 info.stream_info.surface_height = height_;
234 event_handler_->OnInitializeComplete(info);
235 }
236
237 void GpuVideoDecoderHost::OnUninitializeDone() {
238 DCHECK_EQ(message_loop_, MessageLoop::current());
239
240 input_transfer_buffer_.reset();
241 router_->RemoveRoute(decoder_host_id_);
242 context_->ReleaseAllVideoFrames();
243 event_handler_->OnUninitializeComplete();
244 }
245
246 void GpuVideoDecoderHost::OnFlushDone() {
247 DCHECK_EQ(message_loop_, MessageLoop::current());
248
249 state_ = kStateNormal;
250 event_handler_->OnFlushComplete();
251 }
252
253 void GpuVideoDecoderHost::OnPrerollDone() {
254 DCHECK_EQ(message_loop_, MessageLoop::current());
255
256 state_ = kStateNormal;
257 event_handler_->OnSeekComplete();
258 }
259
260 void GpuVideoDecoderHost::OnEmptyThisBufferACK() {
261 DCHECK_EQ(message_loop_, MessageLoop::current());
262
263 input_buffer_busy_ = false;
264 SendConsumeVideoSample();
265 }
266
267 void GpuVideoDecoderHost::OnProduceVideoSample() {
268 DCHECK_EQ(message_loop_, MessageLoop::current());
269 DCHECK_EQ(kStateNormal, state_);
270
271 event_handler_->ProduceVideoSample(NULL);
272 }
273
274 void GpuVideoDecoderHost::OnConsumeVideoFrame(int32 frame_id, int64 timestamp,
275 int64 duration, int32 flags) {
276 DCHECK_EQ(message_loop_, MessageLoop::current());
277
278 scoped_refptr<VideoFrame> frame;
279 if (flags & kGpuVideoEndOfStream) {
280 VideoFrame::CreateEmptyFrame(&frame);
281 } else {
282 frame = video_frame_map_[frame_id];
283 DCHECK(frame) << "Invalid frame ID received";
284
285 frame->SetDuration(base::TimeDelta::FromMicroseconds(duration));
286 frame->SetTimestamp(base::TimeDelta::FromMicroseconds(timestamp));
287 }
288
289 media::PipelineStatistics statistics;
290 // TODO(sjl): Fill in statistics.
291
292 event_handler_->ConsumeVideoFrame(frame, statistics);
293 }
294
295 void GpuVideoDecoderHost::OnAllocateVideoFrames(
296 int32 n, uint32 width, uint32 height, int32 format) {
297 DCHECK_EQ(message_loop_, MessageLoop::current());
298 DCHECK_EQ(0u, video_frames_.size());
299
300 context_->AllocateVideoFrames(
301 n, width, height, static_cast<media::VideoFrame::Format>(format),
302 &video_frames_,
303 NewRunnableMethod(this,
304 &GpuVideoDecoderHost::OnAllocateVideoFramesDone));
305 }
306
307 void GpuVideoDecoderHost::OnReleaseAllVideoFrames() {
308 DCHECK_EQ(message_loop_, MessageLoop::current());
309
310 context_->ReleaseAllVideoFrames();
311 video_frame_map_.clear();
312 video_frames_.clear();
313 }
314
315 void GpuVideoDecoderHost::OnAllocateVideoFramesDone() {
316 if (MessageLoop::current() != message_loop_) {
317 message_loop_->PostTask(
318 FROM_HERE,
319 NewRunnableMethod(
320 this, &GpuVideoDecoderHost::OnAllocateVideoFramesDone));
321 return;
322 }
323
324 // After video frame allocation is done we add these frames to a map and
325 // send them to the GPU process.
326 DCHECK(video_frames_.size()) << "No video frames allocated";
327 for (size_t i = 0; i < video_frames_.size(); ++i) {
328 DCHECK(video_frames_[i]);
329 video_frame_map_.insert(
330 std::make_pair(current_frame_id_, video_frames_[i]));
331 SendVideoFrameAllocated(current_frame_id_, video_frames_[i]);
332 ++current_frame_id_;
333 }
334 }
335
336 void GpuVideoDecoderHost::SendVideoFrameAllocated(
337 int32 frame_id, scoped_refptr<media::VideoFrame> frame) {
338 DCHECK_EQ(message_loop_, MessageLoop::current());
339
340 std::vector<uint32> textures;
341 for (size_t i = 0; i < frame->planes(); ++i) {
342 textures.push_back(frame->gl_texture(i));
343 }
344
345 if (!ipc_sender_->Send(new GpuVideoDecoderMsg_VideoFrameAllocated(
346 decoder_id_, frame_id, textures))) {
347 LOG(ERROR) << "GpuVideoDecoderMsg_EmptyThisBuffer failed";
348 }
349 }
350
351 void GpuVideoDecoderHost::SendConsumeVideoSample() {
352 DCHECK_EQ(message_loop_, MessageLoop::current());
353
354 if (input_buffer_busy_ || input_buffer_queue_.empty())
355 return;
356 input_buffer_busy_ = true;
357
358 scoped_refptr<Buffer> buffer = input_buffer_queue_.front();
359 input_buffer_queue_.pop_front();
360
361 // Send input data to GPU process.
362 GpuVideoDecoderInputBufferParam param;
363 param.offset = 0;
364 param.size = buffer->GetDataSize();
365 param.timestamp = buffer->GetTimestamp().InMicroseconds();
366 memcpy(input_transfer_buffer_->memory(), buffer->GetData(), param.size);
367
368 if (!ipc_sender_->Send(
369 new GpuVideoDecoderMsg_EmptyThisBuffer(decoder_id_, param))) {
370 LOG(ERROR) << "GpuVideoDecoderMsg_EmptyThisBuffer failed";
371 }
372 }
373
374 void GpuVideoDecoderHost::SendProduceVideoFrame(
375 scoped_refptr<media::VideoFrame> frame) {
376 DCHECK_EQ(message_loop_, MessageLoop::current());
377
378 // TODO(hclam): I should mark a frame being used to DCHECK and make sure
379 // user doesn't use it the second time.
380 // TODO(hclam): Derive a faster way to lookup the frame ID.
381 bool found = false;
382 int32 frame_id = 0;
383 for (VideoFrameMap::iterator i = video_frame_map_.begin();
384 i != video_frame_map_.end(); ++i) {
385 if (frame == i->second) {
386 frame_id = i->first;
387 found = true;
388 break;
389 }
390 }
391
392 DCHECK(found) << "Invalid video frame received";
393 if (found && !ipc_sender_->Send(
394 new GpuVideoDecoderMsg_ProduceVideoFrame(decoder_id_, frame_id))) {
395 LOG(ERROR) << "GpuVideoDecoderMsg_ProduceVideoFrame failed";
396 }
397 }
398
399 DISABLE_RUNNABLE_METHOD_REFCOUNT(GpuVideoDecoderHost);
OLDNEW
« no previous file with comments | « chrome/renderer/gpu_video_decoder_host.h ('k') | chrome/renderer/gpu_video_decoder_host_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698