Cogs.Core
VideoCaptureSystem.cpp
1#include "VideoCaptureSystem.h"
2
3#include "VideoCaptureRenderer.h"
4#include "IVideoEncoder.h"
5
6#include "Context.h"
7#include "Components/Core/CameraComponent.h"
8#include "Renderer/RenderResources.h"
9#include "Renderer/RenderTexture.h"
10#include "Systems/Core/CameraSystem.h"
11#include "Resources/Texture.h"
12
13#include "Rendering/IContext.h"
14
15#include "Foundation/Platform/Timer.h"
16#include "Foundation/Logging/Logger.h"
17
18using namespace Cogs::Core;
19
20namespace
21{
22 Cogs::Logging::Log logger = Cogs::Logging::getLogger("VideoCaptureSystem");
23}// namespace ...
24
26{
28 if(!renderer){
29 renderer = new VideoCaptureRenderer;
31 }
32}
33
35{
36 assert(renderer);
37 if (context->renderer) {
38 context->renderer->unregisterExtension(renderer);
39 }
40 delete renderer;
41 renderer = nullptr;
43}
44
46{
47 if (!context->videoEncoderContext) return;
48 for (auto & capComp : pool) {
49 auto & capData = getData(&capComp);
50 if (!capData.encoder || capComp.endOfStream) continue;
51 if(capComp.updateTimestamp)
52 capComp.timestamp = Timer::currentTimeMicroseconds();
53 }
54}
55
57{
58 if (!context->videoEncoderContext) return;
59 for (auto & capComp : pool) {
60 CameraComponent* camComp = capComp.getComponent<CameraComponent>();
61
62 if (!camComp) {
63 continue;
64 }
65
66 VideoCaptureData& capData = getData(&capComp);
67 int64_t now = Timer::currentTimeMilliseconds();
68
69 if (capComp.restart) {
70 capComp.endOfStream = false;
71 }
72
73 if (((!capData.encoder && (capData.nextRestartTime < now)) || capComp.restart || capComp.reconfig) && !capComp.endOfStream) {
74 if (capData.encoder && capComp.restart) {
75 context->videoEncoderContext->destroyVideoEncoder(capData.encoder);
76 capData.encoder = nullptr;
77 }
79
80 desc.codec = capComp.codec;
81 desc.encodeWidth = capComp.width;
82 desc.encodeHeight = capComp.height;
83 desc.darWidth = desc.encodeWidth;
84 desc.darHeight = desc.encodeHeight;
85 desc.maxWidth = capComp.maxWidth;
86 desc.maxHeight = capComp.maxHeight;
87 desc.bitrate = capComp.bitrate;
88 desc.maxBitrate = capComp.maxBitrate;
89 desc.bFrameCount = capComp.bFrameCount;
90 desc.bFrameReference = (uint32_t)capComp.bFrameReference;
91 desc.frameRate = 1000.0f / capComp.frameInterval;
92 desc.lookahead = capComp.lookahead;
93 desc.recordToDisk = capComp.recordToDisk;
94 desc.recordPath = capComp.recordPath;
95 desc.callback = capComp.callback;
96 desc.useMSAA = capComp.useMSAA;
97
98 if (!capData.encoder) {
99 capData.encoder = context->videoEncoderContext->createVideoEncoder(desc);
100
101 if (!capData.encoder) {
102 // If we failed to create an encoder, don't try again for three seconds.
103 // (Or when the application specifically requests it through the VideoCaptureComponent.)
104 capData.nextRestartTime = now + 3000;
105 continue;
106 }
107 else {
108 capData.nextRestartTime = 0;
109 }
110 }
111 else {
112 capData.encoder->reconfigure(desc, false, true);
113 }
114 capComp.width = desc.encodeWidth;
115 capComp.height = desc.encodeHeight;
116 capComp.maxWidth = desc.maxWidth;
117 capComp.maxHeight = desc.maxHeight;
118 capComp.bFrameCount = desc.bFrameCount;
119 capComp.restart = false;
120 capComp.reconfig = false;
121
122 camComp->renderTexture = capData.encoder->getRenderTarget();
123 }
124 if (!capData.encoder || capComp.endOfStream) {
125 continue;
126 }
127 camComp->resolveTarget = capData.encoder->getNextInputBuffer();
128 camComp->viewportSize = glm::vec2(0, 0);
129#ifndef _WIN32
130 camComp->flags |= CameraFlags::FlipY;
131#endif
132 camComp->setChanged();
133 }
134}
135
136void Cogs::Core::VideoCaptureSystem::postRender(Context * context)
137{
138 if (!context->videoEncoderContext) {
139 return;
140 }
141 for (auto& capComp : pool) {
142 CameraComponent* camComp = capComp.getComponent<CameraComponent>();
143
144 if (!camComp) {
145 continue;
146 }
147 if (!camComp->renderTexture) {
148 continue;
149 }
151 continue;
152 }
153 auto & capData = getData(&capComp);
154 if (!capData.encoder) {
155 continue;
156 }
157 if (capComp.endOfStream) {
158 if (capData.encoder) {
159 context->videoEncoderContext->destroyVideoEncoder(capData.encoder);
160 capData.encoder = nullptr;
161 }
162 continue;
163 }
164 int64_t now = Timer::currentTimeMilliseconds();
165
166 if (capData.nextEncodeTime < now) {
167 capData.nextEncodeTime = now + capComp.frameInterval;
168
170
171 input.texture = camComp->resolveTarget;
172 input.timestamp = capComp.timestamp;
173 input.duration = capComp.duration;
174 input.forceIntra = capComp.forceIntra;
175 input.forceIDR = capComp.forceIDR;
176 input.outputSPSPPS = capComp.outputSPSPPS;
177
178 capData.encoder->encode(input);
179 capComp.forceIntra = false;
180 capComp.forceIDR = false;
181 capComp.outputSPSPPS = false;
182 }
183 }
184}
185
187{
188 if (context->videoEncoderContext){
190 VideoCaptureData& capData = getData(vcComp);
191
192#ifndef _WIN32
193 CameraComponent* camComp = vcComp->getComponent<CameraComponent>();
194
195 if (camComp) {
196 camComp->flags &= ~CameraFlags::FlipY;
197 camComp->setChanged();
198 }
199#endif
200
201 if(capData.encoder){
202 context->videoEncoderContext->destroyVideoEncoder(capData.encoder);
203 capData.encoder = nullptr;
204 }
205 }
207}
void setChanged()
Sets the component to the ComponentFlags::Changed state with carry.
Definition: Component.h:202
ComponentType * getComponent() const
Definition: Component.h:159
CameraFlags flags
Camera behavior flags.
glm::vec2 viewportSize
Size of the viewport covered by this instance, given in pixels.
TextureHandle resolveTarget
The texture to which the rendered output will be resolved. (Needs an offscreen renderTexture for this...
TextureHandle renderTexture
The render texture to output the rendered scene from the camera to.
virtual void cleanup(Context *)
Provided for custom cleanup logic in derived systems.
Context * context
Pointer to the Context instance the system lives in.
virtual void initialize(Context *context)
Initialize the system.
virtual void destroyComponent(ComponentHandle)
Destroy the component held by the given handle.
void update()
Updates the system state to that of the current frame.
void preUpdate()
Run the pre-update method of the system.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
class IRenderer * renderer
Renderer.
Definition: Context.h:228
virtual void registerExtension(IRendererExtension *extension)=0
Register an extension with the renderer.
virtual void unregisterExtension(IRendererExtension *extension)=0
Unregister an extension with the renderer.
void destroyComponent(ComponentHandle component) override
void initialize(Context *context) override
Initialize the system.
void cleanup(Context *context) override
Provided for custom cleanup logic in derived systems.
Log implementation class.
Definition: LogManager.h:140
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
@ EnableRender
Renderable.
@ FlipY
Flip the y-axis.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
Handle to a Component instance.
Definition: Component.h:67
ComponentType * resolveComponent() const
Definition: Component.h:90