ffmpeg_decoding_loop.cc 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. // Copyright 2017 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. #include "media/ffmpeg/ffmpeg_decoding_loop.h"
  5. #include "base/callback.h"
  6. #include "base/logging.h"
  7. #include "media/ffmpeg/ffmpeg_common.h"
  8. namespace media {
  9. FFmpegDecodingLoop::FFmpegDecodingLoop(AVCodecContext* context,
  10. bool continue_on_decoding_errors)
  11. : continue_on_decoding_errors_(continue_on_decoding_errors),
  12. context_(context),
  13. frame_(av_frame_alloc()) {}
  14. FFmpegDecodingLoop::~FFmpegDecodingLoop() = default;
  15. FFmpegDecodingLoop::DecodeStatus FFmpegDecodingLoop::DecodePacket(
  16. const AVPacket* packet,
  17. FrameReadyCB frame_ready_cb) {
  18. bool sent_packet = false, frames_remaining = true, decoder_error = false;
  19. while (!sent_packet || frames_remaining) {
  20. if (!sent_packet) {
  21. const int result = avcodec_send_packet(context_, packet);
  22. if (result < 0 && result != AVERROR(EAGAIN) && result != AVERROR_EOF) {
  23. DLOG(ERROR) << "Failed to send packet for decoding: " << result;
  24. return DecodeStatus::kSendPacketFailed;
  25. }
  26. sent_packet = result != AVERROR(EAGAIN);
  27. }
  28. // See if any frames are available. If we receive an EOF or EAGAIN, there
  29. // should be nothing left to do this pass since we've already provided the
  30. // only input packet that we have.
  31. const int result = avcodec_receive_frame(context_, frame_.get());
  32. if (result == AVERROR_EOF || result == AVERROR(EAGAIN)) {
  33. frames_remaining = false;
  34. // TODO(dalecurtis): This should be a DCHECK() or MEDIA_LOG, but since
  35. // this API is new, lets make it a CHECK first and monitor reports.
  36. if (result == AVERROR(EAGAIN)) {
  37. CHECK(sent_packet) << "avcodec_receive_frame() and "
  38. "avcodec_send_packet() both returned EAGAIN, "
  39. "which is an API violation.";
  40. }
  41. continue;
  42. } else if (result < 0) {
  43. DLOG(ERROR) << "Failed to decode frame: " << result;
  44. last_averror_code_ = result;
  45. if (!continue_on_decoding_errors_)
  46. return DecodeStatus::kDecodeFrameFailed;
  47. decoder_error = true;
  48. continue;
  49. }
  50. const bool frame_processing_success = frame_ready_cb.Run(frame_.get());
  51. av_frame_unref(frame_.get());
  52. if (!frame_processing_success)
  53. return DecodeStatus::kFrameProcessingFailed;
  54. }
  55. return decoder_error ? DecodeStatus::kDecodeFrameFailed : DecodeStatus::kOkay;
  56. }
  57. } // namespace media