blob: 1d4d07917ebc2c6f53d8e4b361db9ad2d501b940 [file] [log] [blame]
// Copyright 2019 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 CAST_STANDALONE_RECEIVER_DECODER_H_
#define CAST_STANDALONE_RECEIVER_DECODER_H_
#include <stdint.h>
#include <string>
#include <vector>
#include "absl/types/span.h"
#include "cast/standalone_receiver/avcodec_glue.h"
#include "cast/streaming/frame_id.h"
namespace openscreen {
namespace cast {
// Wraps libavcodec to decode audio or video.
class Decoder {
public:
// A buffer backed by storage that is compatible with FFMPEG (i.e., includes
// the required zero-padding).
class Buffer {
public:
Buffer();
~Buffer();
void Resize(int new_size);
absl::Span<const uint8_t> GetSpan() const;
absl::Span<uint8_t> GetSpan();
private:
std::vector<uint8_t> buffer_;
};
// Interface for receiving decoded frames and/or errors.
class Client {
public:
virtual ~Client();
virtual void OnFrameDecoded(FrameId frame_id, const AVFrame& frame) = 0;
virtual void OnDecodeError(FrameId frame_id, std::string message) = 0;
virtual void OnFatalError(std::string message) = 0;
protected:
Client();
};
// |codec_name| should be the codec_name field from an OFFER message.
explicit Decoder(const std::string& codec_name);
~Decoder();
Client* client() const { return client_; }
void set_client(Client* client) { client_ = client; }
// Starts decoding the data in |buffer|, which should be associated with the
// given |frame_id|. This will synchronously call Client::OnFrameDecoded()
// and/or Client::OnDecodeError() zero or more times with results. Note that
// some codecs will have data dependencies that require multiple encoded
// frame's data before the first decoded frame can be generated.
void Decode(FrameId frame_id, const Buffer& buffer);
private:
// Helper to initialize the FFMPEG decoder and supporting objects. Returns
// false if this failed (and the Client was notified).
bool Initialize();
// Helper to get the FrameId that is associated with the next frame coming out
// of the FFMPEG decoder.
FrameId DidReceiveFrameFromDecoder();
// Helper to handle a codec initialization error and notify the Client of the
// fatal error.
void HandleInitializationError(const char* what, int av_errnum);
// Called when any transient or fatal error occurs, generating an Error and
// notifying the Client of it.
void OnError(const char* what, int av_errnum, FrameId frame_id);
const std::string codec_name_;
AVCodec* codec_ = nullptr;
AVCodecParserContextUniquePtr parser_;
AVCodecContextUniquePtr context_;
AVPacketUniquePtr packet_;
AVFrameUniquePtr decoded_frame_;
Client* client_ = nullptr;
// Queue of frames that have been input to the libavcodec decoder, but which
// have not yet had output generated by it.
std::vector<FrameId> frames_decoding_;
};
} // namespace cast
} // namespace openscreen
#endif // CAST_STANDALONE_RECEIVER_DECODER_H_