Add basic multimedia container and encoder interfaces

Adds the media subdirectory.
This commit is contained in:
James R 2023-02-12 02:03:23 -08:00
parent 8ee785bb7e
commit 3b5245f974
7 changed files with 272 additions and 0 deletions

View file

@ -549,6 +549,7 @@ if(SRB2_CONFIG_ENABLE_TESTS)
add_subdirectory(tests)
endif()
add_subdirectory(menus)
add_subdirectory(media)
# strip debug symbols into separate file when using gcc.
# to be consistent with Makefile, don't generate for OS X.

7
src/media/CMakeLists.txt Normal file
View file

@ -0,0 +1,7 @@
target_sources(SRB2SDL2 PRIVATE
audio_encoder.hpp
container.hpp
encoder.hpp
video_encoder.hpp
video_frame.hpp
)

View file

@ -0,0 +1,39 @@
// RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by James Robert Roman
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#ifndef __SRB2_MEDIA_AUDIO_ENCODER_HPP__
#define __SRB2_MEDIA_AUDIO_ENCODER_HPP__
#include <tcb/span.hpp>
#include "encoder.hpp"
namespace srb2::media
{
class AudioEncoder : virtual public MediaEncoder
{
public:
using sample_buffer_t = tcb::span<const float>;
struct Config
{
int channels;
int sample_rate;
};
virtual void encode(sample_buffer_t samples) = 0;
virtual int channels() const = 0;
virtual int sample_rate() const = 0;
};
}; // namespace srb2::media
#endif // __SRB2_MEDIA_AUDIO_ENCODER_HPP__

53
src/media/container.hpp Normal file
View file

@ -0,0 +1,53 @@
// RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by James Robert Roman
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#ifndef __SRB2_MEDIA_CONTAINER_HPP__
#define __SRB2_MEDIA_CONTAINER_HPP__
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include "audio_encoder.hpp"
#include "video_encoder.hpp"
namespace srb2::media
{
class MediaContainer
{
public:
using dtor_cb_t = std::function<void(const MediaContainer&)>;
using time_unit_t = std::chrono::duration<float>;
struct Config
{
std::string file_name;
dtor_cb_t destructor_callback;
};
virtual ~MediaContainer() = default;
virtual std::unique_ptr<AudioEncoder> make_audio_encoder(AudioEncoder::Config config) = 0;
virtual std::unique_ptr<VideoEncoder> make_video_encoder(VideoEncoder::Config config) = 0;
virtual const char* name() const = 0;
virtual const char* file_name() const = 0;
// These are normally estimates. However, when called from
// Config::destructor_callback, these are the exact final
// values.
virtual time_unit_t duration() const = 0;
virtual std::size_t size() const = 0;
};
}; // namespace srb2::media
#endif // __SRB2_MEDIA_CONTAINER_HPP__

51
src/media/encoder.hpp Normal file
View file

@ -0,0 +1,51 @@
// RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by James Robert Roman
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#ifndef __SRB2_MEDIA_ENCODER_HPP__
#define __SRB2_MEDIA_ENCODER_HPP__
#include <chrono>
#include <cstddef>
#include <tcb/span.hpp>
namespace srb2::media
{
class MediaEncoder
{
public:
using time_unit_t = std::chrono::duration<float>;
struct BitRate
{
std::size_t bits; // 8 bits = 1 byte :)
time_unit_t period;
};
virtual ~MediaEncoder() = default;
// Should be called finally but it's optional.
virtual void flush() = 0;
virtual const char* name() const = 0;
// Returns an average bit rate over a constant period of
// time, assuming no frames drops.
virtual BitRate estimated_bit_rate() const = 0;
protected:
using frame_buffer_t = tcb::span<const std::byte>;
virtual void write_frame(frame_buffer_t frame, time_unit_t timestamp, bool is_key_frame) = 0;
};
}; // namespace srb2::media
#endif // __SRB2_MEDIA_ENCODER_HPP__

View file

@ -0,0 +1,58 @@
// RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by James Robert Roman
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#ifndef __SRB2_MEDIA_VIDEO_ENCODER_HPP__
#define __SRB2_MEDIA_VIDEO_ENCODER_HPP__
#include "encoder.hpp"
#include "video_frame.hpp"
namespace srb2::media
{
class VideoEncoder : virtual public MediaEncoder
{
public:
struct Config
{
int width;
int height;
int frame_rate;
VideoFrame::BufferMethod buffer_method;
};
struct FrameCount
{
// Number of real frames, not counting frame skips.
int frames;
time_unit_t duration;
};
// VideoFrame::width() and VideoFrame::height() should be
// used on the returned frame.
virtual VideoFrame::instance_t new_frame(int width, int height, int pts) = 0;
virtual void encode(VideoFrame::instance_t frame) = 0;
virtual int width() const = 0;
virtual int height() const = 0;
virtual int frame_rate() const = 0;
// Reports the number of threads used, if the encoder is
// multithreaded.
virtual int thread_count() const = 0;
// Number of frames fully encoded so far.
virtual FrameCount frame_count() const = 0;
};
}; // namespace srb2::media
#endif // __SRB2_MEDIA_VIDEO_ENCODER_HPP__

63
src/media/video_frame.hpp Normal file
View file

@ -0,0 +1,63 @@
// RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by James Robert Roman
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#ifndef __SRB2_MEDIA_VIDEO_FRAME_HPP__
#define __SRB2_MEDIA_VIDEO_FRAME_HPP__
#include <cstddef>
#include <cstdint>
#include <memory>
#include <tcb/span.hpp>
namespace srb2::media
{
class VideoFrame
{
public:
using instance_t = std::unique_ptr<VideoFrame>;
enum class BufferMethod
{
// Returns an already allocated buffer for each
// frame. See VideoFrame::rgba_buffer(). The encoder
// completely manages allocating this buffer.
kEncoderAllocatedRGBA8888,
};
struct Buffer
{
tcb::span<uint8_t> plane;
std::size_t row_stride; // size of each row
};
virtual int width() const = 0;
virtual int height() const = 0;
int pts() const { return pts_; }
// Returns a buffer that should be
// filled with RGBA pixels.
//
// This method may only be used if
// the encoder was configured with
// BufferMethod::kEncoderAllocatedRGBA8888.
virtual const Buffer& rgba_buffer() const = 0;
protected:
VideoFrame(int pts) : pts_(pts) {}
private:
int pts_;
};
}; // namespace srb2::media
#endif // __SRB2_MEDIA_VIDEO_FRAME_HPP__