| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "media/ffmpeg/ffmpeg_decoding_loop.h" |
| #include "base/callback.h" |
| #include "base/logging.h" |
| #include "media/ffmpeg/ffmpeg_common.h" |
| |
| namespace media { |
| |
| FFmpegDecodingLoop::FFmpegDecodingLoop(AVCodecContext* context, |
| |
| bool continue_on_decoding_errors) |
| : continue_on_decoding_errors_(continue_on_decoding_errors), |
| context_(context), |
| frame_(av_frame_alloc()) {} |
| |
| FFmpegDecodingLoop::~FFmpegDecodingLoop() = default; |
| |
| FFmpegDecodingLoop::DecodeStatus FFmpegDecodingLoop::DecodePacket( |
| const AVPacket* packet, |
| FrameReadyCB frame_ready_cb) { |
| bool sent_packet = false, frames_remaining = true, decoder_error = false; |
| while (!sent_packet || frames_remaining) { |
| if (!sent_packet) { |
| const int result = avcodec_send_packet(context_, packet); |
| if (result < 0 && result != AVERROR(EAGAIN) && result != AVERROR_EOF) { |
| DLOG(ERROR) << "Failed to send packet for decoding: " << result; |
| return DecodeStatus::kSendPacketFailed; |
| } |
| |
| sent_packet = result != AVERROR(EAGAIN); |
| } |
| |
| // See if any frames are available. If we receive an EOF or EAGAIN, there |
| // should be nothing left to do this pass since we've already provided the |
| // only input packet that we have. |
| const int result = avcodec_receive_frame(context_, frame_.get()); |
| if (result == AVERROR_EOF || result == AVERROR(EAGAIN)) { |
| frames_remaining = false; |
| |
| // TODO(dalecurtis): This should be a DCHECK() or MEDIA_LOG, but since |
| // this API is new, lets make it a CHECK first and monitor reports. |
| if (result == AVERROR(EAGAIN)) { |
| CHECK(sent_packet) << "avcodec_receive_frame() and " |
| "avcodec_send_packet() both returned EAGAIN, " |
| "which is an API violation."; |
| } |
| |
| continue; |
| } else if (result < 0) { |
| DLOG(ERROR) << "Failed to decode frame: " << result; |
| last_averror_code_ = result; |
| if (!continue_on_decoding_errors_) |
| return DecodeStatus::kDecodeFrameFailed; |
| decoder_error = true; |
| continue; |
| } |
| |
| const bool frame_processing_success = frame_ready_cb.Run(frame_.get()); |
| av_frame_unref(frame_.get()); |
| if (!frame_processing_success) |
| return DecodeStatus::kFrameProcessingFailed; |
| } |
| |
| return decoder_error ? DecodeStatus::kDecodeFrameFailed : DecodeStatus::kOkay; |
| } |
| |
| } // namespace media |