save timelapse stream to file
This commit is contained in:
@@ -12,6 +12,11 @@ static void encoder_trace_callback(void* context, int level, const char* message
|
||||
LOG("ENCODER: %s", message);
|
||||
}
|
||||
|
||||
MP4Encoder::~MP4Encoder()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
bool MP4Encoder::init(int width, int height, int fps, int bitrate) noexcept
|
||||
{
|
||||
if (WelsCreateSVCEncoder(&m_encoder) != 0)
|
||||
@@ -75,6 +80,11 @@ bool MP4Encoder::init(int width, int height, int fps, int bitrate) noexcept
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MP4Encoder::init() noexcept
|
||||
{
|
||||
return init(m_width, m_height, m_framerate, m_bitrate);
|
||||
}
|
||||
|
||||
bool MP4Encoder::encode(const Image& rgba) noexcept
|
||||
{
|
||||
// lazy allocation of YUV buffer
|
||||
@@ -167,7 +177,7 @@ bool MP4Encoder::write_mp4(const std::string& filename) const noexcept
|
||||
MP4SetTimeScale(mp4, 90000);
|
||||
MP4SetVideoProfileLevel(mp4, 1);
|
||||
MP4TrackId mp4_track = MP4AddH264VideoTrack(mp4, 90000, 90000 / m_framerate, m_width, m_height,
|
||||
m_header.avc_profile, m_header.avc_profile_compat, m_header.avc_level, 3);
|
||||
m_header.avc_profile, m_header.avc_compat, m_header.avc_level, 3);
|
||||
MP4AddH264SequenceParameterSet(mp4, mp4_track, m_header.SPS_data.data(), m_header.SPS_data.size());
|
||||
MP4AddH264PictureParameterSet(mp4, mp4_track, m_header.PPS_data.data(), m_header.PPS_data.size());
|
||||
for (const auto& f : m_frames)
|
||||
@@ -196,3 +206,54 @@ void MP4Encoder::destroy() noexcept
|
||||
m_header.PPS_data.clear();
|
||||
m_header.SPS_data.clear();
|
||||
}
|
||||
|
||||
bool MP4Encoder::read(BinaryStreamReader& r)
|
||||
{
|
||||
Serializer::Descriptor d;
|
||||
r >> d;
|
||||
d.value<Serializer::Integer>("width", m_width);
|
||||
d.value<Serializer::Integer>("height", m_height);
|
||||
d.value<Serializer::Integer>("bitrate", m_bitrate);
|
||||
d.value<Serializer::Float>("framerate", m_framerate);
|
||||
d.value<Serializer::RawData>("SPS", m_header.SPS_data);
|
||||
d.value<Serializer::RawData>("PPS", m_header.PPS_data);
|
||||
d.value<Serializer::Integer>("avc_profile", m_header.avc_profile);
|
||||
d.value<Serializer::Integer>("avc_compat", m_header.avc_compat);
|
||||
d.value<Serializer::Integer>("avc_level", m_header.avc_level);
|
||||
auto frames = d.get<Serializer::List>("frames");
|
||||
for (const auto& f : frames->items)
|
||||
{
|
||||
if (auto fd = std::dynamic_pointer_cast<Serializer::Descriptor>(f))
|
||||
{
|
||||
m_frames.emplace_back();
|
||||
m_frames.back().type = (Frame::kType)fd->value<Serializer::Integer>("type");
|
||||
m_frames.back().data = fd->value<Serializer::RawData>("data");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MP4Encoder::write(BinaryStreamWriter& w) const
|
||||
{
|
||||
Serializer::Descriptor d;
|
||||
d.class_id = "mp4enc";
|
||||
d.name = L"MP4 Encoder class";
|
||||
d.props["width"] = std::make_shared<Serializer::Integer>(m_width);
|
||||
d.props["height"] = std::make_shared<Serializer::Integer>(m_height);
|
||||
d.props["bitrate"] = std::make_shared<Serializer::Integer>(m_bitrate);
|
||||
d.props["framerate"] = std::make_shared<Serializer::Float>(m_framerate);
|
||||
d.props["SPS"] = std::make_shared<Serializer::RawData>(m_header.SPS_data);
|
||||
d.props["PPS"] = std::make_shared<Serializer::RawData>(m_header.PPS_data);
|
||||
d.props["avc_profile"] = std::make_shared<Serializer::Integer>(m_header.avc_profile);
|
||||
d.props["avc_compat"] = std::make_shared<Serializer::Integer>(m_header.avc_compat);
|
||||
d.props["avc_level"] = std::make_shared<Serializer::Integer>(m_header.avc_level);
|
||||
auto frames = std::make_shared<Serializer::List>();
|
||||
for (const auto& f : m_frames)
|
||||
{
|
||||
auto fd = frames->add<Serializer::Descriptor>();
|
||||
fd->props["type"] = std::make_shared<Serializer::Integer>((int)f.type);
|
||||
fd->props["data"] = std::make_shared<Serializer::RawData>(f.data);
|
||||
}
|
||||
d.props["frames"] = frames;
|
||||
w << d;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user