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

Side by Side Diff: chrome/gpu/gpu_video_decoder.cc

Issue 6684015: Move chrome\gpu to content\gpu. (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
« no previous file with comments | « chrome/gpu/gpu_video_decoder.h ('k') | chrome/gpu/gpu_video_decoder_unittest.cc » ('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 "chrome/gpu/gpu_video_decoder.h"
6
7 #include "base/command_line.h"
8 #include "chrome/gpu/gpu_channel.h"
9 #include "chrome/gpu/media/fake_gl_video_decode_engine.h"
10 #include "chrome/gpu/media/fake_gl_video_device.h"
11 #include "content/common/child_thread.h"
12 #include "content/common/gpu_messages.h"
13 #include "media/base/data_buffer.h"
14 #include "media/base/media_switches.h"
15 #include "media/base/video_frame.h"
16
17 #if defined(OS_WIN)
18 #include "chrome/gpu/media/mft_angle_video_device.h"
19 #include "media/video/mft_h264_decode_engine.h"
20 #include <d3d9.h>
21 #endif
22
23 struct GpuVideoDecoder::PendingAllocation {
24 size_t n;
25 size_t width;
26 size_t height;
27 media::VideoFrame::Format format;
28 std::vector<scoped_refptr<media::VideoFrame> >* frames;
29 Task* task;
30 };
31
32 void GpuVideoDecoder::OnChannelConnected(int32 peer_pid) {
33 }
34
35 void GpuVideoDecoder::OnChannelError() {
36 }
37
38 bool GpuVideoDecoder::OnMessageReceived(const IPC::Message& msg) {
39 bool handled = true;
40 IPC_BEGIN_MESSAGE_MAP(GpuVideoDecoder, msg)
41 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_Initialize,
42 OnInitialize)
43 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_Destroy,
44 OnUninitialize)
45 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_Flush,
46 OnFlush)
47 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_Preroll,
48 OnPreroll)
49 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_EmptyThisBuffer,
50 OnEmptyThisBuffer)
51 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_ProduceVideoFrame,
52 OnProduceVideoFrame)
53 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_VideoFrameAllocated,
54 OnVideoFrameAllocated)
55 IPC_MESSAGE_UNHANDLED(handled = false)
56 IPC_END_MESSAGE_MAP()
57 DCHECK(handled);
58 return handled;
59 }
60
61 bool GpuVideoDecoder::CreateInputTransferBuffer(
62 uint32 size,
63 base::SharedMemoryHandle* handle) {
64 input_transfer_buffer_.reset(new base::SharedMemory);
65 if (!input_transfer_buffer_.get())
66 return false;
67
68 if (!input_transfer_buffer_->CreateAndMapAnonymous(size))
69 return false;
70
71 if (!input_transfer_buffer_->ShareToProcess(renderer_handle_, handle))
72 return false;
73
74 return true;
75 }
76
77 void GpuVideoDecoder::OnInitializeComplete(const VideoCodecInfo& info) {
78 info_ = info;
79 GpuVideoDecoderInitDoneParam param;
80 param.success = false;
81 param.input_buffer_handle = base::SharedMemory::NULLHandle();
82
83 if (!info.success) {
84 SendInitializeDone(param);
85 return;
86 }
87
88 // TODO(jiesun): Check the assumption of input size < original size.
89 param.input_buffer_size =
90 info.stream_info.surface_width * info.stream_info.surface_height * 3 / 2;
91 if (!CreateInputTransferBuffer(param.input_buffer_size,
92 &param.input_buffer_handle)) {
93 SendInitializeDone(param);
94 return;
95 }
96
97 param.success = true;
98 SendInitializeDone(param);
99 }
100
101 void GpuVideoDecoder::OnUninitializeComplete() {
102 SendUninitializeDone();
103 }
104
105 void GpuVideoDecoder::OnFlushComplete() {
106 SendFlushDone();
107 }
108
109 void GpuVideoDecoder::OnSeekComplete() {
110 SendPrerollDone();
111 }
112
113 void GpuVideoDecoder::OnError() {
114 NOTIMPLEMENTED();
115 }
116
117 void GpuVideoDecoder::OnFormatChange(VideoStreamInfo stream_info) {
118 NOTIMPLEMENTED();
119 }
120
121 void GpuVideoDecoder::ProduceVideoSample(scoped_refptr<Buffer> buffer) {
122 SendEmptyBufferDone();
123 }
124
125 void GpuVideoDecoder::ConsumeVideoFrame(scoped_refptr<VideoFrame> frame,
126 const PipelineStatistics& statistics) {
127 // TODO(sjl): Do something with the statistics...
128
129 if (frame->IsEndOfStream()) {
130 SendConsumeVideoFrame(0, 0, 0, kGpuVideoEndOfStream);
131 return;
132 }
133
134 int32 frame_id = -1;
135 for (VideoFrameMap::iterator i = video_frame_map_.begin();
136 i != video_frame_map_.end(); ++i) {
137 if (i->second == frame) {
138 frame_id = i->first;
139 break;
140 }
141 }
142
143 if (frame_id == -1) {
144 NOTREACHED() << "VideoFrame not recognized";
145 return;
146 }
147
148 SendConsumeVideoFrame(frame_id, frame->GetTimestamp().InMicroseconds(),
149 frame->GetDuration().InMicroseconds(), 0);
150 }
151
152 void* GpuVideoDecoder::GetDevice() {
153 bool ret = gles2_decoder_->MakeCurrent();
154 DCHECK(ret) << "Failed to switch context";
155
156 // Simply delegate the method call to GpuVideoDevice.
157 return video_device_->GetDevice();
158 }
159
160 void GpuVideoDecoder::AllocateVideoFrames(
161 int n, size_t width, size_t height, media::VideoFrame::Format format,
162 std::vector<scoped_refptr<media::VideoFrame> >* frames, Task* task) {
163 // Since the communication between Renderer and GPU process is by GL textures.
164 // We need to obtain a set of GL textures by sending IPC commands to the
165 // Renderer process. The recipient of these commands will be IpcVideoDecoder.
166 //
167 // After IpcVideoDecoder replied with a set of textures. We'll assign these
168 // textures to GpuVideoDevice. They will be used to generate platform
169 // specific VideoFrames objects that are used by VideoDecodeEngine.
170 //
171 // After GL textures are assigned we'll proceed with allocation the
172 // VideoFrames. GpuVideoDevice::CreateVideoFramesFromGlTextures() will be
173 // called.
174 //
175 // When GpuVideoDevice replied with a set of VideoFrames we'll give
176 // that to VideoDecodeEngine and the cycle of video frame allocation is done.
177 //
178 // Note that this method is called when there's no video frames allocated or
179 // they were all released.
180 DCHECK(video_frame_map_.empty());
181
182 // Save the parameters for allocation.
183 pending_allocation_.reset(new PendingAllocation());
184 pending_allocation_->n = n;
185 pending_allocation_->width = width;
186 pending_allocation_->height = height;
187 pending_allocation_->format = format;
188 pending_allocation_->frames = frames;
189 pending_allocation_->task = task;
190 SendAllocateVideoFrames(n, width, height, format);
191 }
192
193 void GpuVideoDecoder::ReleaseAllVideoFrames() {
194 // This method will first call to GpuVideoDevice to release all the resource
195 // associated with a VideoFrame.
196 //
197 // And then we'll call GpuVideoDevice::ReleaseVideoFrame() to remove the set
198 // of Gl textures associated with the context.
199 //
200 // And finally we'll send IPC commands to IpcVideoDecoder to destroy all
201 // GL textures generated.
202 bool ret = gles2_decoder_->MakeCurrent();
203 DCHECK(ret) << "Failed to switch context";
204
205 for (VideoFrameMap::iterator i = video_frame_map_.begin();
206 i != video_frame_map_.end(); ++i) {
207 video_device_->ReleaseVideoFrame(i->second);
208 }
209 video_frame_map_.clear();
210 SendReleaseAllVideoFrames();
211 }
212
213 void GpuVideoDecoder::ConvertToVideoFrame(
214 void* buffer,
215 scoped_refptr<media::VideoFrame> frame,
216 Task* task) {
217 // This method is called by VideoDecodeEngine to upload a buffer to a
218 // VideoFrame. We should just delegate this to GpuVideoDevice which contains
219 // the actual implementation.
220 bool ret = gles2_decoder_->MakeCurrent();
221 DCHECK(ret) << "Failed to switch context";
222
223 // Actually doing the upload on the main thread.
224 ret = video_device_->ConvertToVideoFrame(buffer, frame);
225 DCHECK(ret) << "Failed to upload video content to a VideoFrame.";
226 task->Run();
227 delete task;
228 }
229
230 void GpuVideoDecoder::Destroy(Task* task) {
231 // TODO(hclam): I still need to think what I should do here.
232 }
233
234 void GpuVideoDecoder::SetVideoDecodeEngine(media::VideoDecodeEngine* engine) {
235 decode_engine_.reset(engine);
236 }
237
238 void GpuVideoDecoder::SetGpuVideoDevice(GpuVideoDevice* device) {
239 video_device_.reset(device);
240 }
241
242 GpuVideoDecoder::GpuVideoDecoder(
243 MessageLoop* message_loop,
244 int32 decoder_host_id,
245 IPC::Message::Sender* sender,
246 base::ProcessHandle handle,
247 gpu::gles2::GLES2Decoder* decoder)
248 : message_loop_(message_loop),
249 decoder_host_id_(decoder_host_id),
250 sender_(sender),
251 renderer_handle_(handle),
252 gles2_decoder_(decoder) {
253 memset(&info_, 0, sizeof(info_));
254
255 // TODO(jiesun): find a better way to determine which VideoDecodeEngine
256 // to return on current platform.
257 #if defined(OS_WIN)
258 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
259 if (command_line.HasSwitch(switches::kEnableAcceleratedDecoding)) {
260 // The following code are removed so that we don't link them.
261 // TODO(hclam): Enable the code once the crash is solved on XP.
262 // decode_engine_.reset(new media::MftH264DecodeEngine(true));
263 // video_device_.reset(new MftAngleVideoDevice());
264 }
265 #else
266 decode_engine_.reset(new FakeGlVideoDecodeEngine());
267 video_device_.reset(new FakeGlVideoDevice());
268 #endif
269 }
270
271 GpuVideoDecoder::~GpuVideoDecoder() {}
272
273 void GpuVideoDecoder::OnInitialize(const GpuVideoDecoderInitParam& param) {
274 // TODO(jiesun): codec id should come from |param|.
275 media::VideoCodecConfig config(media::kCodecH264,
276 param.width,
277 param.height,
278 param.frame_rate_num,
279 param.frame_rate_den,
280 NULL,
281 0);
282 decode_engine_->Initialize(message_loop_, this, this, config);
283 }
284
285 void GpuVideoDecoder::OnUninitialize() {
286 decode_engine_->Uninitialize();
287 }
288
289 void GpuVideoDecoder::OnFlush() {
290 decode_engine_->Flush();
291 }
292
293 void GpuVideoDecoder::OnPreroll() {
294 decode_engine_->Seek();
295 }
296
297 void GpuVideoDecoder::OnEmptyThisBuffer(
298 const GpuVideoDecoderInputBufferParam& buffer) {
299 DCHECK(input_transfer_buffer_->memory());
300
301 uint8* src = static_cast<uint8*>(input_transfer_buffer_->memory());
302
303 scoped_refptr<Buffer> input_buffer;
304 uint8* dst = buffer.size ? new uint8[buffer.size] : NULL;
305 input_buffer = new media::DataBuffer(dst, buffer.size);
306 memcpy(dst, src, buffer.size);
307 SendEmptyBufferACK();
308
309 // Delegate the method call to VideoDecodeEngine.
310 decode_engine_->ConsumeVideoSample(input_buffer);
311 }
312
313 void GpuVideoDecoder::OnProduceVideoFrame(int32 frame_id) {
314 VideoFrameMap::iterator i = video_frame_map_.find(frame_id);
315 if (i == video_frame_map_.end()) {
316 NOTREACHED() << "Received a request of unknown frame ID.";
317 }
318
319 // Delegate the method call to VideoDecodeEngine.
320 decode_engine_->ProduceVideoFrame(i->second);
321 }
322
323 void GpuVideoDecoder::OnVideoFrameAllocated(int32 frame_id,
324 std::vector<uint32> textures) {
325 bool ret = gles2_decoder_->MakeCurrent();
326 DCHECK(ret) << "Failed to switch context";
327
328 // This method is called in response to a video frame allocation request sent
329 // to the Renderer process.
330 // We should use the textures to generate a VideoFrame by using
331 // GpuVideoDevice. The VideoFrame created is added to the internal map.
332 // If we have generated enough VideoFrame, we call |allocation_callack_| to
333 // complete the allocation process.
334 for (size_t i = 0; i < textures.size(); ++i) {
335 media::VideoFrame::GlTexture gl_texture;
336 // Translate the client texture id to service texture id.
337 ret = gles2_decoder_->GetServiceTextureId(textures[i], &gl_texture);
338 DCHECK(ret) << "Cannot translate client texture ID to service ID";
339 textures[i] = gl_texture;
340 }
341
342 // Use GpuVideoDevice to allocate VideoFrame objects.
343 scoped_refptr<media::VideoFrame> frame;
344
345 ret = video_device_->CreateVideoFrameFromGlTextures(
346 pending_allocation_->width, pending_allocation_->height,
347 pending_allocation_->format, textures, &frame);
348
349 DCHECK(ret) << "Failed to allocation VideoFrame from GL textures)";
350 pending_allocation_->frames->push_back(frame);
351 video_frame_map_.insert(std::make_pair(frame_id, frame));
352
353 if (video_frame_map_.size() == pending_allocation_->n) {
354 pending_allocation_->task->Run();
355 delete pending_allocation_->task;
356 pending_allocation_.reset();
357 }
358 }
359
360 void GpuVideoDecoder::SendInitializeDone(
361 const GpuVideoDecoderInitDoneParam& param) {
362 if (!sender_->Send(
363 new GpuVideoDecoderHostMsg_InitializeACK(decoder_host_id(), param))) {
364 LOG(ERROR) << "GpuVideoDecoderMsg_InitializeACK failed";
365 }
366 }
367
368 void GpuVideoDecoder::SendUninitializeDone() {
369 if (!sender_->Send(
370 new GpuVideoDecoderHostMsg_DestroyACK(decoder_host_id()))) {
371 LOG(ERROR) << "GpuVideoDecoderMsg_DestroyACK failed";
372 }
373 }
374
375 void GpuVideoDecoder::SendFlushDone() {
376 if (!sender_->Send(new GpuVideoDecoderHostMsg_FlushACK(decoder_host_id()))) {
377 LOG(ERROR) << "GpuVideoDecoderMsg_FlushACK failed";
378 }
379 }
380
381 void GpuVideoDecoder::SendPrerollDone() {
382 if (!sender_->Send(new GpuVideoDecoderHostMsg_PrerollDone(
383 decoder_host_id()))) {
384 LOG(ERROR) << "GpuVideoDecoderMsg_PrerollDone failed";
385 }
386 }
387
388 void GpuVideoDecoder::SendEmptyBufferDone() {
389 if (!sender_->Send(
390 new GpuVideoDecoderHostMsg_EmptyThisBufferDone(decoder_host_id()))) {
391 LOG(ERROR) << "GpuVideoDecoderMsg_EmptyThisBufferDone failed";
392 }
393 }
394
395 void GpuVideoDecoder::SendEmptyBufferACK() {
396 if (!sender_->Send(
397 new GpuVideoDecoderHostMsg_EmptyThisBufferACK(decoder_host_id()))) {
398 LOG(ERROR) << "GpuVideoDecoderMsg_EmptyThisBufferACK failed";
399 }
400 }
401
402 void GpuVideoDecoder::SendConsumeVideoFrame(
403 int32 frame_id, int64 timestamp, int64 duration, int32 flags) {
404 if (!sender_->Send(
405 new GpuVideoDecoderHostMsg_ConsumeVideoFrame(
406 decoder_host_id(), frame_id, timestamp, duration, flags))) {
407 LOG(ERROR) << "GpuVideoDecodeHostMsg_ConsumeVideoFrame failed.";
408 }
409 }
410
411 void GpuVideoDecoder::SendAllocateVideoFrames(
412 int n, size_t width, size_t height, media::VideoFrame::Format format) {
413 if (!sender_->Send(
414 new GpuVideoDecoderHostMsg_AllocateVideoFrames(
415 decoder_host_id(), n, width, height,
416 static_cast<int32>(format)))) {
417 LOG(ERROR) << "GpuVideoDecoderMsg_AllocateVideoFrames failed";
418 }
419 }
420
421 void GpuVideoDecoder::SendReleaseAllVideoFrames() {
422 if (!sender_->Send(
423 new GpuVideoDecoderHostMsg_ReleaseAllVideoFrames(
424 decoder_host_id()))) {
425 LOG(ERROR) << "GpuVideoDecoderMsg_ReleaseAllVideoFrames failed";
426 }
427 }
OLDNEW
« no previous file with comments | « chrome/gpu/gpu_video_decoder.h ('k') | chrome/gpu/gpu_video_decoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698