blob: 24ee970d9d83f8297715e7fc612306031bd64bb8 [file] [log] [blame]
// Copyright 2019 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_USE_MEDIA_DECODER_IN_STREAM_H_
#define SRC_MEDIA_CODEC_EXAMPLES_USE_MEDIA_DECODER_IN_STREAM_H_
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/sys/cpp/component_context.h>
#include <fbl/mutex.h>
// Abstract base class which permits reading from a stream of input data.
//
// Sub-classes:
// * InStreamFile can stream in from a file.
// * InStreamHttp can stream in using http.
//
// Re. threading, this class is meant to be called from a single ordering
// domain / thread that isn't the fidl_thread. None of the public methods are
// safe to call from the fidl_thread; also not the destructor.
//
// All methods including the destructor may rely on fidl_thread to make
// progress.
//
// Calls to ReadBytes() will block until there's at least 1 byte or the read
// times out.
//
// It is only safe to delete the instance from a thread that is not the
// fidl_thread.
//
// TODO(dustingreen): Probably we could combine this with
// src/media/playback/mediaplayer/demux/reader.h, assuming it's fine to consume
// that here.
class InStream {
public:
// All sub-classes must retain the property that it's safe to delete this
// instance from any thread.
//
// Sub-classes may wish to use FencePostSerial() at the start of their
// destructor to ensure that any lambdas previously posted with PostSerial()
// are done before any sub-class member vars are destructed.
virtual ~InStream();
// The cursor_position() is the byte offset of the current location in the
// input data. This starts at 0.
//
// Every successful ReadBytes() advances cursor_position().
//
// This method is not meant to be overridden by sub-classes.
uint64_t cursor_position() const;
// Once this starts returning true it'll continue returning true. At the
// latest, this will start returning true when ReadBytesComplete() reads less
// than the requested amount.
bool eos_position_known();
// Requires eos_position_known().
uint64_t eos_position();
// Returns ZX_OK with *bytes_read_out == 0 if the end of input data has been
// reached.
//
// If the end of input data has not yet been reached, this blocks until at
// least 1 bytes of input data is available, and then returns ZX_OK indicating
// at least 1 byte was read. The caller must not expect that the # of bytes
// actaully read is necessarily max_bytes_to_read. Especially as the end of
// input data is reached, the *bytes_read_out will sometimes be less than
// max_bytes_to_read.
//
// When deadline is non-infinite, and the deadline is reached, timeout will
// occur before 1 byte is available and ZX_ERR_TIMED_OUT is returned.
//
// buffer_out must be at least max_bytes_to_read in length.
//
// The cursor_position is advanced by *bytes_read_out.
//
// Sub-classes should override ReadBytesInternal, not ReadBytes.
zx_status_t ReadBytesShort(uint32_t max_bytes_to_read, uint32_t* bytes_read_out,
uint8_t* buffer_out,
zx::time just_fail_deadline = zx::time::infinite());
zx_status_t ReadBytesComplete(uint32_t max_bytes_to_read, uint32_t* bytes_read_out,
uint8_t* buffer_out,
zx::time just_fail_deadline = zx::time::infinite());
// Normally a reset like this isn't necessarily optimal vs. just creating a new instance, but in
// tests we want the reset to be fast, so we allow instance reset.
//
// This either succeeds with ZX_OK and sets cursor_position() back to 0, or fails with an error.
// If the error is ZX_ERR_NOT_SUPPORTED, a sub-class doesn't support ResetToStart(), and any
// wrapper InStream wasn't able to avoid calling ResetToStart() on the sub-class.
zx_status_t ResetToStart(zx::time just_fail_deadline = zx::time::infinite());
protected:
InStream(async::Loop* fidl_loop, thrd_t fidl_thread, sys::ComponentContext* component_context);
void PostToFidlSerial(fit::closure to_run);
void FencePostToFidlSerial();
// Sub-classes override ReadBytesInternal() to actually read data. The
// sub-class doesn't need to update cursor_position_ since ReadBytes() handles
// that.
virtual zx_status_t ReadBytesInternal(uint32_t max_bytes_to_read, uint32_t* bytes_read_out,
uint8_t* buffer_out, zx::time just_fail_deadline) = 0;
virtual zx_status_t ResetToStartInternal(zx::time just_fail_deadline);
async::Loop* const fidl_loop_ = nullptr;
async_dispatcher_t* const fidl_dispatcher_ = nullptr;
const thrd_t fidl_thread_{};
sys::ComponentContext* const component_context_;
// TODO(liyl): Need to change to std::mutex.
fbl::Mutex lock_;
uint64_t cursor_position_ = 0;
bool failure_seen_ = false;
bool eos_position_known_ = false;
uint64_t eos_position_ = 0;
};
#endif // SRC_MEDIA_CODEC_EXAMPLES_USE_MEDIA_DECODER_IN_STREAM_H_