blob: bca8e1e3eba56aface356fb37c6d56474bfe1de2 [file] [log] [blame]
// Copyright 2020 The Fuchsia 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 SRC_MEDIA_CODEC_EXAMPLES_ENCODE_CAMERA_ENCODER_CLIENT_H_
#define SRC_MEDIA_CODEC_EXAMPLES_ENCODE_CAMERA_ENCODER_CLIENT_H_
#include <fuchsia/mediacodec/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/fit/function.h>
#include <lib/media/test/codec_buffer.h>
#include <list>
#include <unordered_map>
// Single-threaded StreamProcessor client that sets up an encoder instance when given
// an input buffer collection and produces encoded packets via callback.
class EncoderClient {
public:
~EncoderClient();
static fpromise::result<std::unique_ptr<EncoderClient>, zx_status_t> Create(
fuchsia::mediacodec::CodecFactoryHandle codec_factory,
fuchsia::sysmem::AllocatorHandle allocator, uint32_t bitrate, uint32_t gop_size,
const std::string& mime_type);
// Connects to codec factory and sets up an encoder stream processor with the given buffer
// collection and image format as input.
zx_status_t Start(fuchsia::sysmem::BufferCollectionTokenHandle token,
fuchsia::sysmem::ImageFormat_2 image_format, uint32_t frame_rate);
void QueueInputPacket(uint32_t buffer_index, zx::eventpair release_fence);
using OutputPacketHandler = fit::function<void(uint8_t* buffer, size_t len)>;
void SetOutputPacketHandler(OutputPacketHandler handler) {
output_packet_handler_ = std::move(handler);
}
private:
EncoderClient(uint32_t bitrate, uint32_t gop_size, const std::string& mime_type);
using BoundBufferCollectionCallback =
fit::callback<void(fuchsia::sysmem::BufferCollectionTokenHandle&&)>;
// Duplicate passed in token to buffer collection, then bind and sync on it, passing back the
// logical buffer collection and the duplicated token to pass to the next client (the encoder)
void BindAndSyncBufferCollectionToken(fuchsia::sysmem::BufferCollectionPtr& buffer_collection,
fuchsia::sysmem::BufferCollectionTokenHandle token,
BoundBufferCollectionCallback callback);
// Allocate new buffer collection, duplicating a token to it, and passing both to the callback.
void CreateAndSyncBufferCollection(fuchsia::sysmem::BufferCollectionPtr& buffer_collection,
BoundBufferCollectionCallback callback);
// Common helper function to wait for buffers
void BindAndSyncBufferCollection(fuchsia::sysmem::BufferCollectionPtr& buffer_collection,
fuchsia::sysmem::BufferCollectionTokenHandle token,
fuchsia::sysmem::BufferCollectionTokenHandle duplicated_token,
BoundBufferCollectionCallback callback);
// On Ok, contains the buffer collection info and negotiated packet count.
using BufferCollectionResult =
fpromise::result<std::pair<fuchsia::sysmem::BufferCollectionInfo_2, uint32_t>, zx_status_t>;
using ConfigurePortBufferCollectionCallback = fit::callback<void(BufferCollectionResult)>;
void ConfigurePortBufferCollection(
fuchsia::sysmem::BufferCollectionPtr& buffer_collection,
fuchsia::sysmem::BufferCollectionTokenHandle codec_sysmem_token, bool is_output,
uint64_t new_buffer_lifetime_ordinal, uint64_t buffer_constraints_version_ordinal,
ConfigurePortBufferCollectionCallback callback);
void OnInputBuffersReady(BufferCollectionResult result);
void OnOutputBuffersReady(BufferCollectionResult result);
//
// Events:
//
void OnStreamFailed(uint64_t stream_lifetime_ordinal, fuchsia::media::StreamError error);
void OnInputConstraints(fuchsia::media::StreamBufferConstraints input_constraints);
void OnFreeInputPacket(fuchsia::media::PacketHeader free_input_packet);
void OnOutputConstraints(fuchsia::media::StreamOutputConstraints output_config);
void OnOutputFormat(fuchsia::media::StreamOutputFormat output_format);
void OnOutputPacket(fuchsia::media::Packet output_packet, bool error_detected_before,
bool error_detected_during);
void OnOutputEndOfStream(uint64_t stream_lifetime_ordinal, bool error_detected_before);
fuchsia::mediacodec::CodecFactoryPtr codec_factory_;
fuchsia::media::StreamProcessorPtr codec_;
fuchsia::sysmem::AllocatorPtr sysmem_;
OutputPacketHandler output_packet_handler_;
fuchsia::sysmem::BufferCollectionTokenHandle input_buffers_token_;
fuchsia::sysmem::BufferCollectionPtr input_buffer_collection_;
fuchsia::sysmem::BufferCollectionPtr output_buffer_collection_;
std::optional<fuchsia::media::StreamBufferConstraints> input_constraints_;
std::optional<fuchsia::media::StreamOutputConstraints> last_output_constraints_;
// The index into the vector is the same as packet_id, since we're running in
// buffer-per-packet mode.
std::vector<std::unique_ptr<CodecBuffer>> all_input_buffers_;
std::vector<std::unique_ptr<CodecBuffer>> all_output_buffers_;
uint32_t input_packet_count_ = 0;
uint32_t output_packet_count_ = 0;
std::unordered_map<uint32_t, zx::eventpair> input_packets_queued_;
// Only odd values are allowed for buffer_lifetime_ordinal.
uint64_t next_output_buffer_lifetime_ordinal_ = 1;
uint64_t current_output_buffer_lifetime_ordinal_ = 0;
uint32_t bitrate_ = 0;
uint32_t gop_size_ = 0;
std::string mime_type_;
EncoderClient(const EncoderClient&) = delete;
EncoderClient(EncoderClient&&) = delete;
EncoderClient& operator=(const EncoderClient&) = delete;
EncoderClient& operator=(EncoderClient&&) = delete;
};
#endif // SRC_MEDIA_CODEC_EXAMPLES_ENCODE_CAMERA_ENCODER_CLIENT_H_