blob: ac51a739158ceade660a9483f78af2a04947c6b1 [file] [log] [blame]
// 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.
#ifndef MEDIA_FFMPEG_FFMPEG_DECODING_LOOP_H_
#define MEDIA_FFMPEG_FFMPEG_DECODING_LOOP_H_
#include <memory>
#include "base/callback_forward.h"
#include "base/macros.h"
#include "media/base/media_export.h"
#include "media/ffmpeg/ffmpeg_deleters.h"
struct AVCodecContext;
struct AVFrame;
struct AVPacket;
namespace media {
class MEDIA_EXPORT FFmpegDecodingLoop {
public:
enum class DecodeStatus {
// Everything went just okay.
kOkay,
// Indicates that avcodec_send_packet() failed on the current packet. This
// error is fatal and indicates the decoding loop is no longer viable.
kSendPacketFailed,
// Indicates that avcodec_receive_frame() failed on some packet; it may be a
// packet sent in the past. If |continue_on_decoding_errors| is true, this
// code is recoverable and may be ignored.
kDecodeFrameFailed,
// Returned when FrameReadyCB returns false which indicates that an internal
// error has occurred; will immediately stop the decoding loop. This should
// not be considered recoverable since internal loop state is unknown.
kFrameProcessingFailed,
};
// Creates a decoding loop using the already initialized codec |context|. If
// decoding errors should be non-fatal, set |continue_on_decoding_errors| to
// true; note: send packet failures are always fatal.
FFmpegDecodingLoop(AVCodecContext* context,
bool continue_on_decoding_errors = false);
~FFmpegDecodingLoop();
// Callback issued when the decoding loop has produced a frame. |frame| is
// owned by the decoding loop. Return true to continue the decoding loop.
using FrameReadyCB = base::RepeatingCallback<bool(AVFrame* frame)>;
// Spins a generic decoding which decodes all available frames and sends them
// to |frame_ready_cb| given a single input |packet|. Returns an enum with
// success or the appropriate error code if failure.
//
// If |packet| is an end of stream packet all available frames still in the
// decoder will be returned. After end of stream, |context| will not be usable
// for decoding until avcodec_flush_buffers() is called on the context; which
// the decoding loop does not handle.
DecodeStatus DecodePacket(const AVPacket* packet,
FrameReadyCB frame_ready_cb);
int last_averror_code() const { return last_averror_code_; }
private:
const bool continue_on_decoding_errors_;
AVCodecContext* const context_;
std::unique_ptr<AVFrame, ScopedPtrAVFreeFrame> frame_;
int last_averror_code_ = 0;
DISALLOW_COPY_AND_ASSIGN(FFmpegDecodingLoop);
};
} // namespace media
#endif // MEDIA_FFMPEG_FFMPEG_DECODING_LOOP_H_