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

Side by Side Diff: chrome/renderer/media/ipc_video_decoder.cc

Issue 2873089: media: gpu process ipc video decoder implementation (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: remove mft Created 10 years, 4 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/renderer/media/ipc_video_decoder.h ('k') | chrome/renderer/render_thread.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) 2010 The Chromium Authors. All rights reserved. Use of this
2 // source code is governed by a BSD-style license that can be found in the
3 // LICENSE file.
4
5
6 #include "chrome/renderer/media/ipc_video_decoder.h"
7
8 #include "base/task.h"
9 #include "media/base/callback.h"
10 #include "media/base/filters.h"
11 #include "media/base/filter_host.h"
12 #include "media/base/limits.h"
13 #include "media/base/media_format.h"
14 #include "media/base/video_frame.h"
15 #include "media/ffmpeg/ffmpeg_common.h"
16 #include "media/ffmpeg/ffmpeg_util.h"
17 #include "media/filters/ffmpeg_interfaces.h"
18
19 namespace media {
20
21 IpcVideoDecoder::IpcVideoDecoder(MessageLoop* message_loop)
22 : width_(0),
23 height_(0),
24 state_(kUnInitialized),
25 pending_reads_(0),
26 pending_requests_(0),
27 renderer_thread_message_loop_(message_loop) {
28 }
29
30 IpcVideoDecoder::~IpcVideoDecoder() {
31 }
32
33 void IpcVideoDecoder::Initialize(DemuxerStream* demuxer_stream,
34 FilterCallback* callback) {
35 if (MessageLoop::current() != renderer_thread_message_loop_) {
36 renderer_thread_message_loop_->PostTask(
37 FROM_HERE,
38 NewRunnableMethod(this,
39 &IpcVideoDecoder::Initialize,
40 demuxer_stream,
41 callback));
42 return;
43 }
44
45 CHECK(!demuxer_stream_);
46 demuxer_stream_ = demuxer_stream;
47 initialize_callback_.reset(callback);
48
49 // Get the AVStream by querying for the provider interface.
50 AVStreamProvider* av_stream_provider;
51 if (!demuxer_stream->QueryInterface(&av_stream_provider)) {
52 GpuVideoDecoderInitDoneParam param;
53 OnInitializeDone(false, param);
54 return;
55 }
56
57 AVStream* av_stream = av_stream_provider->GetAVStream();
58 width_ = av_stream->codec->width;
59 height_ = av_stream->codec->height;
60
61 // Create hardware decoder instance.
62 GpuVideoServiceHost* gpu_video_service_host = GpuVideoServiceHost::get();
63 gpu_video_decoder_host_ = gpu_video_service_host->CreateVideoDecoder(this);
64
65 // Initialize hardware decoder.
66 GpuVideoDecoderInitParam param;
67 param.width_ = width_;
68 param.height_ = height_;
69 if (!gpu_video_decoder_host_->Initialize(param)) {
70 GpuVideoDecoderInitDoneParam param;
71 OnInitializeDone(false, param);
72 }
73 }
74
75 void IpcVideoDecoder::OnInitializeDone(
76 bool success, const GpuVideoDecoderInitDoneParam& param) {
77 if (MessageLoop::current() != renderer_thread_message_loop_) {
78 renderer_thread_message_loop_->PostTask(
79 FROM_HERE,
80 NewRunnableMethod(this,
81 &IpcVideoDecoder::OnInitializeDone,
82 success,
83 param));
84 return;
85 }
86
87 AutoCallbackRunner done_runner(initialize_callback_.release());
88
89 if (success) {
90 media_format_.SetAsString(MediaFormat::kMimeType,
91 mime_type::kUncompressedVideo);
92 media_format_.SetAsInteger(MediaFormat::kWidth, width_);
93 media_format_.SetAsInteger(MediaFormat::kHeight, height_);
94 media_format_.SetAsInteger(MediaFormat::kSurfaceType,
95 static_cast<int>(param.surface_type_));
96 media_format_.SetAsInteger(MediaFormat::kSurfaceFormat,
97 static_cast<int>(param.format_));
98 state_ = kPlaying;
99 } else {
100 LOG(ERROR) << "IpcVideoDecoder initialization failed!";
101 host()->SetError(PIPELINE_ERROR_DECODE);
102 }
103 }
104
105 void IpcVideoDecoder::Stop(FilterCallback* callback) {
106 if (MessageLoop::current() != renderer_thread_message_loop_) {
107 renderer_thread_message_loop_->PostTask(
108 FROM_HERE,
109 NewRunnableMethod(this,
110 &IpcVideoDecoder::Stop,
111 callback));
112 return;
113 }
114
115 stop_callback_.reset(callback);
116 if (!gpu_video_decoder_host_->Uninitialize()) {
117 LOG(ERROR) << "gpu video decoder destroy failed";
118 IpcVideoDecoder::OnUninitializeDone();
119 }
120 }
121
122 void IpcVideoDecoder::OnUninitializeDone() {
123 if (MessageLoop::current() != renderer_thread_message_loop_) {
124 renderer_thread_message_loop_->PostTask(
125 FROM_HERE,
126 NewRunnableMethod(this,
127 &IpcVideoDecoder::OnUninitializeDone));
128 return;
129 }
130
131 AutoCallbackRunner done_runner(stop_callback_.release());
132
133 state_ = kStopped;
134 }
135
136 void IpcVideoDecoder::Pause(FilterCallback* callback) {
137 Flush(callback); // TODO(jiesun): move this to flush().
138 }
139
140 void IpcVideoDecoder::Flush(FilterCallback* callback) {
141 if (MessageLoop::current() != renderer_thread_message_loop_) {
142 renderer_thread_message_loop_->PostTask(
143 FROM_HERE,
144 NewRunnableMethod(this,
145 &IpcVideoDecoder::Flush,
146 callback));
147 return;
148 }
149
150 state_ = kFlushing;
151
152 flush_callback_.reset(callback);
153
154 if (!gpu_video_decoder_host_->Flush()) {
155 LOG(ERROR) << "gpu video decoder flush failed";
156 OnFlushDone();
157 }
158 }
159
160 void IpcVideoDecoder::OnFlushDone() {
161 if (MessageLoop::current() != renderer_thread_message_loop_) {
162 renderer_thread_message_loop_->PostTask(
163 FROM_HERE,
164 NewRunnableMethod(this,
165 &IpcVideoDecoder::OnFlushDone));
166 return;
167 }
168
169 if (pending_reads_ == 0 && pending_requests_ == 0 && flush_callback_.get()) {
170 flush_callback_->Run();
171 flush_callback_.reset();
172 }
173 }
174
175 void IpcVideoDecoder::Seek(base::TimeDelta time, FilterCallback* callback) {
176 if (MessageLoop::current() != renderer_thread_message_loop_) {
177 renderer_thread_message_loop_->PostTask(
178 FROM_HERE,
179 NewRunnableMethod(this,
180 &IpcVideoDecoder::Seek,
181 time,
182 callback));
183 return;
184 }
185
186 OnSeekComplete(callback);
187 }
188
189 void IpcVideoDecoder::OnSeekComplete(FilterCallback* callback) {
190 if (MessageLoop::current() != renderer_thread_message_loop_) {
191 renderer_thread_message_loop_->PostTask(
192 FROM_HERE,
193 NewRunnableMethod(this,
194 &IpcVideoDecoder::OnSeekComplete,
195 callback));
196 return;
197 }
198
199 AutoCallbackRunner done_runner(callback);
200
201 state_ = kPlaying;
202
203 for (int i = 0; i < 20; ++i) {
204 demuxer_stream_->Read(
205 NewCallback(this,
206 &IpcVideoDecoder::OnReadComplete));
207 ++pending_reads_;
208 }
209 }
210
211 void IpcVideoDecoder::OnReadComplete(Buffer* buffer) {
212 scoped_refptr<Buffer> buffer_ref = buffer;
213 ReadCompleteTask(buffer_ref);
214 }
215
216 void IpcVideoDecoder::ReadCompleteTask(scoped_refptr<Buffer> buffer) {
217 if (MessageLoop::current() != renderer_thread_message_loop_) {
218 renderer_thread_message_loop_->PostTask(
219 FROM_HERE,
220 NewRunnableMethod(this,
221 &IpcVideoDecoder::ReadCompleteTask,
222 buffer));
223 return;
224 }
225
226 DCHECK_GT(pending_reads_, 0u);
227 --pending_reads_;
228
229 if (state_ == kStopped || state_ == kEnded) {
230 // Just discard the input buffers
231 return;
232 }
233
234 if (state_ == kFlushing) {
235 if (pending_reads_ == 0 && pending_requests_ == 0) {
236 CHECK(flush_callback_.get());
237 flush_callback_->Run();
238 flush_callback_.reset();
239 state_ = kPlaying;
240 }
241 return;
242 }
243 // Transition to kFlushCodec on the first end of input stream buffer.
244 if (state_ == kPlaying && buffer->IsEndOfStream()) {
245 state_ = kFlushCodec;
246 }
247
248 gpu_video_decoder_host_->EmptyThisBuffer(buffer);
249 }
250
251 void IpcVideoDecoder::FillThisBuffer(scoped_refptr<VideoFrame> video_frame) {
252 if (MessageLoop::current() != renderer_thread_message_loop_) {
253 renderer_thread_message_loop_->PostTask(
254 FROM_HERE,
255 NewRunnableMethod(this,
256 &IpcVideoDecoder::FillThisBuffer,
257 video_frame));
258 return;
259 }
260
261 // Synchronized flushing before stop should prevent this.
262 CHECK_NE(state_, kStopped);
263
264 // Notify decode engine the available of new frame.
265 ++pending_requests_;
266 gpu_video_decoder_host_->FillThisBuffer(video_frame);
267 }
268
269 void IpcVideoDecoder::OnFillBufferDone(scoped_refptr<VideoFrame> video_frame) {
270 if (MessageLoop::current() != renderer_thread_message_loop_) {
271 renderer_thread_message_loop_->PostTask(
272 FROM_HERE,
273 NewRunnableMethod(this,
274 &IpcVideoDecoder::OnFillBufferDone,
275 video_frame));
276 return;
277 }
278
279 if (video_frame.get()) {
280 --pending_requests_;
281 fill_buffer_done_callback()->Run(video_frame);
282 if (state_ == kFlushing && pending_reads_ == 0 && pending_requests_ == 0) {
283 CHECK(flush_callback_.get());
284 flush_callback_->Run();
285 flush_callback_.reset();
286 state_ = kPlaying;
287 }
288
289 } else {
290 if (state_ == kFlushCodec) {
291 // When in kFlushCodec, any errored decode, or a 0-lengthed frame,
292 // is taken as a signal to stop decoding.
293 state_ = kEnded;
294 scoped_refptr<VideoFrame> video_frame;
295 VideoFrame::CreateEmptyFrame(&video_frame);
296 fill_buffer_done_callback()->Run(video_frame);
297 }
298 }
299 }
300
301 void IpcVideoDecoder::OnEmptyBufferDone(scoped_refptr<Buffer> buffer) {
302 if (MessageLoop::current() != renderer_thread_message_loop_) {
303 renderer_thread_message_loop_->PostTask(
304 FROM_HERE,
305 NewRunnableMethod(this,
306 &IpcVideoDecoder::OnEmptyBufferDone,
307 buffer));
308 return;
309 }
310
311 // TODO(jiesun): We haven't recycle input buffer yet.
312 demuxer_stream_->Read(NewCallback(this, &IpcVideoDecoder::OnReadComplete));
313 ++pending_reads_;
314 }
315
316 void IpcVideoDecoder::OnDeviceError() {
317 host()->SetError(PIPELINE_ERROR_DECODE);
318 }
319
320 bool IpcVideoDecoder::ProvidesBuffer() {
321 return true;
322 }
323
324 // static
325 FilterFactory* IpcVideoDecoder::CreateFactory(MessageLoop* message_loop) {
326 return new FilterFactoryImpl1<IpcVideoDecoder, MessageLoop*>(message_loop);
327 }
328
329 // static
330 bool IpcVideoDecoder::IsMediaFormatSupported(const MediaFormat& format) {
331 std::string mime_type;
332 if (!format.GetAsString(MediaFormat::kMimeType, &mime_type) &&
333 mime_type::kFFmpegVideo != mime_type)
334 return false;
335
336 // TODO(jiesun): Although we current only support H264 hardware decoding,
337 // in the future, we should query GpuVideoService for capabilities.
338 int codec_id;
339 return format.GetAsInteger(MediaFormat::kFFmpegCodecID, &codec_id) &&
340 codec_id == CODEC_ID_H264;
341 }
342
343 } // namespace media
344
OLDNEW
« no previous file with comments | « chrome/renderer/media/ipc_video_decoder.h ('k') | chrome/renderer/render_thread.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698