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

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

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

Powered by Google App Engine
This is Rietveld 408576698