mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-01-10 00:34:32 +00:00
media: add WebM Vorbis and VP8 encoders
This commit is contained in:
parent
60899133c1
commit
654f97fa72
5 changed files with 237 additions and 0 deletions
|
|
@ -15,8 +15,12 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
vp8.hpp
|
||||
vpx_error.hpp
|
||||
webm.hpp
|
||||
webm_encoder.hpp
|
||||
webm_container.cpp
|
||||
webm_container.hpp
|
||||
webm_vorbis.hpp
|
||||
webm_vorbis_lace.cpp
|
||||
webm_vp8.hpp
|
||||
webm_writer.hpp
|
||||
yuv420p.cpp
|
||||
yuv420p.hpp
|
||||
|
|
|
|||
51
src/media/webm_encoder.hpp
Normal file
51
src/media/webm_encoder.hpp
Normal 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_WEBM_ENCODER_HPP__
|
||||
#define __SRB2_MEDIA_WEBM_ENCODER_HPP__
|
||||
|
||||
#include <mkvmuxer/mkvmuxer.h>
|
||||
|
||||
#include "encoder.hpp"
|
||||
#include "webm_container.hpp"
|
||||
|
||||
namespace srb2::media
|
||||
{
|
||||
|
||||
template <typename T = mkvmuxer::Track>
|
||||
class WebmEncoder : virtual public MediaEncoder
|
||||
{
|
||||
public:
|
||||
WebmEncoder(WebmContainer& container, webm::track trackid) : container_(container), trackid_(trackid)
|
||||
{
|
||||
container_.init_queue(trackid_);
|
||||
}
|
||||
|
||||
protected:
|
||||
WebmContainer& container_;
|
||||
webm::track trackid_;
|
||||
|
||||
std::size_t size() const { return container_.track_size(trackid_); }
|
||||
time_unit_t duration() const { return container_.track_duration(trackid_); }
|
||||
|
||||
static T* get_track(const WebmContainer& container, webm::track trackid) { return container.get_track<T>(trackid); }
|
||||
|
||||
T* track() const { return get_track(container_, trackid_); }
|
||||
|
||||
virtual void write_frame(frame_buffer_t p, time_unit_t ts, bool is_key_frame) override final
|
||||
{
|
||||
const auto ts_nano = std::chrono::duration_cast<webm::duration>(ts);
|
||||
|
||||
container_.queue_frame(p, trackid_, ts_nano.count(), is_key_frame);
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace srb2::media
|
||||
|
||||
#endif // __SRB2_MEDIA_WEBM_ENCODER_HPP__
|
||||
59
src/media/webm_vorbis.hpp
Normal file
59
src/media/webm_vorbis.hpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// 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_WEBM_VORBIS_HPP__
|
||||
#define __SRB2_MEDIA_WEBM_VORBIS_HPP__
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "../cxxutil.hpp"
|
||||
#include "vorbis.hpp"
|
||||
#include "webm_encoder.hpp"
|
||||
|
||||
namespace srb2::media
|
||||
{
|
||||
|
||||
class WebmVorbisEncoder : public WebmEncoder<mkvmuxer::AudioTrack>, public VorbisEncoder
|
||||
{
|
||||
public:
|
||||
WebmVorbisEncoder(WebmContainer& container, webm::track trackid, AudioEncoder::Config cfg) :
|
||||
WebmEncoder(container, trackid), VorbisEncoder(cfg)
|
||||
{
|
||||
// write Vorbis extra data
|
||||
|
||||
const auto p = make_vorbis_private_data();
|
||||
|
||||
SRB2_ASSERT(track()->SetCodecPrivate(reinterpret_cast<const uint8_t*>(p.data()), p.size()) == true);
|
||||
}
|
||||
|
||||
virtual BitRate estimated_bit_rate() const override final
|
||||
{
|
||||
auto _ = container_.queue_guard();
|
||||
|
||||
const std::chrono::duration<float> t = duration();
|
||||
|
||||
if (t <= t.zero())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
return {static_cast<std::size_t>((size() * 8) / t.count()), 1s};
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::byte> make_vorbis_private_data();
|
||||
};
|
||||
|
||||
}; // namespace srb2::media
|
||||
|
||||
#endif // __SRB2_MEDIA_WEBM_VORBIS_HPP__
|
||||
79
src/media/webm_vorbis_lace.cpp
Normal file
79
src/media/webm_vorbis_lace.cpp
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
#include <tcb/span.hpp>
|
||||
|
||||
#include "webm_vorbis.hpp"
|
||||
|
||||
// https://www.matroska.org/technical/notes.html#xiph-lacing
|
||||
// https://www.matroska.org/technical/codec_specs.html#a_vorbis
|
||||
|
||||
using namespace srb2::media;
|
||||
|
||||
static std::size_t lace_length(const ogg_packet& op)
|
||||
{
|
||||
return (op.bytes / 255) + 1;
|
||||
}
|
||||
|
||||
static void lace(std::vector<std::byte>& v, const ogg_packet& op)
|
||||
{
|
||||
// The lacing size is encoded in at least one byte. If
|
||||
// the value is 255, add the value of the next byte in
|
||||
// sequence. This ends with a byte that is less than 255.
|
||||
|
||||
std::fill_n(std::back_inserter(v), lace_length(op) - 1, std::byte {255});
|
||||
|
||||
const unsigned char n = (op.bytes % 255);
|
||||
v.emplace_back(std::byte {n});
|
||||
}
|
||||
|
||||
std::vector<std::byte> WebmVorbisEncoder::make_vorbis_private_data()
|
||||
{
|
||||
const headers_t packets = generate_headers();
|
||||
|
||||
std::vector<std::byte> v;
|
||||
|
||||
// There are three Vorbis header packets. The lacing for
|
||||
// these packets in Matroska does not count the final
|
||||
// packet.
|
||||
|
||||
// clang-format off
|
||||
v.reserve(
|
||||
1
|
||||
+ lace_length(packets[0])
|
||||
+ lace_length(packets[1])
|
||||
+ packets[0].bytes
|
||||
+ packets[1].bytes
|
||||
+ packets[2].bytes);
|
||||
// clang-format on
|
||||
|
||||
// The first byte is the number of packets. Once again,
|
||||
// the last packet is not counted.
|
||||
v.emplace_back(std::byte {2});
|
||||
|
||||
// Then the laced sizes for each packet.
|
||||
lace(v, packets[0]);
|
||||
lace(v, packets[1]);
|
||||
|
||||
// Then each packet's data. The last packet's data
|
||||
// actually is written here.
|
||||
for (auto op : packets)
|
||||
{
|
||||
tcb::span<const std::byte> p(reinterpret_cast<const std::byte*>(op.packet), op.bytes);
|
||||
|
||||
std::copy(p.begin(), p.end(), std::back_inserter(v));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
44
src/media/webm_vp8.hpp
Normal file
44
src/media/webm_vp8.hpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// 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_WEBM_VP8_HPP__
|
||||
#define __SRB2_MEDIA_WEBM_VP8_HPP__
|
||||
|
||||
#include "vp8.hpp"
|
||||
#include "webm_encoder.hpp"
|
||||
|
||||
namespace srb2::media
|
||||
{
|
||||
|
||||
class WebmVP8Encoder : public WebmEncoder<mkvmuxer::VideoTrack>, public VP8Encoder
|
||||
{
|
||||
public:
|
||||
WebmVP8Encoder(WebmContainer& container, webm::track trackid, VideoEncoder::Config cfg) :
|
||||
WebmEncoder(container, trackid), VP8Encoder(cfg)
|
||||
{
|
||||
}
|
||||
|
||||
virtual BitRate estimated_bit_rate() const override final
|
||||
{
|
||||
auto _ = container_.queue_guard();
|
||||
|
||||
const int frames = frame_count().frames;
|
||||
|
||||
if (frames <= 0)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return {(size() * 8) / frames, std::chrono::duration<float>(1.f / frame_rate())};
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace srb2::media
|
||||
|
||||
#endif // __SRB2_MEDIA_WEBM_VP8_HPP__
|
||||
Loading…
Add table
Reference in a new issue