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 }
78
79 desc.codec = capComp.codec;
80 desc.encodeWidth = capComp.width;
81 desc.encodeHeight = capComp.height;
82 desc.darWidth = desc.encodeWidth;
83 desc.darHeight = desc.encodeHeight;
84 desc.maxWidth = capComp.maxWidth;
85 desc.maxHeight = capComp.maxHeight;
86 desc.bitrate = capComp.bitrate;
87 desc.maxBitrate = capComp.maxBitrate;
88 desc.bFrameCount = capComp.bFrameCount;
89 desc.bFrameReference = (uint32_t)capComp.bFrameReference;
90 desc.frameRate = 1000.0f / capComp.frameInterval;
91 desc.lookahead = capComp.lookahead;
92 desc.recordToDisk = capComp.recordToDisk;
93 desc.recordPath = capComp.recordPath;
94 desc.callback = capComp.callback;
95 desc.useMSAA = capComp.useMSAA;
96
97 if(!capData.encoder || capComp.restart) {
98 capData.encoder = context->videoEncoderContext->createVideoEncoder(desc);
99
100 if (!capData.encoder) {
101 // If we failed to create an encoder, don't try again for three seconds.
102 // (Or when the application specifically requests it through the VideoCaptureComponent.)
103 capData.nextRestartTime = now + 3000;
104 }
105 else {
106 capData.nextRestartTime = 0;
107 }
108 }
109 else {
110 capData.encoder->reconfigure(desc, false, true);
111 }
112 capComp.width = desc.encodeWidth;
113 capComp.height = desc.encodeHeight;
114 capComp.maxWidth = desc.maxWidth;
115 capComp.maxHeight = desc.maxHeight;
116 capComp.bFrameCount = desc.bFrameCount;
117 capComp.restart = false;
118 capComp.reconfig = false;
119
120 camComp->renderTexture = capData.encoder->getRenderTarget();
121 }
122 if (!capData.encoder || capComp.endOfStream) {
123 continue;
124 }
125 camComp->resolveTarget = capData.encoder->getNextInputBuffer();
126 camComp->viewportSize = glm::vec2(0, 0);
127#ifndef _WIN32
128 camComp->flags |= CameraFlags::FlipY;
129#endif
130 camComp->setChanged();
131 }
132}
133
134void Cogs::Core::VideoCaptureSystem::postRender(Context * context)
135{
136 if (!context->videoEncoderContext) {
137 return;
138 }
139 for (auto& capComp : pool) {
140 CameraComponent* camComp = capComp.getComponent<CameraComponent>();
141
142 if (!camComp) {
143 continue;
144 }
145 if (!camComp->renderTexture) {
146 continue;
147 }
149 continue;
150 }
151 auto & capData = getData(&capComp);
152 if (!capData.encoder) {
153 continue;
154 }
155 if (capComp.endOfStream) {
156 if (capData.encoder) {
157 context->videoEncoderContext->destroyVideoEncoder(capData.encoder);
158 capData.encoder = nullptr;
159 }
160 continue;
161 }
162 int64_t now = Timer::currentTimeMilliseconds();
163
164 if (capData.nextEncodeTime < now) {
165 capData.nextEncodeTime = now + capComp.frameInterval;
166
168
169 input.texture = camComp->resolveTarget;
170 input.timestamp = capComp.timestamp;
171 input.duration = capComp.duration;
172 input.forceIntra = capComp.forceIntra;
173 input.forceIDR = capComp.forceIDR;
174 input.outputSPSPPS = capComp.outputSPSPPS;
175
176 capData.encoder->encode(input);
177 capComp.forceIntra = false;
178 capComp.forceIDR = false;
179 capComp.outputSPSPPS = false;
180 }
181 }
182}
183
185{
186 if (context->videoEncoderContext){
188 VideoCaptureData& capData = getData(vcComp);
189
190#ifndef _WIN32
191 CameraComponent* camComp = vcComp->getComponent<CameraComponent>();
192
193 if (camComp) {
194 camComp->flags &= ~CameraFlags::FlipY;
195 camComp->setChanged();
196 }
197#endif
198
199 if(capData.encoder){
200 context->videoEncoderContext->destroyVideoEncoder(capData.encoder);
201 capData.encoder = nullptr;
202 }
203 }
205}
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:139
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:180
Handle to a Component instance.
Definition: Component.h:67
ComponentType * resolveComponent() const
Definition: Component.h:90