CVB++ 14.0
recorder.hpp
1#pragma once
2
3#include <memory>
4
5#include "../global.hpp"
6#include "../exception.hpp"
7#include "../string.hpp"
8#include "../size_2d.hpp"
9
10#include "../image.hpp"
11
12#include "movie2.hpp"
13#include "recording_settings.hpp"
14
15#include "_detail/detail_recording_engine.hpp"
16
17namespace Cvb
18{
19
20CVB_BEGIN_INLINE_NS
21
22
23template <>
24inline HandleGuard<Movie2::Recorder>::HandleGuard(void * handle) noexcept
25 : HandleGuard<Movie2::Recorder>(handle, [](void* handle) { CVB_CALL_CAPI(ReleaseObject(handle)); })
26{
27}
28
29namespace Movie2
30{
31
33
67{
68
69 public:
70
72
79 static RecorderPtr FromHandle(HandleGuard<Recorder>&& guard)
80 {
81 if (!guard.Handle())
82 throw std::runtime_error("handle must not be null");
83
84 return std::unique_ptr<Recorder>(new Recorder(std::move(guard)));
85 }
86
88
96 static std::unique_ptr<Recorder> Create(const String & path, Size2D<int> size, RecorderPixelFormat pixelFormat, const RecordingSettings& settings)
97 {
98 return Create(path, size, pixelFormat, Private::RecordingEngine::Create(settings));
99 }
100
102
110 {
111 return Create(path, size, pixelFormat, Private::RecordingEngine::Create(DirectShowSettings()));
112 }
113
115
121 void * Handle() const noexcept
122 {
123 return handle_.Handle();
124 }
125
127
132 void Write(const Image & image, const String & metaData = String())
133 {
134 metaData_ = metaData;
135
136 auto res = CVB_CALL_CAPI(Movie2SetImage(Handle(), image.Handle()));
137 if (res != CExports::CVC_E_OK)
138 Utilities::SystemInfo::ThrowLastError();
139
140 res = CVB_CALL_CAPI(Movie2AddFrame(Handle()));
141 if (res != CExports::CVC_E_OK)
142 Utilities::SystemInfo::ThrowLastError();
143 }
144
145 virtual ~Recorder()
146 {
147 if (Handle())
148 {
149 CExports::Movie2StopRecording(Handle());
150 }
151 }
152
153 Recorder(HandleGuard<Recorder>&& guard) noexcept
154 : handle_(std::move(guard))
155 {
156 }
157
158 private:
159
160 Recorder(Recorder && other) noexcept
161 : handle_(std::move(other.handle_))
162 {
163 }
164
165 Recorder(const String & path, Size2D<int> size, RecorderPixelFormat pixelFormat, Private::RecordingEnginePtr engine)
166 : Recorder(std::move(*CreateRecorder(size, pixelFormat, engine)))
167 {
168 // After creating recorder
169 // configure the engine
170 ConfigureEngine(engine);
171 // and start recording
172 Record(path);
173 }
174
175 static std::unique_ptr<Recorder> Create(const String & path, Size2D<int> size, RecorderPixelFormat pixelFormat, Private::RecordingEnginePtr engine)
176 {
177 return std::unique_ptr<Recorder>(new Recorder(path, size, pixelFormat, engine));
178 }
179
180 static RecorderPtr CreateRecorder(Size2D<int> size, RecorderPixelFormat pixelFormat, Private::RecordingEnginePtr engine)
181 {
182 intptr_t dummyBuffer = 0;
183 auto dummyImage = (pixelFormat == RecorderPixelFormat::Mono)
184 ? WrappedImage::FromGreyPixels(&dummyBuffer, size.Width() * size.Height(), size.Width(), size.Height(), DataType::Int8BppUnsigned(), 1, size.Width())
185 : WrappedImage::FromRgbPixels(&dummyBuffer, size.Width() * size.Height() * 3, size.Width(), size.Height(), DataType::Int8BppUnsigned(), 3, size.Width() * 3, 1);
186
187 HandleGuard<Recorder> guard(CExports::CreateMovie2RecorderEx(static_cast<CExports::Movie2_RecordingEngine>(engine->Settings().EngineType()), dummyImage->Handle()));
188 if (!guard.Handle())
189 throw std::runtime_error("failed to create movie recorder");
190
191 return std::make_unique<Recorder>(std::move(guard));
192 }
193
194 void ConfigureEngine(Private::RecordingEnginePtr engine)
195 {
196 engine_ = engine;
197
198 if (engine_->Settings().EngineType() == RecordingEngineType::DirectShow)
199 ConfigureDirectShowEngine();
200 else if (engine_->Settings().EngineType() == RecordingEngineType::RawVideo)
201 ConfigureRawVideoEngine();
202 }
203
204 void ConfigureDirectShowEngine()
205 {
206 auto directShowEngine = std::dynamic_pointer_cast<Private::DirectShowEngine>(engine_);
207 const auto& settings = directShowEngine->Settings();
208
209 CVB_CALL_CAPI(Movie2SetSyncMode(Handle(), CExports::Movie2_SyncAfterCopy));
210 CVB_CALL_CAPI(Movie2SetAcqMode(Handle(), CExports::Movie2_AcqAddFrame));
211 CVB_CALL_CAPI(Movie2SetCompressorIndex(Handle(), static_cast<CExports::cvbval_t>(settings.CodecIndex())));
212 CVB_CALL_CAPI(Movie2SetFrameRate(Handle(), settings.FrameRate()));
213 CVB_CALL_CAPI(Movie2SetUseMetadata(Handle(), (settings.UseMetaData()) ? 1 : 0));
214
215 if (settings.UseMetaData())
216 {
217 Internal::DoResCall([&]()
218 {
219 CExports::pfMovie2ProvideMetaData metaDataCallback = [](CExports::MOVIE2RECORDER, char* szMetaData, CExports::cvbval_t BufferSize, void* pUserData)
220 {
221 if (szMetaData && BufferSize > 0)
222 {
223 auto recorder = reinterpret_cast<Cvb::Movie2::Recorder*>(pUserData);
224 auto metaData = recorder->metaData_;
225
226 std::string metaDataAscii(Internal::CastToAscii (metaData));
227 size_t charsToCopy = std::min(metaData.size(), static_cast<std::size_t>(BufferSize) - 1);
228 std::copy_n(metaDataAscii.begin(), charsToCopy, szMetaData);
229 szMetaData[charsToCopy] = 0;
230 }
231 };
232
233 CExports::cvbval_t dummy = 0;
234 return CVB_CALL_CAPI(Movie2RegisterMetaDataCallback(Handle(), metaDataCallback, this, dummy));
235 });
236 }
237 }
238
239 void ConfigureRawVideoEngine()
240 {
241 const auto& settings = engine_->Settings();
242 CVB_CALL_CAPI(Movie2SetSyncMode(Handle(), CExports::Movie2_SyncAfterCopy));
243 CVB_CALL_CAPI(Movie2SetAcqMode(Handle(), CExports::Movie2_AcqAddFrame));
244 Internal::DoResCall([&]()
245 {
246 return CVB_CALL_CAPI(Movie2SetFrameRate(Handle(), settings.FrameRate()));
247 });
248 }
249
250 void Record(const String & path)
251 {
252 auto res = CExports::Movie2SetTargetFileNameTyped(Handle(), path.c_str());
253 if (res != CExports::CVC_E_OK)
254 Utilities::SystemInfo::ThrowLastError();
255
256 Internal::DoResCall([&]()
257 {
258 return CVB_CALL_CAPI(Movie2StartRecording(Handle()));
259 });
260 }
261
262 private:
263 HandleGuard<Recorder> handle_;
264 Private::RecordingEnginePtr engine_;
265 String metaData_;
266};
267
268}
269
270
271CVB_END_INLINE_NS
272
273}
274
275
static DataType Int8BppUnsigned() noexcept
Represents 8-bit unsigned integer pixels (bytes).
Definition: data_type.hpp:47
The Common Vision Blox image.
Definition: decl_image.hpp:45
Settings for initializing a direct show engine recorder.
Definition: recording_settings.hpp:94
Movie recorder for writing video files to disk.
Definition: recorder.hpp:67
static RecorderPtr FromHandle(HandleGuard< Recorder > &&guard)
Creates a recorder from a classic API handle.
Definition: recorder.hpp:79
static std::unique_ptr< Recorder > Create(const String &path, Size2D< int > size, RecorderPixelFormat pixelFormat)
Creates a recorder object writing video streams with the given pixel format. Uses the DirectShowEngin...
Definition: recorder.hpp:109
static std::unique_ptr< Recorder > Create(const String &path, Size2D< int > size, RecorderPixelFormat pixelFormat, const RecordingSettings &settings)
Creates a recorder object writing video streams with the given pixel format and recording engine.
Definition: recorder.hpp:96
void Write(const Image &image, const String &metaData=String())
Writes the given image into the stream.
Definition: recorder.hpp:132
void * Handle() const noexcept
Classic API classifier handle.
Definition: recorder.hpp:121
Settings for initializing a recorder.
Definition: recording_settings.hpp:22
T Height() const noexcept
Gets the vertical component of the size.
Definition: size_2d.hpp:79
T Width() const noexcept
Gets the horizontal component of the size.
Definition: size_2d.hpp:59
static std::unique_ptr< WrappedImage > FromRgbPixels(void *buffer, int bufferSize, int width, int height, DataType dataType, int pixelStride, int lineStride, int planeStride)
Wraps, without copying, the given RGB pixel buffer in a CvbImage.
Definition: decl_wrapped_image.hpp:80
static std::unique_ptr< WrappedImage > FromGreyPixels(void *buffer, int bufferSize, int width, int height, DataType dataType, int pixelStride, int lineStride)
Wraps, without copying, the given monochrome pixel buffer in an image.
Definition: decl_wrapped_image.hpp:47
T move(T... args)
std::shared_ptr< Recorder > RecorderPtr
Convenience shared pointer for Recorder.
Definition: movie2.hpp:27
RecorderPixelFormat
Defines whether the recorder object writes color or mono data.
Definition: movie2.hpp:32
@ Mono
Recorder writes single-plane monochrome data.
@ DirectShow
Use DirectShow framework for recording AVI files.
@ RawVideo
Use RawVideo for recording raw video.
Root namespace for the Image Manager interface.
Definition: c_barcode.h:24
std::string String
String for wide characters or unicode characters.
Definition: string.hpp:45