OLD | NEW |
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/ffmpeg_video_decoder.h" | 5 #include "media/filters/ffmpeg_video_decoder.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
302 } | 302 } |
303 | 303 |
304 scoped_refptr<VideoFrame> video_frame; | 304 scoped_refptr<VideoFrame> video_frame; |
305 if (!Decode(buffer, &video_frame)) { | 305 if (!Decode(buffer, &video_frame)) { |
306 state_ = kDecodeFinished; | 306 state_ = kDecodeFinished; |
307 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); | 307 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); |
308 return; | 308 return; |
309 } | 309 } |
310 | 310 |
311 // Any successful decode counts! | 311 // Any successful decode counts! |
312 if (buffer->GetDataSize()) { | 312 if (!buffer->IsEndOfStream() && buffer->GetDataSize() > 0) { |
313 PipelineStatistics statistics; | 313 PipelineStatistics statistics; |
314 statistics.video_bytes_decoded = buffer->GetDataSize(); | 314 statistics.video_bytes_decoded = buffer->GetDataSize(); |
315 statistics_cb_.Run(statistics); | 315 statistics_cb_.Run(statistics); |
316 } | 316 } |
317 | 317 |
318 // If we didn't get a frame then we've either completely finished decoding or | 318 // If we didn't get a frame then we've either completely finished decoding or |
319 // we need more data. | 319 // we need more data. |
320 if (!video_frame) { | 320 if (!video_frame) { |
321 if (state_ == kFlushCodec) { | 321 if (state_ == kFlushCodec) { |
322 state_ = kDecodeFinished; | 322 state_ = kDecodeFinished; |
323 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); | 323 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); |
324 return; | 324 return; |
325 } | 325 } |
326 | 326 |
327 ReadFromDemuxerStream(); | 327 ReadFromDemuxerStream(); |
328 return; | 328 return; |
329 } | 329 } |
330 | 330 |
331 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame); | 331 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame); |
332 } | 332 } |
333 | 333 |
334 bool FFmpegVideoDecoder::Decode( | 334 bool FFmpegVideoDecoder::Decode( |
335 const scoped_refptr<DecoderBuffer>& buffer, | 335 const scoped_refptr<DecoderBuffer>& buffer, |
336 scoped_refptr<VideoFrame>* video_frame) { | 336 scoped_refptr<VideoFrame>* video_frame) { |
337 DCHECK(video_frame); | 337 DCHECK(video_frame); |
338 | 338 |
| 339 // Reset frame to default values. |
| 340 avcodec_get_frame_defaults(av_frame_); |
| 341 |
339 // Create a packet for input data. | 342 // Create a packet for input data. |
340 // Due to FFmpeg API changes we no longer have const read-only pointers. | 343 // Due to FFmpeg API changes we no longer have const read-only pointers. |
341 AVPacket packet; | 344 AVPacket packet; |
342 av_init_packet(&packet); | 345 av_init_packet(&packet); |
343 packet.data = const_cast<uint8*>(buffer->GetData()); | 346 if (buffer->IsEndOfStream()) { |
344 packet.size = buffer->GetDataSize(); | 347 packet.data = NULL; |
| 348 packet.size = 0; |
| 349 } else { |
| 350 packet.data = const_cast<uint8*>(buffer->GetData()); |
| 351 packet.size = buffer->GetDataSize(); |
345 | 352 |
346 // Let FFmpeg handle presentation timestamp reordering. | 353 // Let FFmpeg handle presentation timestamp reordering. |
347 codec_context_->reordered_opaque = buffer->GetTimestamp().InMicroseconds(); | 354 codec_context_->reordered_opaque = buffer->GetTimestamp().InMicroseconds(); |
348 | 355 |
349 // Reset frame to default values. | 356 // This is for codecs not using get_buffer to initialize |
350 avcodec_get_frame_defaults(av_frame_); | 357 // |av_frame_->reordered_opaque| |
351 | 358 av_frame_->reordered_opaque = codec_context_->reordered_opaque; |
352 // This is for codecs not using get_buffer to initialize | 359 } |
353 // |av_frame_->reordered_opaque| | |
354 av_frame_->reordered_opaque = codec_context_->reordered_opaque; | |
355 | 360 |
356 int frame_decoded = 0; | 361 int frame_decoded = 0; |
357 int result = avcodec_decode_video2(codec_context_, | 362 int result = avcodec_decode_video2(codec_context_, |
358 av_frame_, | 363 av_frame_, |
359 &frame_decoded, | 364 &frame_decoded, |
360 &packet); | 365 &packet); |
361 // Log the problem if we can't decode a video frame and exit early. | 366 // Log the problem if we can't decode a video frame and exit early. |
362 if (result < 0) { | 367 if (result < 0) { |
363 LOG(ERROR) << "Error decoding a video frame with timestamp: " | 368 LOG(ERROR) << "Error decoding video: " << buffer->AsHumanReadableString(); |
364 << buffer->GetTimestamp().InMicroseconds() << " us, duration: " | |
365 << buffer->GetDuration().InMicroseconds() << " us, packet size: " | |
366 << buffer->GetDataSize() << " bytes"; | |
367 *video_frame = NULL; | 369 *video_frame = NULL; |
368 return false; | 370 return false; |
369 } | 371 } |
370 | 372 |
371 // If no frame was produced then signal that more data is required to | 373 // If no frame was produced then signal that more data is required to |
372 // produce more frames. This can happen under two circumstances: | 374 // produce more frames. This can happen under two circumstances: |
373 // 1) Decoder was recently initialized/flushed | 375 // 1) Decoder was recently initialized/flushed |
374 // 2) End of stream was reached and all internal frames have been output | 376 // 2) End of stream was reached and all internal frames have been output |
375 if (frame_decoded == 0) { | 377 if (frame_decoded == 0) { |
376 *video_frame = NULL; | 378 *video_frame = NULL; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
446 if (!codec || avcodec_open2(codec_context_, codec, NULL) < 0) { | 448 if (!codec || avcodec_open2(codec_context_, codec, NULL) < 0) { |
447 ReleaseFFmpegResources(); | 449 ReleaseFFmpegResources(); |
448 return false; | 450 return false; |
449 } | 451 } |
450 | 452 |
451 av_frame_ = avcodec_alloc_frame(); | 453 av_frame_ = avcodec_alloc_frame(); |
452 return true; | 454 return true; |
453 } | 455 } |
454 | 456 |
455 } // namespace media | 457 } // namespace media |
OLD | NEW |