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

Side by Side Diff: media/filters/vpx_video_decoder.cc

Issue 16274005: Separate DemuxerStream and VideoDecoder. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: VideoFrameStream ready for review. Created 7 years, 6 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "media/filters/vpx_video_decoder.h" 5 #include "media/filters/vpx_video_decoder.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback_helpers.h" 8 #include "base/callback_helpers.h"
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/location.h" 10 #include "base/location.h"
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 decode_threads = std::max(decode_threads, 0); 54 decode_threads = std::max(decode_threads, 0);
55 decode_threads = std::min(decode_threads, kMaxDecodeThreads); 55 decode_threads = std::min(decode_threads, kMaxDecodeThreads);
56 return decode_threads; 56 return decode_threads;
57 } 57 }
58 58
59 VpxVideoDecoder::VpxVideoDecoder( 59 VpxVideoDecoder::VpxVideoDecoder(
60 const scoped_refptr<base::MessageLoopProxy>& message_loop) 60 const scoped_refptr<base::MessageLoopProxy>& message_loop)
61 : message_loop_(message_loop), 61 : message_loop_(message_loop),
62 weak_factory_(this), 62 weak_factory_(this),
63 state_(kUninitialized), 63 state_(kUninitialized),
64 demuxer_stream_(NULL),
65 vpx_codec_(NULL), 64 vpx_codec_(NULL),
66 vpx_codec_alpha_(NULL) { 65 vpx_codec_alpha_(NULL) {
67 } 66 }
68 67
69 VpxVideoDecoder::~VpxVideoDecoder() { 68 VpxVideoDecoder::~VpxVideoDecoder() {
70 DCHECK_EQ(kUninitialized, state_); 69 DCHECK_EQ(kUninitialized, state_);
71 CloseDecoder(); 70 CloseDecoder();
72 } 71 }
73 72
74 void VpxVideoDecoder::Initialize( 73 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config,
75 DemuxerStream* stream, 74 const PipelineStatusCB& status_cb,
76 const PipelineStatusCB& status_cb, 75 const StatisticsCB& statistics_cb) {
77 const StatisticsCB& statistics_cb) {
78 DCHECK(message_loop_->BelongsToCurrentThread()); 76 DCHECK(message_loop_->BelongsToCurrentThread());
79 DCHECK(stream); 77 DCHECK(config.IsValidConfig());
78 DCHECK(!config.is_encrypted());
80 DCHECK(read_cb_.is_null()); 79 DCHECK(read_cb_.is_null());
81 DCHECK(reset_cb_.is_null()); 80 DCHECK(reset_cb_.is_null());
82 81
83 weak_this_ = weak_factory_.GetWeakPtr(); 82 weak_this_ = weak_factory_.GetWeakPtr();
84 83
85 demuxer_stream_ = stream; 84 if (!ConfigureDecoder(config)) {
86 statistics_cb_ = statistics_cb;
87
88 if (!ConfigureDecoder()) {
89 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); 85 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
90 return; 86 return;
91 } 87 }
92 88
93 // Success! 89 // Success!
90 config_ = config;
91 statistics_cb_ = statistics_cb;
94 state_ = kNormal; 92 state_ = kNormal;
95 status_cb.Run(PIPELINE_OK); 93 status_cb.Run(PIPELINE_OK);
96 } 94 }
97 95
98 static vpx_codec_ctx* InitializeVpxContext(vpx_codec_ctx* context, 96 static vpx_codec_ctx* InitializeVpxContext(vpx_codec_ctx* context,
99 const VideoDecoderConfig& config) { 97 const VideoDecoderConfig& config) {
100 context = new vpx_codec_ctx(); 98 context = new vpx_codec_ctx();
101 vpx_codec_dec_cfg_t vpx_config = {0}; 99 vpx_codec_dec_cfg_t vpx_config = {0};
102 vpx_config.w = config.coded_size().width(); 100 vpx_config.w = config.coded_size().width();
103 vpx_config.h = config.coded_size().height(); 101 vpx_config.h = config.coded_size().height();
104 vpx_config.threads = GetThreadCount(); 102 vpx_config.threads = GetThreadCount();
105 103
106 vpx_codec_err_t status = vpx_codec_dec_init(context, 104 vpx_codec_err_t status = vpx_codec_dec_init(context,
107 config.codec() == kCodecVP9 ? 105 config.codec() == kCodecVP9 ?
108 vpx_codec_vp9_dx() : 106 vpx_codec_vp9_dx() :
109 vpx_codec_vp8_dx(), 107 vpx_codec_vp8_dx(),
110 &vpx_config, 108 &vpx_config,
111 0); 109 0);
112 if (status != VPX_CODEC_OK) { 110 if (status != VPX_CODEC_OK) {
113 LOG(ERROR) << "vpx_codec_dec_init failed, status=" << status; 111 LOG(ERROR) << "vpx_codec_dec_init failed, status=" << status;
114 delete context; 112 delete context;
115 return NULL; 113 return NULL;
116 } 114 }
117 return context; 115 return context;
118 } 116 }
119 117
120 bool VpxVideoDecoder::ConfigureDecoder() { 118 bool VpxVideoDecoder::ConfigureDecoder(const VideoDecoderConfig& config) {
121 const VideoDecoderConfig& config = demuxer_stream_->video_decoder_config();
122 DCHECK(config.IsValidConfig());
123
124 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 119 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
125 bool can_handle = false; 120 bool can_handle = false;
126 if (cmd_line->HasSwitch(switches::kEnableVp9Playback) && 121 if (cmd_line->HasSwitch(switches::kEnableVp9Playback) &&
127 config.codec() == kCodecVP9) { 122 config.codec() == kCodecVP9) {
128 can_handle = true; 123 can_handle = true;
129 } 124 }
130 if (cmd_line->HasSwitch(switches::kEnableVp8AlphaPlayback) && 125 if (cmd_line->HasSwitch(switches::kEnableVp8AlphaPlayback) &&
131 config.codec() == kCodecVP8 && config.format() == VideoFrame::YV12A) { 126 config.codec() == kCodecVP8 && config.format() == VideoFrame::YV12A) {
132 can_handle = true; 127 can_handle = true;
133 } 128 }
(...skipping 21 matching lines...) Expand all
155 delete vpx_codec_; 150 delete vpx_codec_;
156 vpx_codec_ = NULL; 151 vpx_codec_ = NULL;
157 } 152 }
158 if (vpx_codec_alpha_) { 153 if (vpx_codec_alpha_) {
159 vpx_codec_destroy(vpx_codec_alpha_); 154 vpx_codec_destroy(vpx_codec_alpha_);
160 delete vpx_codec_alpha_; 155 delete vpx_codec_alpha_;
161 vpx_codec_alpha_ = NULL; 156 vpx_codec_alpha_ = NULL;
162 } 157 }
163 } 158 }
164 159
165 void VpxVideoDecoder::Read(const ReadCB& read_cb) { 160 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
161 const ReadCB& read_cb) {
166 DCHECK(message_loop_->BelongsToCurrentThread()); 162 DCHECK(message_loop_->BelongsToCurrentThread());
167 DCHECK(!read_cb.is_null()); 163 DCHECK(!read_cb.is_null());
168 CHECK_NE(state_, kUninitialized); 164 CHECK_NE(state_, kUninitialized);
169 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; 165 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported.";
166
170 read_cb_ = BindToCurrentLoop(read_cb); 167 read_cb_ = BindToCurrentLoop(read_cb);
171 168
172 if (state_ == kError) { 169 if (state_ == kError) {
173 read_cb.Run(kDecodeError, NULL); 170 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
174 return; 171 return;
175 } 172 }
176 173
177 // Return empty frames if decoding has finished. 174 // Return empty frames if decoding has finished.
178 if (state_ == kDecodeFinished) { 175 if (state_ == kDecodeFinished) {
179 read_cb.Run(kOk, VideoFrame::CreateEmptyFrame()); 176 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame());
180 return; 177 return;
181 } 178 }
182 179
183 ReadFromDemuxerStream(); 180 DecodeBuffer(buffer);
184 } 181 }
185 182
186 void VpxVideoDecoder::Reset(const base::Closure& closure) { 183 void VpxVideoDecoder::Reset(const base::Closure& closure) {
187 DCHECK(message_loop_->BelongsToCurrentThread()); 184 DCHECK(message_loop_->BelongsToCurrentThread());
188 DCHECK(reset_cb_.is_null()); 185 DCHECK(reset_cb_.is_null());
189 reset_cb_ = BindToCurrentLoop(closure); 186 reset_cb_ = BindToCurrentLoop(closure);
190 187
191 // Defer the reset if a read is pending. 188 // Defer the reset if a read is pending.
192 if (!read_cb_.is_null()) 189 if (!read_cb_.is_null())
193 return; 190 return;
194 191
195 DoReset(); 192 DoReset();
196 } 193 }
197 194
198 void VpxVideoDecoder::Stop(const base::Closure& closure) { 195 void VpxVideoDecoder::Stop(const base::Closure& closure) {
199 DCHECK(message_loop_->BelongsToCurrentThread()); 196 DCHECK(message_loop_->BelongsToCurrentThread());
200 197
201 if (state_ == kUninitialized) { 198 if (state_ == kUninitialized) {
202 closure.Run(); 199 closure.Run();
203 return; 200 return;
204 } 201 }
205 202
206 if (!read_cb_.is_null()) 203 if (!read_cb_.is_null())
207 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); 204 base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
208 205
209 state_ = kUninitialized; 206 state_ = kUninitialized;
210 closure.Run(); 207 closure.Run();
211 } 208 }
212 209
213 void VpxVideoDecoder::ReadFromDemuxerStream() { 210 void VpxVideoDecoder::DecodeBuffer(const scoped_refptr<DecoderBuffer>& buffer) {
214 DCHECK_NE(state_, kUninitialized);
215 DCHECK_NE(state_, kDecodeFinished);
216 DCHECK_NE(state_, kError);
217 DCHECK(!read_cb_.is_null());
218
219 demuxer_stream_->Read(base::Bind(
220 &VpxVideoDecoder::DoDecryptOrDecodeBuffer, weak_this_));
221 }
222
223 void VpxVideoDecoder::DoDecryptOrDecodeBuffer(
224 DemuxerStream::Status status,
225 const scoped_refptr<DecoderBuffer>& buffer) {
226 DCHECK(message_loop_->BelongsToCurrentThread());
227 DCHECK_NE(state_, kDecodeFinished);
228 DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status;
229
230 if (state_ == kUninitialized)
231 return;
232
233 DCHECK(!read_cb_.is_null());
234
235 if (!reset_cb_.is_null()) {
236 base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
237 DoReset();
238 return;
239 }
240
241 if (status == DemuxerStream::kAborted) {
242 base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
243 return;
244 }
245
246 // VideoFrameStream ensures no kConfigChanged is passed to VideoDecoders.
247 DCHECK_EQ(status, DemuxerStream::kOk) << status;
248 DecodeBuffer(buffer);
249 }
250
251 void VpxVideoDecoder::DecodeBuffer(
252 const scoped_refptr<DecoderBuffer>& buffer) {
253 DCHECK(message_loop_->BelongsToCurrentThread()); 211 DCHECK(message_loop_->BelongsToCurrentThread());
254 DCHECK_NE(state_, kUninitialized); 212 DCHECK_NE(state_, kUninitialized);
255 DCHECK_NE(state_, kDecodeFinished); 213 DCHECK_NE(state_, kDecodeFinished);
256 DCHECK_NE(state_, kError); 214 DCHECK_NE(state_, kError);
257 DCHECK(reset_cb_.is_null()); 215 DCHECK(reset_cb_.is_null());
258 DCHECK(!read_cb_.is_null()); 216 DCHECK(!read_cb_.is_null());
259 DCHECK(buffer);
260 217
261 // Transition to kDecodeFinished on the first end of stream buffer. 218 // Transition to kDecodeFinished on the first end of stream buffer.
262 if (state_ == kNormal && buffer->IsEndOfStream()) { 219 if (state_ == kNormal && buffer->IsEndOfStream()) {
263 state_ = kDecodeFinished; 220 state_ = kDecodeFinished;
264 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); 221 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame());
265 return; 222 return;
266 } 223 }
267 224
268 scoped_refptr<VideoFrame> video_frame; 225 scoped_refptr<VideoFrame> video_frame;
269 if (!Decode(buffer, &video_frame)) { 226 if (!VpxDecode(buffer, &video_frame)) {
270 state_ = kError; 227 state_ = kError;
271 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); 228 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
272 return; 229 return;
273 } 230 }
274 231
275 // Any successful decode counts! 232 // Any successful decode counts!
276 if (buffer->GetDataSize() && buffer->GetSideDataSize()) { 233 if (buffer->GetDataSize() && buffer->GetSideDataSize()) {
277 PipelineStatistics statistics; 234 PipelineStatistics statistics;
278 statistics.video_bytes_decoded = buffer->GetDataSize(); 235 statistics.video_bytes_decoded = buffer->GetDataSize();
279 statistics_cb_.Run(statistics); 236 statistics_cb_.Run(statistics);
280 } 237 }
281 238
282 // If we didn't get a frame we need more data.
283 if (!video_frame) { 239 if (!video_frame) {
284 ReadFromDemuxerStream(); 240 base::ResetAndReturn(&read_cb_).Run(kNotEnoughData, NULL);
285 return; 241 return;
286 } 242 }
287 243
288 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame); 244 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame);
289 } 245 }
290 246
291 bool VpxVideoDecoder::Decode( 247 bool VpxVideoDecoder::VpxDecode(const scoped_refptr<DecoderBuffer>& buffer,
292 const scoped_refptr<DecoderBuffer>& buffer, 248 scoped_refptr<VideoFrame>* video_frame) {
293 scoped_refptr<VideoFrame>* video_frame) {
294 DCHECK(video_frame); 249 DCHECK(video_frame);
295 DCHECK(!buffer->IsEndOfStream()); 250 DCHECK(!buffer->IsEndOfStream());
296 251
297 // Pass |buffer| to libvpx. 252 // Pass |buffer| to libvpx.
298 int64 timestamp = buffer->GetTimestamp().InMicroseconds(); 253 int64 timestamp = buffer->GetTimestamp().InMicroseconds();
299 void* user_priv = reinterpret_cast<void*>(&timestamp); 254 void* user_priv = reinterpret_cast<void*>(&timestamp);
300 vpx_codec_err_t status = vpx_codec_decode(vpx_codec_, 255 vpx_codec_err_t status = vpx_codec_decode(vpx_codec_,
301 buffer->GetData(), 256 buffer->GetData(),
302 buffer->GetDataSize(), 257 buffer->GetDataSize(),
303 user_priv, 258 user_priv,
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
363 } 318 }
364 319
365 void VpxVideoDecoder::DoReset() { 320 void VpxVideoDecoder::DoReset() {
366 DCHECK(read_cb_.is_null()); 321 DCHECK(read_cb_.is_null());
367 322
368 state_ = kNormal; 323 state_ = kNormal;
369 reset_cb_.Run(); 324 reset_cb_.Run();
370 reset_cb_.Reset(); 325 reset_cb_.Reset();
371 } 326 }
372 327
373 void VpxVideoDecoder::CopyVpxImageTo( 328 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image,
374 const vpx_image* vpx_image, 329 const struct vpx_image* vpx_image_alpha,
375 const struct vpx_image* vpx_image_alpha, 330 scoped_refptr<VideoFrame>* video_frame) {
376 scoped_refptr<VideoFrame>* video_frame) {
377 CHECK(vpx_image); 331 CHECK(vpx_image);
378 CHECK_EQ(vpx_image->d_w % 2, 0U); 332 CHECK_EQ(vpx_image->d_w % 2, 0U);
379 CHECK_EQ(vpx_image->d_h % 2, 0U); 333 CHECK_EQ(vpx_image->d_h % 2, 0U);
380 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || 334 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 ||
381 vpx_image->fmt == VPX_IMG_FMT_YV12); 335 vpx_image->fmt == VPX_IMG_FMT_YV12);
382 336
383 gfx::Size size(vpx_image->d_w, vpx_image->d_h); 337 gfx::Size size(vpx_image->d_w, vpx_image->d_h);
384 gfx::Size natural_size =
385 demuxer_stream_->video_decoder_config().natural_size();
386 338
387 *video_frame = VideoFrame::CreateFrame(vpx_codec_alpha_ ? 339 *video_frame = VideoFrame::CreateFrame(
388 VideoFrame::YV12A : 340 vpx_codec_alpha_ ? VideoFrame::YV12A : VideoFrame::YV12,
389 VideoFrame::YV12, 341 size,
390 size, 342 gfx::Rect(size),
391 gfx::Rect(size), 343 config_.natural_size(),
392 natural_size, 344 kNoTimestamp());
393 kNoTimestamp());
394 345
395 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], 346 CopyYPlane(vpx_image->planes[VPX_PLANE_Y],
396 vpx_image->stride[VPX_PLANE_Y], 347 vpx_image->stride[VPX_PLANE_Y],
397 vpx_image->d_h, 348 vpx_image->d_h,
398 *video_frame); 349 *video_frame);
399 CopyUPlane(vpx_image->planes[VPX_PLANE_U], 350 CopyUPlane(vpx_image->planes[VPX_PLANE_U],
400 vpx_image->stride[VPX_PLANE_U], 351 vpx_image->stride[VPX_PLANE_U],
401 vpx_image->d_h / 2, 352 vpx_image->d_h / 2,
402 *video_frame); 353 *video_frame);
403 CopyVPlane(vpx_image->planes[VPX_PLANE_V], 354 CopyVPlane(vpx_image->planes[VPX_PLANE_V],
404 vpx_image->stride[VPX_PLANE_V], 355 vpx_image->stride[VPX_PLANE_V],
405 vpx_image->d_h / 2, 356 vpx_image->d_h / 2,
406 *video_frame); 357 *video_frame);
358
407 if (!vpx_codec_alpha_) 359 if (!vpx_codec_alpha_)
408 return; 360 return;
361
409 if (!vpx_image_alpha) { 362 if (!vpx_image_alpha) {
410 MakeOpaqueAPlane(vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, 363 MakeOpaqueAPlane(
411 *video_frame); 364 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, *video_frame);
412 return; 365 return;
413 } 366 }
367
414 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], 368 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y],
415 vpx_image->stride[VPX_PLANE_Y], 369 vpx_image->stride[VPX_PLANE_Y],
416 vpx_image->d_h, 370 vpx_image->d_h,
417 *video_frame); 371 *video_frame);
418 } 372 }
419 373
420 } // namespace media 374 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698