avb++.h¶
#include <primo/avblocks/avb++.h>
Includes¶
primo/avblocks/avb.hprimo/platform/error_facility.hprimo/platform/reference++.hprimo/platform/ustring.hstringconceptstype_traitsmemoryfunctionaloptionalstdexcept
Classes¶
Name |
Description |
|---|---|
Exception thrown when an AVBlocks operation fails. |
|
Fluent wrapper for primo::codecs::AudioStreamInfo, which describes an elementary audio stream. |
|
Fluent wrapper for a generic data stream. |
|
Copy of the error information reported by AVBlocks: facility, code, message and hint. |
|
RAII owner of the AVBlocks library and a static facade over primo::avblocks::Library. |
|
Fluent wrapper for primo::license::LicenseInfo, which describes the license state of the library. |
|
Fluent wrapper for primo::codecs::MediaBuffer, a buffer for media data. |
|
Fluent wrapper for primo::avblocks::MediaInfo, which analyzes a file or a stream and reports its type and properties. |
|
Fluent wrapper for primo::avblocks::MediaPin, which represents an elementary media stream. |
|
Non-owning view of a MediaPinList. |
|
Fluent wrapper for primo::codecs::MediaSample, one or more samples of audio or video data. |
|
Non-owning view of a MediaSocketList. |
|
Fluent wrapper for primo::avblocks::MediaSocket, an input or output point of a transcoder. |
|
Fluent wrapper for primo::codecs::MetaAttribute. |
|
Non-owning view of a MetaAttributeList. |
|
Fluent wrapper for primo::codecs::MetaPicture. |
|
Non-owning view of a MetaPictureList. |
|
Fluent wrapper for primo::codecs::Metadata. |
|
CRTP mixin that adds the typed, fluent addParam() to a class that owns a primo::avblocks::ParameterList (TMediaPin and TMediaSocketT). |
|
CRTP base for TAudioStreamInfo, TVideoStreamInfo, and TDataStreamInfo. |
|
Internal adapter that bridges std::function callbacks to the raw primo::avblocks::TranscoderCallback interface. |
|
Fluent wrapper for primo::avblocks::Transcoder, which encodes, decodes and transforms audio and video. |
|
Fluent wrapper for primo::codecs::VideoStreamInfo, which describes an elementary video stream. |
Namespaces¶
primoprimo::avblocksprimo::avblocks::modern
Macros and Functions¶
Source¶
1#pragma once
2
3#include <primo/avblocks/avb.h>
4#include <primo/platform/error_facility.h>
5#include <primo/platform/reference++.h>
6#include <primo/platform/ustring.h>
7
8#include <string>
9#include <concepts>
10#include <type_traits>
11#include <memory>
12#include <functional>
13#include <optional>
14#include <stdexcept>
15
16#ifndef TRUE
17#define TRUE 1
18#endif
19
20#ifndef FALSE
21#define FALSE 0
22#endif
23
24namespace primo::avblocks::modern {
25
26/**
27 * RAII owner of the AVBlocks library and a static facade over @c primo::avblocks::Library.
28 *
29 * Constructing a @c TLibrary initializes the library and destroying it shuts the library down. Create one
30 * instance before using any other class in this header and keep it alive for as long as AVBlocks is used.
31 * The static members mirror the functions of the @c primo::avblocks::Library namespace.
32 *
33 * Not copyable and not movable.
34 * @code
35 * TLibrary lib;
36 * std::cout << TLibrary::description() << std::endl;
37 * @endcode
38 */
39class TLibrary {
40public:
41 /// Initializes the AVBlocks library.
42 TLibrary() {
43 primo::avblocks::Library::initialize();
44 }
45
46 /// Shuts the AVBlocks library down and frees the resources it uses.
47 ~TLibrary() {
48 primo::avblocks::Library::shutdown();
49 }
50
51 TLibrary(const TLibrary&) = delete;
52 TLibrary& operator=(const TLibrary&) = delete;
53 TLibrary(TLibrary&&) = delete;
54 TLibrary& operator=(TLibrary&&) = delete;
55
56 // ---- Static accessors mirroring primo::avblocks::Library namespace ----
57
58 /**
59 * Initializes the library. Must be called once before the library is used unless a @c TLibrary instance
60 * is created.
61 * @return @c true if the library is initialized successfully.
62 */
63 static bool initialize() {
64 return primo::avblocks::Library::initialize() == TRUE;
65 }
66
67 /// Closes the library and frees the resources it uses. Call it when the library is not needed anymore.
68 static void shutdown() {
69 primo::avblocks::Library::shutdown();
70 }
71
72 /**
73 * Returns the build description: full version, architecture, configuration (Release/Debug),
74 * license (OEM/Demo) and platform.
75 */
76 static const char* description() {
77 return primo::avblocks::Library::description();
78 }
79
80 /// Returns the library major version.
81 static int32_t majorVersion() {
82 return primo::avblocks::Library::majorVersion();
83 }
84
85 /// Returns the library minor version.
86 static int32_t minorVersion() {
87 return primo::avblocks::Library::minorVersion();
88 }
89
90 /// Returns the library patch version. It changes for bug fixes and small improvements that do not affect the API.
91 static int32_t patchVersion() {
92 return primo::avblocks::Library::patchVersion();
93 }
94
95 /**
96 * Sets whether TLS (Transport Layer Security) is used to validate the license. TLS is not used by default.
97 * Call it before @c setLicense() to have an effect.
98 * @param useTls @c true to validate the license over TLS.
99 */
100 static void setLicenseTls(bool useTls) {
101 primo::avblocks::Library::setLicenseTls(useTls ? TRUE : FALSE);
102 }
103
104 /**
105 * Sets a license string. The license is appended to the library license state.
106 * @param license The license string. If @c nullptr the library license state is cleared.
107 * @return The license status after the license is set, as a combination of
108 * @c primo::license::LicenseStatusFlags::Enum flags.
109 */
110 static int32_t setLicense(const char* license) {
111 return primo::avblocks::Library::setLicense(license);
112 }
113};
114
115/**
116 * Fluent wrapper for @c primo::license::LicenseInfo, which describes the license state of the library.
117 *
118 * Owns the raw object through a @c primo::ref. Not copyable, movable.
119 */
120class TLicenseInfo {
121 primo::ref<primo::license::LicenseInfo> info_;
122
123public:
124 /**
125 * Creates a license info object for the library (@c Library::createLicenseInfo).
126 */
127 TLicenseInfo()
128 : info_(primo::avblocks::Library::createLicenseInfo()) {}
129
130 /**
131 * Takes ownership of an existing @c LicenseInfo reference.
132 */
133 explicit TLicenseInfo(primo::ref<primo::license::LicenseInfo> info)
134 : info_(std::move(info)) {}
135
136 // Non-copyable, movable
137 TLicenseInfo(const TLicenseInfo&) = delete;
138 TLicenseInfo& operator=(const TLicenseInfo&) = delete;
139 /// @{
140 /// Move construction/assignment transfers ownership of the underlying object. The moved-from object no longer wraps anything.
141 TLicenseInfo(TLicenseInfo&&) = default;
142 TLicenseInfo& operator=(TLicenseInfo&&) = default;
143 /// @}
144
145 /// Returns the current license status as a combination of LicenseStatusFlags::Enum flags.
146 primo::license::LicenseStatusFlags::Enum licenseStatus() const {
147 return static_cast<primo::license::LicenseStatusFlags::Enum>(info_->licenseStatus());
148 }
149
150 /// Returns true if the specified product/feature is licensed.
151 /// Pass nullptr for product/feature to use library defaults.
152 bool isLicensed(const char* product = nullptr, const char* feature = nullptr) const {
153 return info_->isLicensed(product, feature) == TRUE;
154 }
155
156 /// Returns the raw underlying pointer. For interop with the core API only.
157 primo::license::LicenseInfo* get() const { return info_.get(); }
158};
159
160/**
161 * Copy of the error information reported by AVBlocks: facility, code, message and hint.
162 *
163 * The strings are copied out of the source @c primo::error::ErrorInfo, so a @c TErrorInfo stays valid after
164 * the source object is gone. A default-constructed @c TErrorInfo is empty.
165 */
166class TErrorInfo {
167 int32_t facility_{};
168 int32_t code_{};
169 std::string message_;
170 std::string hint_;
171
172public:
173 /// Creates an empty error info: zero facility and code, empty message and hint.
174 TErrorInfo() = default;
175
176 /**
177 * Copies the error information from @p error.
178 * @param error The error to copy. If @c nullptr the result is an empty error info.
179 */
180 explicit TErrorInfo(const primo::error::ErrorInfo* error) {
181 if (error) {
182 facility_ = error->facility();
183 code_ = error->code();
184 if (error->message()) message_ = std::string(primo::ustring(error->message()));
185 if (error->hint()) hint_ = std::string(primo::ustring(error->hint()));
186 }
187 }
188
189 /// Returns the error facility, i.e. the component that reports the error.
190 int32_t facility() const { return facility_; }
191 /// Returns the error code. Its meaning depends on the facility.
192 int32_t code() const { return code_; }
193 /// Returns the error message, a textual representation of the error code. Empty if not set.
194 const std::string& message() const { return message_; }
195 /// Returns a diagnostic hint, suitable for error logs and debugging. Empty if not set.
196 const std::string& hint() const { return hint_; }
197};
198
199/**
200 * Exception thrown when an AVBlocks operation fails.
201 *
202 * @c what() returns the context of the failure followed by the error message, when there is one.
203 * Use @c error() to get the complete error information.
204 */
205class TAVBlocksException : public std::runtime_error {
206 TErrorInfo error_;
207public:
208 /**
209 * Creates the exception.
210 * @param context Short description of the failed operation, e.g. "Failed to open transcoder".
211 * @param error Error information reported by AVBlocks.
212 */
213 TAVBlocksException(const char* context, const TErrorInfo& error)
214 : std::runtime_error(
215 error.message().empty()
216 ? std::string(context)
217 : std::string(context) + ": " + error.message())
218 , error_(error) {}
219
220 /// Returns the error information reported by AVBlocks.
221 const TErrorInfo& error() const { return error_; }
222};
223
224/**
225 * Fluent wrapper for @c primo::codecs::MediaBuffer, a buffer for media data.
226 *
227 * A buffer has a capacity, which is the size of its memory block, and a data range, the part of the block that
228 * holds valid data. The valid data is contiguous and can start at any offset in the block.
229 *
230 * Owns the raw object through a @c primo::ref. Not copyable, movable.
231 */
232class TMediaBuffer {
233 primo::ref<primo::codecs::MediaBuffer> buffer_;
234
235public:
236 /// Creates an empty buffer with zero capacity.
237 TMediaBuffer()
238 : buffer_(primo::avblocks::Library::createMediaBuffer()) {}
239
240 /**
241 * Creates a buffer with internal storage.
242 * @param capacity Buffer capacity in bytes.
243 */
244 explicit TMediaBuffer(int32_t capacity)
245 : buffer_(primo::avblocks::Library::createMediaBuffer(capacity)) {}
246
247 /**
248 * Takes ownership of an existing @c MediaBuffer reference.
249 */
250 explicit TMediaBuffer(primo::ref<primo::codecs::MediaBuffer> buffer)
251 : buffer_(std::move(buffer)) {}
252
253 /**
254 * Wraps a non-owned @c MediaBuffer pointer, retaining it.
255 */
256 explicit TMediaBuffer(primo::codecs::MediaBuffer* buffer)
257 : buffer_(buffer) { if (buffer) buffer->retain(); }
258
259 // Delete copy operations
260 TMediaBuffer(const TMediaBuffer&) = delete;
261 TMediaBuffer& operator=(const TMediaBuffer&) = delete;
262
263 // Enable move operations
264 /// @{
265 /// Move construction/assignment transfers ownership of the underlying object. The moved-from object no longer wraps anything.
266 TMediaBuffer(TMediaBuffer&&) = default;
267 TMediaBuffer& operator=(TMediaBuffer&&) = default;
268 /// @}
269
270 /// @{
271 /**
272 * Attaches an external memory block as the buffer storage. Any internal storage is freed.
273 * The block is not copied and must stay valid for as long as it is attached.
274 * @param data Pointer to the memory block.
275 * @param size Size of the block in bytes.
276 * @param copy When @c true (default) the whole block is marked as valid data, i.e. @c dataSize() equals
277 * @p size. When @c false the data size is 0.
278 * @return This object, for chaining.
279 */
280 TMediaBuffer&& attach(const uint8_t* data, size_t size, bool copy = true) && {
281 buffer_->attach(const_cast<uint8_t*>(data), static_cast<int32_t>(size), copy ? TRUE : FALSE);
282 return std::move(*this);
283 }
284
285 TMediaBuffer& attach(const uint8_t* data, size_t size, bool copy = true) & {
286 buffer_->attach(const_cast<uint8_t*>(data), static_cast<int32_t>(size), copy ? TRUE : FALSE);
287 return *this;
288 }
289 /// @}
290
291 // -- Getters --
292
293 /**
294 * Returns a pointer to the start of the buffer block. It is valid only when @c capacity() is greater than 0.
295 */
296 uint8_t* start() const { return buffer_->start(); }
297 /// Returns the size of the buffer block in bytes. Can be zero.
298 int32_t capacity() const { return buffer_->capacity(); }
299 /**
300 * Returns @c true if the buffer uses an external memory block attached with @c attach().
301 */
302 bool external() const { return buffer_->external() == TRUE; }
303 /**
304 * Returns a pointer to the first byte of valid data. Same as @c start() + @c dataOffset().
305 */
306 const uint8_t* data() const { return buffer_->data(); }
307 /**
308 * Returns the size of the valid data in bytes, from 0 to @c capacity().
309 */
310 int32_t dataSize() const { return buffer_->dataSize(); }
311 /// Returns the offset in bytes at which the valid data starts in the buffer block.
312 int32_t dataOffset() const { return buffer_->dataOffset(); }
313 /**
314 * Returns the free space in bytes that can be used to append data without reallocation: @c capacity() - @c dataSize().
315 */
316 int32_t freeSpace() const { return buffer_->freeSpace(); }
317 /**
318 * Returns the contiguous free space in bytes after the valid data, which can be used to append data without
319 * @c normalize(): @c capacity() - @c dataSize() - @c dataOffset(). It is at most @c freeSpace().
320 */
321 int32_t freeLinearSpace() const { return buffer_->freeLinearSpace(); }
322
323 // -- Fluent setter --
324
325 /**
326 * Sets the range of valid data. Both values are validated so that the range is always inside the buffer.
327 * @param offset Offset at which valid data starts, from 0 to @c capacity() - 1.
328 * @param size Size of the valid data, from 0 to @c capacity().
329 * @return This object, for chaining.
330 */
331 TMediaBuffer& setData(int32_t offset, int32_t size) {
332 buffer_->setData(offset, size);
333 return *this;
334 }
335
336 // -- Operations --
337
338 /**
339 * Allocates internal storage. Storage is allocated only if @p size exceeds the current capacity;
340 * the actual capacity may be larger than requested.
341 * @param size Requested size in bytes.
342 * @param keepData Whether to keep the existing data when the storage is reallocated.
343 * @return @c true on success.
344 */
345 bool alloc(int32_t size, bool keepData) {
346 return buffer_->alloc(size, keepData ? TRUE : FALSE) == TRUE;
347 }
348
349 /**
350 * Allocates internal storage with the specified memory alignment. Storage is allocated only if @p size
351 * exceeds the current capacity.
352 * @param alignment Alignment in bytes. Must be a power of 2 and at least 8.
353 * @param size Requested size in bytes.
354 * @param keepData Whether to keep the existing data when the storage is reallocated.
355 * @return @c true on success.
356 */
357 bool alignedAlloc(int32_t alignment, int32_t size, bool keepData) {
358 return buffer_->alignedAlloc(alignment, size, keepData ? TRUE : FALSE) == TRUE;
359 }
360
361 /// Frees the internal storage. Does nothing if an external memory block is attached. Returns this object, for chaining.
362 TMediaBuffer& free() {
363 buffer_->free();
364 return *this;
365 }
366
367 /// Clears the data. The capacity does not change. Returns this object, for chaining.
368 TMediaBuffer& clear() {
369 buffer_->clear();
370 return *this;
371 }
372
373 /**
374 * Moves the valid data to the start of the buffer, which maximizes the free linear space. Useful after data
375 * is added by copying it directly after the existing data and then extended with @c setData().
376 * The capacity does not change. Returns this object, for chaining.
377 */
378 TMediaBuffer& normalize() {
379 buffer_->normalize();
380 return *this;
381 }
382
383 /**
384 * Appends data to the end of the valid data. Internal storage grows when needed; external storage does not.
385 * @param data Pointer to the data to append.
386 * @param dataSize Number of bytes to append.
387 * @return @c true on success.
388 */
389 bool append(const void* data, int32_t dataSize) {
390 return buffer_->append(data, dataSize) == TRUE;
391 }
392
393 /**
394 * Removes data from the beginning of the valid data. The capacity does not change.
395 * @param dataSize Number of bytes to remove.
396 * @return This object, for chaining.
397 */
398 TMediaBuffer& remove(int32_t dataSize) {
399 buffer_->remove(dataSize);
400 return *this;
401 }
402
403 /**
404 * Detaches the external memory block. Returns a pointer to it, or @c nullptr if none was attached.
405 */
406 uint8_t* detach() {
407 return buffer_->detach();
408 }
409
410 /// Creates a deep copy. If the buffer uses an external memory block only the pointer to it is copied.
411 TMediaBuffer clone() const {
412 return TMediaBuffer(primo::ref<primo::codecs::MediaBuffer>(buffer_->clone()));
413 }
414
415 /// Returns the raw underlying pointer. For interop with the core API only.
416 primo::codecs::MediaBuffer* get() const { return buffer_.get(); }
417};
418
419/**
420 * Fluent wrapper for @c primo::codecs::MediaSample, one or more samples of audio or video data.
421 *
422 * Holds compressed or uncompressed data in a @c TMediaBuffer together with timing and stream information.
423 * Owns the raw object through a @c primo::ref. Not copyable, movable.
424 */
425class TMediaSample {
426 primo::ref<primo::codecs::MediaSample> sample_;
427
428public:
429 /// Creates an empty media sample.
430 TMediaSample()
431 : sample_(primo::avblocks::Library::createMediaSample()) {}
432
433 /**
434 * Takes ownership of an existing @c MediaSample reference.
435 */
436 explicit TMediaSample(primo::ref<primo::codecs::MediaSample> sample)
437 : sample_(std::move(sample)) {}
438
439 // Delete copy operations
440 TMediaSample(const TMediaSample&) = delete;
441 TMediaSample& operator=(const TMediaSample&) = delete;
442
443 // Enable move operations
444 /// @{
445 /// Move construction/assignment transfers ownership of the underlying object. The moved-from object no longer wraps anything.
446 TMediaSample(TMediaSample&&) = default;
447 TMediaSample& operator=(TMediaSample&&) = default;
448 /// @}
449
450 // -- Fluent buffer setters --
451
452 /// @{
453 /**
454 * Sets the buffer of the sample. The sample retains the buffer and releases the previous one.
455 * @param buf The new buffer.
456 * @return This object, for chaining.
457 */
458 TMediaSample&& buffer(TMediaBuffer&& buf) && {
459 sample_->setBuffer(buf.get());
460 return std::move(*this);
461 }
462
463 TMediaSample& buffer(TMediaBuffer&& buf) & {
464 sample_->setBuffer(buf.get());
465 return *this;
466 }
467 /// @}
468
469 /// Removes the buffer from the sample. Returns this object, for chaining.
470 TMediaSample& buffer(std::nullptr_t) {
471 sample_->setBuffer(nullptr);
472 return *this;
473 }
474
475 // -- Const getters --
476
477 /// Returns the buffer of the sample. The returned wrapper is invalid if the sample has no buffer.
478 TMediaBuffer buffer() const {
479 return TMediaBuffer(sample_->buffer());
480 }
481
482 /// Returns the presentation timestamp (PTS) of the sample in seconds.
483 double startTime() const { return sample_->startTime(); }
484 /// Returns the end time of the sample in seconds. It is optional and valid only if greater than the start time.
485 double endTime() const { return sample_->endTime(); }
486 /**
487 * Returns the sample flags, a combination of @c primo::codecs::MediaSampleFlags::Enum values.
488 */
489 int32_t flags() const { return sample_->flags(); }
490 /// Returns the zero-based index of the elementary stream in the container to which the sample belongs.
491 int32_t streamNumber() const { return sample_->streamNumber(); }
492
493 /// Returns the picture type (I/P/B/etc.) of a demuxed, decoded or encoded frame. Currently set only by the MPEG-2 encoder.
494 primo::codecs::PictureType::Enum pictureType() const {
495 return sample_->pictureType();
496 }
497
498 /// Returns the frame type of a demuxed, decoded or encoded frame. Currently used only by the G.711 a-law and u-law codecs.
499 primo::codecs::FrameType::Enum frameType() const {
500 return sample_->frameType();
501 }
502
503 /**
504 * Calculates the exact number of bytes needed for a video frame with the given properties.
505 * @param width Frame width in pixels.
506 * @param height Frame height in pixels.
507 * @param colorFormat How colors are coded in the frame.
508 * @return The size in bytes, or 0 if it cannot be calculated.
509 */
510 int32_t videoBufferSizeInBytes(int32_t width, int32_t height,
511 primo::codecs::ColorFormat::Enum colorFormat) const {
512 return sample_->videoBufferSizeInBytes(width, height, colorFormat);
513 }
514
515 // -- Fluent setters --
516
517 /**
518 * Sets the presentation timestamp (PTS) of the sample.
519 * @param time Time in seconds.
520 * @return This object, for chaining.
521 */
522 TMediaSample& startTime(double time) { sample_->setStartTime(time); return *this; }
523 /**
524 * Sets the end time of the sample. It is optional and valid only if greater than the start time.
525 * @param time Time in seconds.
526 * @return This object, for chaining.
527 */
528 TMediaSample& endTime(double time) { sample_->setEndTime(time); return *this; }
529 /**
530 * Sets the sample flags.
531 * @param f A combination of @c primo::codecs::MediaSampleFlags::Enum values.
532 * @return This object, for chaining.
533 */
534 TMediaSample& flags(int32_t f) { sample_->setFlags(f); return *this; }
535 /**
536 * Sets the elementary stream to which the sample belongs.
537 * @param n Zero-based index of the elementary stream in the container.
538 * @return This object, for chaining.
539 */
540 TMediaSample& streamNumber(int32_t n) { sample_->setStreamNumber(n); return *this; }
541
542 /**
543 * Sets the required picture type (I/P/B/etc.). Currently ignored by all encoders.
544 * @return This object, for chaining.
545 */
546 TMediaSample& pictureType(primo::codecs::PictureType::Enum pt) {
547 sample_->setPictureType(pt);
548 return *this;
549 }
550
551 /**
552 * Sets the frame type. Currently used only by the G.711 a-law and u-law codecs.
553 * @return This object, for chaining.
554 */
555 TMediaSample& frameType(primo::codecs::FrameType::Enum ft) {
556 sample_->setFrameType(ft);
557 return *this;
558 }
559
560 // -- Operations --
561
562 /// Resets the sample to its default values and clears the data in its buffer. Returns this object, for chaining.
563 TMediaSample& reset() {
564 sample_->reset();
565 return *this;
566 }
567
568 /// Creates a deep copy of the sample.
569 TMediaSample clone() const {
570 return TMediaSample(primo::ref<primo::codecs::MediaSample>(sample_->clone()));
571 }
572
573 /// Returns the raw underlying pointer. For interop with the core API only.
574 primo::codecs::MediaSample* get() const { return sample_.get(); }
575};
576
577// ---- Metadata wrappers -------------------------------------------------------
578
579/**
580 * Fluent wrapper for @c primo::codecs::MetaAttribute.
581 *
582 * Owns the raw object through a @c primo::ref<MetaAttribute>.
583 * Non-copyable, movable. Constructed from a factory-owned object (via
584 * @c primo::ref) or from a non-owned pointer (via raw-pointer ctor, which
585 * retains it).
586 */
587class TMetaAttribute {
588 primo::ref<primo::codecs::MetaAttribute> attr_;
589
590public:
591 /// Creates an empty meta attribute.
592 TMetaAttribute()
593 : attr_(primo::avblocks::Library::createMetaAttribute()) {}
594
595 /**
596 * Takes ownership of an existing @c MetaAttribute reference.
597 */
598 explicit TMetaAttribute(primo::ref<primo::codecs::MetaAttribute> attr)
599 : attr_(std::move(attr)) {}
600
601 /// Wraps a non-owned @c MetaAttribute pointer, retaining it.
602 explicit TMetaAttribute(primo::codecs::MetaAttribute* attr)
603 : attr_(attr) { if (attr) attr->retain(); }
604
605 TMetaAttribute(const TMetaAttribute&) = delete;
606 TMetaAttribute& operator=(const TMetaAttribute&) = delete;
607 /// @{
608 /// Move construction/assignment transfers ownership of the underlying object. The moved-from object no longer wraps anything.
609 TMetaAttribute(TMetaAttribute&&) = default;
610 TMetaAttribute& operator=(TMetaAttribute&&) = default;
611 /// @}
612
613 // -- Getters --
614
615 /// Returns the attribute name as an ANSI string (see @c primo::codecs::Meta constants).
616 const char* name() const { return attr_ ? attr_->name() : nullptr; }
617
618 /// Returns the attribute value as a UTF-8 @c std::string.
619 std::string value() const {
620 return attr_ ? std::string(primo::ustring(attr_->value())) : std::string{};
621 }
622
623 /// Returns @c true if the attribute is immutable.
624 bool immutable() const { return attr_ && attr_->immutable() == TRUE; }
625
626 // -- Fluent setters --
627
628 /// Sets the attribute name (@p name is an ANSI string).
629 TMetaAttribute& name(const char* n) { if (attr_) attr_->setName(n); return *this; }
630
631 /// Sets the attribute value (@p val is a UTF-8 C-string).
632 TMetaAttribute& value(const char* val) {
633 if (attr_) attr_->setValue(primo::ustring(val));
634 return *this;
635 }
636
637 // -- Operations --
638
639 /// Creates a full independent clone. The returned object is always mutable.
640 TMetaAttribute clone() const {
641 return TMetaAttribute(
642 primo::ref<primo::codecs::MetaAttribute>(attr_->clone()));
643 }
644
645 /// Returns @c true when this handle wraps a non-null underlying object.
646 bool valid() const { return attr_.get() != nullptr; }
647
648 /// Returns the raw underlying pointer. For interop with the core API only.
649 primo::codecs::MetaAttribute* get() const { return attr_.get(); }
650};
651
652/**
653 * Non-owning view of a @c MetaAttributeList.
654 *
655 * Returned by @c TMetadata::attributes().
656 */
657class TMetaAttributeList {
658 primo::codecs::MetaAttributeList* list_;
659
660public:
661 /**
662 * Wraps a non-owned @c MetaAttributeList pointer.
663 */
664 explicit TMetaAttributeList(primo::codecs::MetaAttributeList* list) : list_(list) {}
665
666 /**
667 * Proxy returned by the non-const lvalue @c operator[](int32_t).
668 * Supports both read (implicit conversion to @c TMetaAttribute) and
669 * write (@c operator= calls @c setAt on the parent list).
670 */
671 struct ItemRef {
672 /// The list this proxy refers to.
673 TMetaAttributeList& list_;
674 /// Index of the item the proxy refers to.
675 int32_t index_;
676 /// Read — implicit conversion to a non-owning attribute wrapper.
677 operator TMetaAttribute() const { return TMetaAttribute(list_.list_->at(index_)); }
678 /// Write — calls @c setAt; returns @c true on success.
679 bool operator=(TMetaAttribute&& a) { return list_.list_->setAt(index_, a.get()) == TRUE; }
680 };
681
682 /// Returns the number of attributes.
683 int32_t count() const { return list_ ? list_->count() : 0; }
684
685 /// Returns the attribute at @p index (non-owning, retaining).
686 TMetaAttribute at(int32_t index) const { return TMetaAttribute(list_->at(index)); }
687
688 /// Non-const lvalue subscript — returns a proxy supporting read and @c setAt write.
689 ItemRef operator[](int32_t index) & { return {*this, index}; }
690
691 /// Returns the first attribute whose name matches @p name (non-owning, retaining).
692 /// Check @c TMetaAttribute::valid() before use.
693 TMetaAttribute itemByName(const char* name) const {
694 return TMetaAttribute(list_ ? list_->itemByName(name) : nullptr);
695 }
696
697 /// Subscript by name — same as @c itemByName(@p name).
698 TMetaAttribute operator[](const char* name) const & {
699 return TMetaAttribute(list_ ? list_->itemByName(name) : nullptr);
700 }
701
702 /// Replaces the attribute at @p index with @p attr. Returns @c true on success.
703 bool setAt(int32_t index, TMetaAttribute&& attr) {
704 return list_ && list_->setAt(index, attr.get()) == TRUE;
705 }
706
707 /// Inserts @p attr before @p index, shifting later items. Returns @c true on success.
708 bool insert(int32_t index, TMetaAttribute&& attr) {
709 return list_ && list_->insert(index, attr.get()) == TRUE;
710 }
711
712 /// Returns @c true when the list (and its parent @c Metadata) is immutable.
713 bool immutable() const { return list_ && list_->immutable() == TRUE; }
714
715 /// Removes the attribute at @p index. Returns @c true on success.
716 bool remove(int32_t index) { return list_ && list_->remove(index) == TRUE; }
717
718 /// Removes all attributes from the list. Returns @c true on success.
719 bool clear() { return list_ && list_->clear() == TRUE; }
720};
721
722/**
723 * Fluent wrapper for @c primo::codecs::MetaPicture.
724 *
725 * Owns the raw object through a @c primo::ref<MetaPicture>.
726 * Non-copyable, movable.
727 */
728class TMetaPicture {
729 primo::ref<primo::codecs::MetaPicture> pic_;
730
731public:
732 /// Creates an empty meta picture.
733 TMetaPicture()
734 : pic_(primo::avblocks::Library::createMetaPicture()) {}
735
736 /**
737 * Takes ownership of an existing @c MetaPicture reference.
738 */
739 explicit TMetaPicture(primo::ref<primo::codecs::MetaPicture> pic)
740 : pic_(std::move(pic)) {}
741
742 /// Wraps a non-owned @c MetaPicture pointer, retaining it.
743 explicit TMetaPicture(primo::codecs::MetaPicture* pic)
744 : pic_(pic) { if (pic) pic->retain(); }
745
746 TMetaPicture(const TMetaPicture&) = delete;
747 TMetaPicture& operator=(const TMetaPicture&) = delete;
748 /// @{
749 /// Move construction/assignment transfers ownership of the underlying object. The moved-from object no longer wraps anything.
750 TMetaPicture(TMetaPicture&&) = default;
751 TMetaPicture& operator=(TMetaPicture&&) = default;
752 /// @}
753
754 // -- Getters --
755
756 /// Returns the MIME type as an ANSI string (see @c primo::codecs::MimeType constants).
757 const char* mimeType() const { return pic_ ? pic_->mimeType() : nullptr; }
758 /// Returns the picture type (front cover, back cover, artist, etc.).
759 primo::codecs::MetaPictureType::Enum pictureType() const { return pic_ ? pic_->pictureType() : primo::codecs::MetaPictureType::Other; }
760 /// Returns the picture description as a UTF-8 @c std::string (empty if none).
761 std::string description() const {
762 return (pic_ && pic_->description())
763 ? std::string(primo::ustring(pic_->description()))
764 : std::string{};
765 }
766 /**
767 * Returns a pointer to the image data (jpeg, png, etc., as given by @c mimeType()). The size is @c dataSize().
768 */
769 const uint8_t* data() const { return pic_ ? pic_->data() : nullptr; }
770 /// Returns the number of image bytes.
771 int32_t dataSize() const { return pic_ ? pic_->dataSize() : 0; }
772 /**
773 * Returns @c true if the picture is immutable.
774 */
775 bool immutable() const { return pic_ && pic_->immutable() == TRUE; }
776
777 // -- Fluent setters --
778
779 /**
780 * Sets the MIME type (see @c primo::codecs::MimeType constants).
781 * @return This object, for chaining.
782 */
783 TMetaPicture& mimeType(const char* mt) { if (pic_) pic_->setMimeType(mt); return *this; }
784 /**
785 * Sets the picture type (front cover, back cover, artist, etc.).
786 * @return This object, for chaining.
787 */
788 TMetaPicture& pictureType(primo::codecs::MetaPictureType::Enum pt) { if (pic_) pic_->setPictureType(pt); return *this; }
789 /**
790 * Sets the picture description (@p desc is a UTF-8 C-string). Pass @c nullptr to clear it.
791 * @return This object, for chaining.
792 */
793 TMetaPicture& description(const char* desc) {
794 if (pic_) pic_->setDescription(primo::ustring(desc));
795 return *this;
796 }
797 /**
798 * Sets the image data. The data is copied.
799 * @param d Pointer to the image data.
800 * @param size Size of the image in bytes.
801 * @return This object, for chaining.
802 */
803 TMetaPicture& data(const void* d, int32_t size) { if (pic_) pic_->setData(d, size); return *this; }
804
805 // -- Operations --
806
807 /// Creates a full independent clone. The returned object is always mutable.
808 TMetaPicture clone() const {
809 return TMetaPicture(primo::ref<primo::codecs::MetaPicture>(pic_->clone()));
810 }
811
812 /// Returns @c true when this handle wraps a non-null underlying object.
813 bool valid() const { return pic_.get() != nullptr; }
814
815 /// Returns the raw underlying pointer. For interop with the core API only.
816 primo::codecs::MetaPicture* get() const { return pic_.get(); }
817};
818
819/**
820 * Non-owning view of a @c MetaPictureList.
821 *
822 * Returned by @c TMetadata::pictures().
823 */
824class TMetaPictureList {
825 primo::codecs::MetaPictureList* list_;
826
827public:
828 /**
829 * Wraps a non-owned @c MetaPictureList pointer.
830 */
831 explicit TMetaPictureList(primo::codecs::MetaPictureList* list) : list_(list) {}
832
833 /**
834 * Proxy returned by the non-const lvalue @c operator[](int32_t).
835 * Supports both read (implicit conversion to @c TMetaPicture) and
836 * write (@c operator= calls @c setAt on the parent list).
837 */
838 struct ItemRef {
839 /// The list this proxy refers to.
840 TMetaPictureList& list_;
841 /// Index of the item the proxy refers to.
842 int32_t index_;
843 /// Read — implicit conversion to a non-owning picture wrapper.
844 operator TMetaPicture() const { return TMetaPicture(list_.list_->at(index_)); }
845 /// Write — calls @c setAt; returns @c true on success.
846 bool operator=(TMetaPicture&& p) { return list_.list_->setAt(index_, p.get()) == TRUE; }
847 };
848
849 /// Returns the number of pictures.
850 int32_t count() const { return list_ ? list_->count() : 0; }
851
852 /// Returns the picture at @p index (non-owning, retaining).
853 TMetaPicture at(int32_t index) const { return TMetaPicture(list_->at(index)); }
854
855 /// Non-const lvalue subscript — returns a proxy supporting read and @c setAt write.
856 ItemRef operator[](int32_t index) & { return {*this, index}; }
857
858 /// Const subscript — same as @c at(@p index).
859 TMetaPicture operator[](int32_t index) const & { return TMetaPicture(list_->at(index)); }
860
861 /// Replaces the picture at @p index with @p pic. Returns @c true on success.
862 bool setAt(int32_t index, TMetaPicture&& pic) {
863 return list_ && list_->setAt(index, pic.get()) == TRUE;
864 }
865
866 /// Inserts @p pic before @p index, shifting later items. Returns @c true on success.
867 bool insert(int32_t index, TMetaPicture&& pic) {
868 return list_ && list_->insert(index, pic.get()) == TRUE;
869 }
870
871 /// Returns @c true when the list (and its parent @c Metadata) is immutable.
872 bool immutable() const { return list_ && list_->immutable() == TRUE; }
873
874 /// Removes the picture at @p index. Returns @c true on success.
875 bool remove(int32_t index) { return list_ && list_->remove(index) == TRUE; }
876
877 /// Removes all pictures from the list. Returns @c true on success.
878 bool clear() { return list_ && list_->clear() == TRUE; }
879};
880
881/**
882 * Fluent wrapper for @c primo::codecs::Metadata.
883 *
884 * Owns the raw object through a @c primo::ref<Metadata>.
885 * Non-copyable, movable. Obtained from @c TMediaSocketT::metadata() or
886 * created directly via the default constructor.
887 */
888class TMetadata {
889 primo::ref<primo::codecs::Metadata> meta_;
890
891public:
892 /// Creates an empty metadata object.
893 TMetadata()
894 : meta_(primo::avblocks::Library::createMetadata()) {}
895
896 /**
897 * Takes ownership of an existing @c Metadata reference.
898 */
899 explicit TMetadata(primo::ref<primo::codecs::Metadata> meta)
900 : meta_(std::move(meta)) {}
901
902 /// Wraps a non-owned @c Metadata pointer, retaining it.
903 explicit TMetadata(primo::codecs::Metadata* meta)
904 : meta_(meta) { if (meta) meta->retain(); }
905
906 TMetadata(const TMetadata&) = delete;
907 TMetadata& operator=(const TMetadata&) = delete;
908 /// @{
909 /// Move construction/assignment transfers ownership of the underlying object. The moved-from object no longer wraps anything.
910 TMetadata(TMetadata&&) = default;
911 TMetadata& operator=(TMetadata&&) = default;
912 /// @}
913
914 // -- List accessors --
915
916 /// Returns a non-owning view of the attribute list.
917 TMetaAttributeList attributes() const {
918 return TMetaAttributeList(meta_ ? meta_->attributes() : nullptr);
919 }
920
921 /// Returns a non-owning view of the picture list.
922 TMetaPictureList pictures() const {
923 return TMetaPictureList(meta_ ? meta_->pictures() : nullptr);
924 }
925
926 // -- List mutation --
927
928 /// @{
929 /**
930 * Appends an attribute to the attribute list.
931 * @param attr The attribute to add. The list retains it.
932 * @return This object, for chaining.
933 */
934 TMetadata&& addAttribute(TMetaAttribute&& attr) && {
935 meta_->attributes()->add(attr.get());
936 return std::move(*this);
937 }
938
939 TMetadata& addAttribute(TMetaAttribute&& attr) & {
940 meta_->attributes()->add(attr.get());
941 return *this;
942 }
943 /// @}
944
945 /// @{
946 /**
947 * Appends a picture to the picture list.
948 * @param pic The picture to add. The list retains it.
949 * @return This object, for chaining.
950 */
951 TMetadata&& addPicture(TMetaPicture&& pic) && {
952 meta_->pictures()->add(pic.get());
953 return std::move(*this);
954 }
955
956 TMetadata& addPicture(TMetaPicture&& pic) & {
957 meta_->pictures()->add(pic.get());
958 return *this;
959 }
960 /// @}
961
962 // -- Getters --
963
964 /**
965 * Returns @c true if the metadata is immutable.
966 */
967 bool immutable() const { return meta_ && meta_->immutable() == TRUE; }
968
969 // -- Operations --
970
971 /// Creates a full independent clone. The returned object is always mutable.
972 TMetadata clone() const {
973 return TMetadata(primo::ref<primo::codecs::Metadata>(meta_->clone()));
974 }
975
976 /// Returns @c true when this handle wraps a non-null underlying object.
977 bool valid() const { return meta_.get() != nullptr; }
978
979 /// Returns the raw underlying pointer. For interop with the core API only.
980 primo::codecs::Metadata* get() const { return meta_.get(); }
981};
982
983// ---- StreamInfo CRTP base and subclasses -------------------------------------
984
985/**
986 * CRTP base for @c TAudioStreamInfo, @c TVideoStreamInfo, and @c TDataStreamInfo.
987 *
988 * Holds the @c primo::ref<RawT> and exposes all properties defined on the
989 * raw @c primo::codecs::StreamInfo interface, with fluent setters that return
990 * @c Derived& (on lvalues) or @c Derived&& (on temporaries) so chaining works naturally
991 * on the concrete subclass. The rvalue overloads let a chained temporary be returned or
992 * moved, e.g. @c return @c TVideoStreamInfo().frameWidth(352).frameHeight(288);
993 */
994template<typename Derived, typename RawT>
995class TStreamInfo {
996protected:
997 /// The wrapped raw stream info.
998 primo::ref<RawT> info_;
999
1000 /// Takes ownership of an existing raw stream info reference.
1001 explicit TStreamInfo(primo::ref<RawT> info)
1002 : info_(std::move(info)) {}
1003
1004 /// Wraps a non-owned pointer, retaining it. Used by subclass raw-pointer constructors.
1005 explicit TStreamInfo(RawT* info)
1006 : info_(info) { if (info) info->retain(); }
1007
1008 TStreamInfo(const TStreamInfo&) = delete;
1009 TStreamInfo& operator=(const TStreamInfo&) = delete;
1010 /// @{
1011 /// Move construction/assignment transfers ownership of the underlying object. The moved-from object no longer wraps anything.
1012 TStreamInfo(TStreamInfo&&) = default;
1013 TStreamInfo& operator=(TStreamInfo&&) = default;
1014 /// @}
1015
1016private:
1017 Derived& self() { return static_cast<Derived&>(*this); }
1018 const Derived& self() const { return static_cast<const Derived&>(*this); }
1019
1020public:
1021 // -- Fluent setters --
1022
1023 /// @{
1024 /**
1025 * Sets the stream type.
1026 * @param type Major stream type.
1027 * @return This object, for chaining.
1028 */
1029 Derived& streamType(primo::codecs::StreamType::Enum type) & {
1030 info_->setStreamType(type);
1031 return self();
1032 }
1033
1034 Derived&& streamType(primo::codecs::StreamType::Enum type) && {
1035 info_->setStreamType(type);
1036 return std::move(self());
1037 }
1038 /// @}
1039
1040 /// @{
1041 /**
1042 * Sets the stream subtype.
1043 * @param subType Stream subtype.
1044 * @return This object, for chaining.
1045 */
1046 Derived& streamSubType(primo::codecs::StreamSubType::Enum subType) & {
1047 info_->setStreamSubType(subType);
1048 return self();
1049 }
1050
1051 Derived&& streamSubType(primo::codecs::StreamSubType::Enum subType) && {
1052 info_->setStreamSubType(subType);
1053 return std::move(self());
1054 }
1055 /// @}
1056
1057 /// @{
1058 /**
1059 * Sets the stream duration.
1060 * @param d Duration in seconds.
1061 * @return This object, for chaining.
1062 */
1063 Derived& duration(double d) & {
1064 info_->setDuration(d);
1065 return self();
1066 }
1067
1068 Derived&& duration(double d) && {
1069 info_->setDuration(d);
1070 return std::move(self());
1071 }
1072 /// @}
1073
1074 /// @{
1075 /**
1076 * Sets the stream bitrate.
1077 * @param bps Bitrate in bits per second.
1078 * @return This object, for chaining.
1079 */
1080 Derived& bitrate(int32_t bps) & {
1081 info_->setBitrate(bps);
1082 return self();
1083 }
1084
1085 Derived&& bitrate(int32_t bps) && {
1086 info_->setBitrate(bps);
1087 return std::move(self());
1088 }
1089 /// @}
1090
1091 /// @{
1092 /**
1093 * Sets the stream bitrate mode.
1094 * @param mode A @c primo::codecs::BitrateMode::Enum constant.
1095 * @return This object, for chaining.
1096 */
1097 Derived& bitrateMode(int32_t mode) & {
1098 info_->setBitrateMode(mode);
1099 return self();
1100 }
1101
1102 Derived&& bitrateMode(int32_t mode) && {
1103 info_->setBitrateMode(mode);
1104 return std::move(self());
1105 }
1106 /// @}
1107
1108 /// @{
1109 /**
1110 * Sets the ID of the elementary stream.
1111 * @param id Elementary stream ID.
1112 * @return This object, for chaining.
1113 */
1114 Derived& ID(int32_t id) & {
1115 info_->setID(id);
1116 return self();
1117 }
1118
1119 Derived&& ID(int32_t id) && {
1120 info_->setID(id);
1121 return std::move(self());
1122 }
1123 /// @}
1124
1125 /// @{
1126 /**
1127 * Sets the program to which the elementary stream belongs.
1128 * @param num Program number.
1129 * @return This object, for chaining.
1130 */
1131 Derived& programNumber(int32_t num) & {
1132 info_->setProgramNumber(num);
1133 return self();
1134 }
1135
1136 Derived&& programNumber(int32_t num) && {
1137 info_->setProgramNumber(num);
1138 return std::move(self());
1139 }
1140 /// @}
1141
1142 /// @{
1143 /**
1144 * Sets decoder specific configuration data. It is typically obtained from a demuxer and is required to decode certain stream types.
1145 * @param buf Buffer with the configuration data. Can be @c nullptr.
1146 * @return This object, for chaining.
1147 */
1148 Derived& configData(primo::codecs::MediaBuffer* buf) & {
1149 info_->setConfigData(buf);
1150 return self();
1151 }
1152
1153 Derived&& configData(primo::codecs::MediaBuffer* buf) && {
1154 info_->setConfigData(buf);
1155 return std::move(self());
1156 }
1157 /// @}
1158
1159 // -- Getters --
1160
1161 /// Returns the media type of the stream. It cannot be changed.
1162 primo::codecs::MediaType::Enum mediaType() const { return info_->mediaType(); }
1163 /// Returns the stream type.
1164 primo::codecs::StreamType::Enum streamType() const { return info_->streamType(); }
1165 /// Returns the stream subtype.
1166 primo::codecs::StreamSubType::Enum streamSubType() const { return info_->streamSubType(); }
1167 /// Returns the stream duration in seconds.
1168 double duration() const { return info_->duration(); }
1169 /// Returns the stream bitrate in bits per second.
1170 int32_t bitrate() const { return info_->bitrate(); }
1171 /**
1172 * Returns the stream bitrate mode, a @c primo::codecs::BitrateMode::Enum constant.
1173 */
1174 int32_t bitrateMode() const { return info_->bitrateMode(); }
1175 /// Returns the ID of the elementary stream.
1176 int32_t ID() const { return info_->ID(); }
1177 /// Returns the number of the program to which the elementary stream belongs.
1178 int32_t programNumber() const { return info_->programNumber(); }
1179 /**
1180 * Returns @c true if the object is immutable. An immutable object cannot be modified.
1181 */
1182 bool immutable() const { return info_->immutable() == TRUE; }
1183 /**
1184 * Returns the decoder specific configuration data, or @c nullptr if not set.
1185 */
1186 primo::codecs::MediaBuffer* configData() const { return info_->configData(); }
1187
1188 // -- Operations --
1189
1190 /// Resets all fields to their defaults. Returns @c false if the object is immutable.
1191 bool reset() { return info_->reset() == TRUE; }
1192
1193 /// Returns a mutable deep copy. The cloned object is always mutable regardless
1194 /// of whether the source was immutable.
1195 Derived clone() const {
1196 return Derived(primo::ref<RawT>(static_cast<RawT*>(info_->clone())));
1197 }
1198
1199 /// Returns the raw underlying pointer. For interop with the C API only.
1200 RawT* get() const { return info_.get(); }
1201};
1202
1203/**
1204 * Fluent wrapper for @c primo::codecs::AudioStreamInfo, which describes an elementary audio stream.
1205 *
1206 * The properties common to all streams are inherited from @c TStreamInfo. The setters can be chained;
1207 * on a temporary they return the object by rvalue reference so that the chain can be returned or moved:
1208 * @code
1209 * TAudioStreamInfo audio = TAudioStreamInfo().channels(2).sampleRate(44100).bitsPerSample(16);
1210 * @endcode
1211 * Owns the raw object through a @c primo::ref. Not copyable, movable.
1212 */
1213class TAudioStreamInfo
1214 : public TStreamInfo<TAudioStreamInfo, primo::codecs::AudioStreamInfo> {
1215 using Base = TStreamInfo<TAudioStreamInfo, primo::codecs::AudioStreamInfo>;
1216
1217public:
1218 /// Creates an audio stream info with default values.
1219 TAudioStreamInfo()
1220 : Base(primo::ref<primo::codecs::AudioStreamInfo>(
1221 primo::avblocks::Library::createAudioStreamInfo())) {}
1222
1223 /**
1224 * Takes ownership of an existing @c AudioStreamInfo reference.
1225 */
1226 explicit TAudioStreamInfo(primo::ref<primo::codecs::AudioStreamInfo> info)
1227 : Base(std::move(info)) {}
1228
1229 /// Wraps a non-owned @c AudioStreamInfo pointer, retaining it.
1230 explicit TAudioStreamInfo(primo::codecs::AudioStreamInfo* info)
1231 : Base(info) {}
1232
1233 TAudioStreamInfo(const TAudioStreamInfo&) = delete;
1234 TAudioStreamInfo& operator=(const TAudioStreamInfo&) = delete;
1235 /// @{
1236 /// Move construction/assignment transfers ownership of the underlying object. The moved-from object no longer wraps anything.
1237 TAudioStreamInfo(TAudioStreamInfo&&) = default;
1238 TAudioStreamInfo& operator=(TAudioStreamInfo&&) = default;
1239 /// @}
1240
1241 // -- Fluent setters --
1242
1243 /// @{
1244 /**
1245 * Sets the number of audio channels.
1246 * @param channels Number of channels.
1247 * @return This object, for chaining.
1248 */
1249 TAudioStreamInfo& channels(int32_t channels) & {
1250 info_->setChannels(channels);
1251 return *this;
1252 }
1253
1254 TAudioStreamInfo&& channels(int32_t channels) && {
1255 info_->setChannels(channels);
1256 return std::move(*this);
1257 }
1258 /// @}
1259
1260 /// @{
1261 /**
1262 * Sets the audio sample rate.
1263 * @param sampleRate Sample rate in Hz.
1264 * @return This object, for chaining.
1265 */
1266 TAudioStreamInfo& sampleRate(int32_t sampleRate) & {
1267 info_->setSampleRate(sampleRate);
1268 return *this;
1269 }
1270
1271 TAudioStreamInfo&& sampleRate(int32_t sampleRate) && {
1272 info_->setSampleRate(sampleRate);
1273 return std::move(*this);
1274 }
1275 /// @}
1276
1277 /// @{
1278 /**
1279 * Sets the number of bits per sample (sample resolution), usually 8, 16, 24 or 32.
1280 * @param bits Bits per sample.
1281 * @return This object, for chaining.
1282 */
1283 TAudioStreamInfo& bitsPerSample(int32_t bits) & {
1284 info_->setBitsPerSample(bits);
1285 return *this;
1286 }
1287
1288 TAudioStreamInfo&& bitsPerSample(int32_t bits) && {
1289 info_->setBitsPerSample(bits);
1290 return std::move(*this);
1291 }
1292 /// @}
1293
1294 /// @{
1295 /**
1296 * Sets the audio format flags.
1297 * @param flags A combination of @c primo::codecs::PcmFlags::Enum values.
1298 * @return This object, for chaining.
1299 */
1300 TAudioStreamInfo& pcmFlags(int32_t flags) & {
1301 info_->setPcmFlags(flags);
1302 return *this;
1303 }
1304
1305 TAudioStreamInfo&& pcmFlags(int32_t flags) && {
1306 info_->setPcmFlags(flags);
1307 return std::move(*this);
1308 }
1309 /// @}
1310
1311 /// @{
1312 /**
1313 * Sets the channel layout, the mapping between channels and speakers.
1314 * @param layout A combination of @c primo::codecs::AudioChannelFlags::Enum values.
1315 * @return This object, for chaining.
1316 */
1317 TAudioStreamInfo& channelLayout(int32_t layout) & {
1318 info_->setChannelLayout(layout);
1319 return *this;
1320 }
1321
1322 TAudioStreamInfo&& channelLayout(int32_t layout) && {
1323 info_->setChannelLayout(layout);
1324 return std::move(*this);
1325 }
1326 /// @}
1327
1328 /// @{
1329 /**
1330 * Sets the number of bytes occupied by an audio frame, the smallest discrete unit of an audio stream. It is normally valid (greater than 0) for LPCM streams and 0 for compressed streams.
1331 * @param bytes Bytes per frame.
1332 * @return This object, for chaining.
1333 */
1334 TAudioStreamInfo& bytesPerFrame(int32_t bytes) & {
1335 info_->setBytesPerFrame(bytes);
1336 return *this;
1337 }
1338
1339 TAudioStreamInfo&& bytesPerFrame(int32_t bytes) && {
1340 info_->setBytesPerFrame(bytes);
1341 return std::move(*this);
1342 }
1343 /// @}
1344
1345 // -- Getters --
1346
1347 /// Returns the number of audio channels.
1348 int32_t channels() const { return info_->channels(); }
1349 /// Returns the audio sample rate in Hz.
1350 int32_t sampleRate() const { return info_->sampleRate(); }
1351 /// Returns the number of bits per sample. Normally 0 for a compressed audio stream.
1352 int32_t bitsPerSample() const { return info_->bitsPerSample(); }
1353 /**
1354 * Returns the audio format flags, a combination of @c primo::codecs::PcmFlags::Enum values.
1355 */
1356 int32_t pcmFlags() const { return info_->pcmFlags(); }
1357 /**
1358 * Returns the channel layout, a combination of @c primo::codecs::AudioChannelFlags::Enum values.
1359 */
1360 int32_t channelLayout() const { return info_->channelLayout(); }
1361 /// Returns the number of bytes occupied by an audio frame. Normally 0 for a compressed audio stream.
1362 int32_t bytesPerFrame() const { return info_->bytesPerFrame(); }
1363
1364 // -- Operations --
1365
1366 /// Creates a full independent clone. The returned object is always mutable.
1367 TAudioStreamInfo clone() const {
1368 return TAudioStreamInfo(
1369 primo::ref<primo::codecs::AudioStreamInfo>(info_->clone()));
1370 }
1371
1372 /// Copies all fields to @p dst. Returns @c false if @p dst is null.
1373 bool copyTo(TAudioStreamInfo& dst) const {
1374 return info_->copyTo(dst.get()) == TRUE;
1375 }
1376};
1377
1378/**
1379 * Fluent wrapper for @c primo::codecs::VideoStreamInfo, which describes an elementary video stream.
1380 *
1381 * The properties common to all streams are inherited from @c TStreamInfo. The setters can be chained;
1382 * on a temporary they return the object by rvalue reference so that the chain can be returned or moved:
1383 * @code
1384 * TVideoStreamInfo video = TVideoStreamInfo().frameWidth(352).frameHeight(288).frameRate(25.0);
1385 * @endcode
1386 * Owns the raw object through a @c primo::ref. Not copyable, movable.
1387 */
1388class TVideoStreamInfo
1389 : public TStreamInfo<TVideoStreamInfo, primo::codecs::VideoStreamInfo> {
1390 using Base = TStreamInfo<TVideoStreamInfo, primo::codecs::VideoStreamInfo>;
1391
1392public:
1393 /// Creates a video stream info with default values.
1394 TVideoStreamInfo()
1395 : Base(primo::ref<primo::codecs::VideoStreamInfo>(
1396 primo::avblocks::Library::createVideoStreamInfo())) {}
1397
1398 /**
1399 * Takes ownership of an existing @c VideoStreamInfo reference.
1400 */
1401 explicit TVideoStreamInfo(primo::ref<primo::codecs::VideoStreamInfo> info)
1402 : Base(std::move(info)) {}
1403
1404 /// Wraps a non-owned @c VideoStreamInfo pointer, retaining it. Used by @c TMediaPin::videoStreamInfo().
1405 explicit TVideoStreamInfo(primo::codecs::VideoStreamInfo* info)
1406 : Base(info) {}
1407
1408 TVideoStreamInfo(const TVideoStreamInfo&) = delete;
1409 TVideoStreamInfo& operator=(const TVideoStreamInfo&) = delete;
1410 /// @{
1411 /// Move construction/assignment transfers ownership of the underlying object. The moved-from object no longer wraps anything.
1412 TVideoStreamInfo(TVideoStreamInfo&&) = default;
1413 TVideoStreamInfo& operator=(TVideoStreamInfo&&) = default;
1414 /// @}
1415
1416 // -- Fluent setters --
1417
1418 /// @{
1419 /**
1420 * Sets the video color format.
1421 * @param format A @c primo::codecs::ColorFormat::Enum constant.
1422 * @return This object, for chaining.
1423 */
1424 TVideoStreamInfo& colorFormat(primo::codecs::ColorFormat::Enum format) & {
1425 info_->setColorFormat(format);
1426 return *this;
1427 }
1428
1429 TVideoStreamInfo&& colorFormat(primo::codecs::ColorFormat::Enum format) && {
1430 info_->setColorFormat(format);
1431 return std::move(*this);
1432 }
1433 /// @}
1434
1435 /// @{
1436 /**
1437 * Sets the video frame width.
1438 * @param width Width in pixels.
1439 * @return This object, for chaining.
1440 */
1441 TVideoStreamInfo& frameWidth(int32_t width) & {
1442 info_->setFrameWidth(width);
1443 return *this;
1444 }
1445
1446 TVideoStreamInfo&& frameWidth(int32_t width) && {
1447 info_->setFrameWidth(width);
1448 return std::move(*this);
1449 }
1450 /// @}
1451
1452 /// @{
1453 /**
1454 * Sets the video frame height.
1455 * @param height Height in pixels.
1456 * @return This object, for chaining.
1457 */
1458 TVideoStreamInfo& frameHeight(int32_t height) & {
1459 info_->setFrameHeight(height);
1460 return *this;
1461 }
1462
1463 TVideoStreamInfo&& frameHeight(int32_t height) && {
1464 info_->setFrameHeight(height);
1465 return std::move(*this);
1466 }
1467 /// @}
1468
1469 /// @{
1470 /**
1471 * Sets the horizontal dimension of the display aspect ratio. The value has no meaning on its own; together with @c displayRatioHeight() it expresses the ratio.
1472 * @param width Horizontal ratio.
1473 * @return This object, for chaining.
1474 */
1475 TVideoStreamInfo& displayRatioWidth(int32_t width) & {
1476 info_->setDisplayRatioWidth(width);
1477 return *this;
1478 }
1479
1480 TVideoStreamInfo&& displayRatioWidth(int32_t width) && {
1481 info_->setDisplayRatioWidth(width);
1482 return std::move(*this);
1483 }
1484 /// @}
1485
1486 /// @{
1487 /**
1488 * Sets the vertical dimension of the display aspect ratio. The value has no meaning on its own; together with @c displayRatioWidth() it expresses the ratio.
1489 * @param height Vertical ratio.
1490 * @return This object, for chaining.
1491 */
1492 TVideoStreamInfo& displayRatioHeight(int32_t height) & {
1493 info_->setDisplayRatioHeight(height);
1494 return *this;
1495 }
1496
1497 TVideoStreamInfo&& displayRatioHeight(int32_t height) && {
1498 info_->setDisplayRatioHeight(height);
1499 return std::move(*this);
1500 }
1501 /// @}
1502
1503 /// @{
1504 /**
1505 * Sets the video frame rate.
1506 * @param fps Frames per second.
1507 * @return This object, for chaining.
1508 */
1509 TVideoStreamInfo& frameRate(double fps) & {
1510 info_->setFrameRate(fps);
1511 return *this;
1512 }
1513
1514 TVideoStreamInfo&& frameRate(double fps) && {
1515 info_->setFrameRate(fps);
1516 return std::move(*this);
1517 }
1518 /// @}
1519
1520 /// @{
1521 /**
1522 * Sets the scan type of the video frame.
1523 * @param scan A @c primo::codecs::ScanType::Enum constant.
1524 * @return This object, for chaining.
1525 */
1526 TVideoStreamInfo& scanType(primo::codecs::ScanType::Enum scan) & {
1527 info_->setScanType(scan);
1528 return *this;
1529 }
1530
1531 TVideoStreamInfo&& scanType(primo::codecs::ScanType::Enum scan) && {
1532 info_->setScanType(scan);
1533 return std::move(*this);
1534 }
1535 /// @}
1536
1537 /// @{
1538 /**
1539 * Sets the image stride (pitch): the distance in bytes from the start of one row of pixels in memory to the start of the next row.
1540 * @param stride Stride in bytes.
1541 * @return This object, for chaining.
1542 */
1543 TVideoStreamInfo& stride(int32_t stride) & {
1544 info_->setStride(stride);
1545 return *this;
1546 }
1547
1548 TVideoStreamInfo&& stride(int32_t stride) && {
1549 info_->setStride(stride);
1550 return std::move(*this);
1551 }
1552 /// @}
1553
1554 /// @{
1555 /**
1556 * Sets whether the frame is stored upside down in memory, as is typical for bitmaps.
1557 * @param bottomUp @c true if the frame is stored upside down, @c false if the top row is first in memory.
1558 * @return This object, for chaining.
1559 */
1560 TVideoStreamInfo& frameBottomUp(bool bottomUp) & {
1561 info_->setFrameBottomUp(bottomUp ? TRUE : FALSE);
1562 return *this;
1563 }
1564
1565 TVideoStreamInfo&& frameBottomUp(bool bottomUp) && {
1566 info_->setFrameBottomUp(bottomUp ? TRUE : FALSE);
1567 return std::move(*this);
1568 }
1569 /// @}
1570
1571 // -- Getters --
1572
1573 /// Returns the video color format.
1574 primo::codecs::ColorFormat::Enum colorFormat() const { return info_->colorFormat(); }
1575 /// Returns the video frame width in pixels.
1576 int32_t frameWidth() const { return info_->frameWidth(); }
1577 /// Returns the video frame height in pixels.
1578 int32_t frameHeight() const { return info_->frameHeight(); }
1579 /// Returns the horizontal dimension of the display aspect ratio.
1580 int32_t displayRatioWidth() const { return info_->displayRatioWidth(); }
1581 /// Returns the vertical dimension of the display aspect ratio.
1582 int32_t displayRatioHeight() const { return info_->displayRatioHeight(); }
1583 /// Returns the video frame rate in frames per second.
1584 double frameRate() const { return info_->frameRate(); }
1585 /// Returns the scan type of the video frame.
1586 primo::codecs::ScanType::Enum scanType() const { return info_->scanType(); }
1587 /// Returns the image stride (pitch) in bytes.
1588 int32_t stride() const { return info_->stride(); }
1589 /**
1590 * Returns @c true if the frame is stored upside down in memory.
1591 */
1592 bool frameBottomUp() const { return info_->frameBottomUp() == TRUE; }
1593
1594 // -- Operations --
1595
1596 /// Creates a full independent clone. The returned object is always mutable.
1597 TVideoStreamInfo clone() const {
1598 return TVideoStreamInfo(
1599 primo::ref<primo::codecs::VideoStreamInfo>(info_->clone()));
1600 }
1601
1602 /// Copies all fields to @p dst. Returns @c false if @p dst is null.
1603 bool copyTo(TVideoStreamInfo& dst) const {
1604 return info_->copyTo(dst.get()) == TRUE;
1605 }
1606};
1607
1608/**
1609 * Fluent wrapper for a generic data stream.
1610 *
1611 * Wraps @c primo::codecs::StreamInfo as returned by
1612 * @c Library::createDataStreamInfo(). The media type is always
1613 * @c MediaType::Data and cannot be changed. There are no subclass-specific
1614 * properties beyond those exposed by the @c TStreamInfo CRTP base.
1615 */
1616class TDataStreamInfo
1617 : public TStreamInfo<TDataStreamInfo, primo::codecs::StreamInfo> {
1618 using Base = TStreamInfo<TDataStreamInfo, primo::codecs::StreamInfo>;
1619
1620public:
1621 /// Creates a data stream info with default values.
1622 TDataStreamInfo()
1623 : Base(primo::ref<primo::codecs::StreamInfo>(
1624 primo::avblocks::Library::createDataStreamInfo())) {}
1625
1626 /**
1627 * Takes ownership of an existing @c StreamInfo reference.
1628 */
1629 explicit TDataStreamInfo(primo::ref<primo::codecs::StreamInfo> info)
1630 : Base(std::move(info)) {}
1631
1632 /// Wraps a non-owned @c StreamInfo pointer, retaining it. Used by @c TMediaPin::streamInfo().
1633 explicit TDataStreamInfo(primo::codecs::StreamInfo* info)
1634 : Base(info) {}
1635
1636 TDataStreamInfo(const TDataStreamInfo&) = delete;
1637 TDataStreamInfo& operator=(const TDataStreamInfo&) = delete;
1638 /// @{
1639 /// Move construction/assignment transfers ownership of the underlying object. The moved-from object no longer wraps anything.
1640 TDataStreamInfo(TDataStreamInfo&&) = default;
1641 TDataStreamInfo& operator=(TDataStreamInfo&&) = default;
1642 /// @}
1643
1644 // -- Operations --
1645
1646 /// Creates a full independent clone. The returned object is always mutable.
1647 TDataStreamInfo clone() const {
1648 return TDataStreamInfo(
1649 primo::ref<primo::codecs::StreamInfo>(info_->clone()));
1650 }
1651
1652 /// Copies all fields to @p dst. Returns @c false if @p dst is null.
1653 bool copyTo(TDataStreamInfo& dst) const {
1654 return info_->copyTo(dst.get()) == TRUE;
1655 }
1656};
1657
1658/**
1659 * CRTP mixin that adds the typed, fluent @c addParam() to a class that owns a @c primo::avblocks::ParameterList
1660 * (@c TMediaPin and @c TMediaSocketT). @p Derived must provide a private @c paramList() and declare this mixin a friend.
1661 *
1662 * Adds a codec parameter (fluent). @p name is a parameter name constant, e.g. @c Param::Video::Crop::Left or
1663 * @c Param::Encoder::Audio::AAC::StereoMode. The overload is chosen by the type of @p value:
1664 * - integer or enum (e.g. @c InterpolationMethod::Super) -> integer parameter
1665 * - @c float / @c double -> floating point parameter
1666 * - @c std::string / @c std::wstring / string literal -> string parameter
1667 * - @c TMediaBuffer -> media buffer parameter
1668 * - @c TVideoStreamInfo -> video stream info parameter
1669 *
1670 * Each overload has an lvalue version (returns @c Derived&) and an rvalue version (returns @c Derived&&) so it can be
1671 * used in the middle of a chain on a temporary.
1672 */
1673template<typename Derived>
1674class TParamsMixin {
1675 primo::avblocks::ParameterList* params_() { return static_cast<Derived&>(*this).paramList(); }
1676 Derived& self_() { return static_cast<Derived&>(*this); }
1677
1678public:
1679 /// @{
1680 /**
1681 * Adds an integer parameter. Selected for integral and enum values, e.g. @c InterpolationMethod::Super.
1682 * @param name Parameter name constant, e.g. @c Param::Video::Crop::Left.
1683 * @param value Parameter value.
1684 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference.
1685 */
1686 template<typename T> requires (std::integral<T> || std::is_enum_v<T>)
1687 Derived& addParam(const char* name, T value) & {
1688 params_()->addInt(name, static_cast<int64_t>(value));
1689 return self_();
1690 }
1691
1692 template<typename T> requires (std::integral<T> || std::is_enum_v<T>)
1693 Derived&& addParam(const char* name, T value) && {
1694 params_()->addInt(name, static_cast<int64_t>(value));
1695 return std::move(self_());
1696 }
1697 /// @}
1698
1699 /// @{
1700 /**
1701 * Adds a floating point parameter. Selected for @c float and @c double values.
1702 * @param name Parameter name constant, e.g. @c Param::Video::Crop::Left.
1703 * @param value Parameter value.
1704 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference.
1705 */
1706 template<std::floating_point T>
1707 Derived& addParam(const char* name, T value) & {
1708 params_()->addFloat(name, static_cast<double>(value));
1709 return self_();
1710 }
1711
1712 template<std::floating_point T>
1713 Derived&& addParam(const char* name, T value) && {
1714 params_()->addFloat(name, static_cast<double>(value));
1715 return std::move(self_());
1716 }
1717 /// @}
1718
1719 /// @{
1720 /**
1721 * Adds a string parameter. Accepts @c std::string, @c std::wstring and string literals.
1722 * @param name Parameter name constant, e.g. @c Param::Video::Crop::Left.
1723 * @param value Parameter value.
1724 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference.
1725 */
1726 Derived& addParam(const char* name, const std::string& value) & {
1727 params_()->addString(name, primo::ustring(value));
1728 return self_();
1729 }
1730
1731 Derived&& addParam(const char* name, const std::string& value) && {
1732 params_()->addString(name, primo::ustring(value));
1733 return std::move(self_());
1734 }
1735
1736 Derived& addParam(const char* name, const std::wstring& value) & {
1737 params_()->addString(name, primo::ustring(value));
1738 return self_();
1739 }
1740
1741 Derived&& addParam(const char* name, const std::wstring& value) && {
1742 params_()->addString(name, primo::ustring(value));
1743 return std::move(self_());
1744 }
1745 /// @}
1746
1747 /// @{
1748 /**
1749 * Adds a media buffer parameter.
1750 * @param name Parameter name constant, e.g. @c Param::Video::Crop::Left.
1751 * @param value The buffer to store in the parameter.
1752 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference.
1753 */
1754 Derived& addParam(const char* name, const TMediaBuffer& value) & {
1755 params_()->addMediaBuffer(name, value.get());
1756 return self_();
1757 }
1758
1759 Derived&& addParam(const char* name, const TMediaBuffer& value) && {
1760 params_()->addMediaBuffer(name, value.get());
1761 return std::move(self_());
1762 }
1763 /// @}
1764
1765 /// @{
1766 /**
1767 * Adds a video stream info parameter.
1768 * @param name Parameter name constant, e.g. @c Param::Video::Crop::Left.
1769 * @param value The video stream info to store in the parameter.
1770 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference.
1771 */
1772 Derived& addParam(const char* name, const TVideoStreamInfo& value) & {
1773 params_()->addVideoStreamInfo(name, value.get());
1774 return self_();
1775 }
1776
1777 Derived&& addParam(const char* name, const TVideoStreamInfo& value) && {
1778 params_()->addVideoStreamInfo(name, value.get());
1779 return std::move(self_());
1780 }
1781 /// @}
1782};
1783
1784/**
1785 * Fluent wrapper for @c primo::avblocks::MediaPin, which represents an elementary media stream.
1786 *
1787 * A pin can exist for audio, video or any other kind of stream, but AVBlocks processes only audio and video
1788 * streams. Pins are the inputs and outputs of a @c TMediaSocketT. A transcoder matches input and output pins by
1789 * their connection ID (see @c connection()). Codec parameters are added with @c addParam().
1790 *
1791 * Owns the raw object through a @c primo::ref. Not copyable, movable.
1792 */
1793class TMediaPin : public TParamsMixin<TMediaPin> {
1794 friend class TParamsMixin<TMediaPin>;
1795
1796 primo::ref<primo::avblocks::MediaPin> pin_;
1797
1798public:
1799 /// Creates an empty media pin.
1800 TMediaPin()
1801 : pin_(primo::avblocks::Library::createMediaPin()) {}
1802
1803 /**
1804 * Takes ownership of an existing @c MediaPin reference.
1805 */
1806 explicit TMediaPin(primo::ref<primo::avblocks::MediaPin> pin)
1807 : pin_(std::move(pin)) {}
1808
1809 /// Wraps a non-owned @c MediaPin pointer, retaining it. Used by @c TMediaSocketT::pin().
1810 explicit TMediaPin(primo::avblocks::MediaPin* pin)
1811 : pin_(pin) { if (pin) pin->retain(); }
1812
1813 // Delete copy operations
1814 TMediaPin(const TMediaPin&) = delete;
1815 TMediaPin& operator=(const TMediaPin&) = delete;
1816
1817 // Enable move operations
1818 /// @{
1819 /// Move construction/assignment transfers ownership of the underlying object. The moved-from object no longer wraps anything.
1820 TMediaPin(TMediaPin&&) = default;
1821 TMediaPin& operator=(TMediaPin&&) = default;
1822 /// @}
1823
1824 /// @{
1825 /**
1826 * Sets the stream info of the pin. The pin retains the stream info object, so the pin and @p info share it.
1827 * @param info Audio or video stream info.
1828 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference.
1829 */
1830 TMediaPin&& streamInfo(const TAudioStreamInfo& info) && {
1831 pin_->setStreamInfo(info.get());
1832 return std::move(*this);
1833 }
1834
1835 TMediaPin& streamInfo(const TAudioStreamInfo& info) & {
1836 pin_->setStreamInfo(info.get());
1837 return *this;
1838 }
1839
1840 TMediaPin&& streamInfo(const TVideoStreamInfo& info) && {
1841 pin_->setStreamInfo(info.get());
1842 return std::move(*this);
1843 }
1844
1845 TMediaPin& streamInfo(const TVideoStreamInfo& info) & {
1846 pin_->setStreamInfo(info.get());
1847 return *this;
1848 }
1849 /// @}
1850
1851 /// Returns the pin's stream info cast to @c TAudioStreamInfo, wrapping the existing pointer.
1852 TAudioStreamInfo audioStreamInfo() const {
1853 return TAudioStreamInfo(
1854 static_cast<primo::codecs::AudioStreamInfo*>(pin_->streamInfo()));
1855 }
1856
1857 /// Returns the pin's stream info cast to @c TVideoStreamInfo, wrapping the existing pointer.
1858 TVideoStreamInfo videoStreamInfo() const {
1859 return TVideoStreamInfo(
1860 static_cast<primo::codecs::VideoStreamInfo*>(pin_->streamInfo()));
1861 }
1862
1863 /// Returns the pin's stream info as a @c TDataStreamInfo (base @c StreamInfo view),
1864 /// wrapping the existing pointer. Use to access @c mediaType(), @c streamType(),
1865 /// @c ID(), @c programNumber() without knowing the concrete media type.
1866 TDataStreamInfo streamInfo() const {
1867 return TDataStreamInfo(pin_->streamInfo());
1868 }
1869
1870 /// @{
1871 /**
1872 * Sets the connection ID of the pin. A transcoder matches and connects input and output pins by their
1873 * connection ID. Do not confuse it with the stream ID defined for certain stream types.
1874 * @param connectionID @c PinConnection::Disabled to exclude the pin, @c PinConnection::Auto for automatic
1875 * matching, or any positive integer to match with an output pin that has the same ID.
1876 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference.
1877 */
1878 TMediaPin&& connection(int32_t connectionID) && {
1879 pin_->setConnection(connectionID);
1880 return std::move(*this);
1881 }
1882
1883 TMediaPin& connection(int32_t connectionID) & {
1884 pin_->setConnection(connectionID);
1885 return *this;
1886 }
1887 /// @}
1888
1889 /// Returns the pin's current connection ID.
1890 int32_t connection() const {
1891 return pin_->connection();
1892 }
1893
1894 /// Returns the raw underlying pointer. For interop with the core API only.
1895 primo::avblocks::MediaPin* get() const { return pin_.get(); }
1896
1897private:
1898 primo::avblocks::ParameterList* paramList() { return pin_->params(); }
1899};
1900
1901/**
1902 * Non-owning view of a @c MediaPinList. Returned by @c TMediaSocketT::pins().
1903 */
1904class TMediaPinList {
1905 primo::avblocks::MediaPinList* list_;
1906
1907public:
1908 /// Wraps a non-owned @c MediaPinList pointer.
1909 explicit TMediaPinList(primo::avblocks::MediaPinList* list) : list_(list) {}
1910
1911 /**
1912 * Proxy returned by the non-const lvalue @c operator[](int32_t).
1913 * Supports both read (implicit conversion to @c TMediaPin) and
1914 * write (@c operator= calls @c setAt on the parent list).
1915 */
1916 struct ItemRef {
1917 /// The list this proxy refers to.
1918 TMediaPinList& list_;
1919 /// Index of the item the proxy refers to.
1920 int32_t index_;
1921 /// Read — implicit conversion to a non-owning pin wrapper.
1922 operator TMediaPin() const { return TMediaPin(list_.list_->at(index_)); }
1923 /// Write — calls @c setAt; returns @c true on success.
1924 bool operator=(TMediaPin&& p) { return list_.list_->setAt(index_, p.get()) == TRUE; }
1925 };
1926
1927 /// Returns the number of pins in the collection.
1928 int32_t count() const { return list_ ? list_->count() : 0; }
1929
1930 /// Returns the pin at @p index, wrapping the existing (non-owned) pointer.
1931 TMediaPin at(int32_t index) const { return TMediaPin(list_->at(index)); }
1932
1933 /// Non-const lvalue subscript — returns a proxy supporting read and @c setAt write.
1934 ItemRef operator[](int32_t index) & { return {*this, index}; }
1935
1936 /// Const subscript — same as @c at(@p index).
1937 TMediaPin operator[](int32_t index) const & { return TMediaPin(list_->at(index)); }
1938
1939 /// Replaces the pin at @p index with @p pin. Returns @c true on success.
1940 bool setAt(int32_t index, TMediaPin&& pin) {
1941 return list_ && list_->setAt(index, pin.get()) == TRUE;
1942 }
1943
1944 /// Inserts @p pin before @p index, shifting later items. Returns @c true on success.
1945 bool insert(int32_t index, TMediaPin&& pin) {
1946 return list_ && list_->insert(index, pin.get()) == TRUE;
1947 }
1948
1949 /// Returns @c true when the list (and its parent @c MediaSocket) is immutable.
1950 bool immutable() const { return list_ && list_->immutable() == TRUE; }
1951
1952 /// Removes the pin at @p index. Returns @c true on success.
1953 bool remove(int32_t index) { return list_ && list_->remove(index) == TRUE; }
1954
1955 /// Removes all pins from the list. Returns @c true on success.
1956 bool clear() { return list_ && list_->clear() == TRUE; }
1957};
1958
1959// String traits for handling both char and wchar_t
1960/**
1961 * Maps the character type of the fluent API (@c char or @c wchar_t) to the matching string type and converts
1962 * to and from @c primo::ustring. Used by @c TMediaSocketT, @c TMediaInfoT and @c TTranscoderT.
1963 */
1964template<typename CharT>
1965struct string_traits;
1966
1967/**
1968 * Narrow strings: @c std::string holding UTF-8.
1969 */
1970template<>
1971struct string_traits<char> {
1972 /**
1973 * The string type: @c std::string.
1974 */
1975 using string_type = std::string;
1976 /**
1977 * Converts a string to a @c primo::ustring.
1978 */
1979 static primo::ustring to_ustring(const string_type& s) {
1980 return primo::ustring(s);
1981 }
1982 /**
1983 * Converts a @c primo::ustring to a string.
1984 */
1985 static string_type from_ustring(const primo::ustring& u) {
1986 return u.str();
1987 }
1988};
1989
1990/**
1991 * Wide strings: @c std::wstring.
1992 */
1993template<>
1994struct string_traits<wchar_t> {
1995 /**
1996 * The string type: @c std::wstring.
1997 */
1998 using string_type = std::wstring;
1999 /**
2000 * Converts a string to a @c primo::ustring.
2001 */
2002 static primo::ustring to_ustring(const string_type& s) {
2003 return primo::ustring(s);
2004 }
2005 /**
2006 * Converts a @c primo::ustring to a string.
2007 */
2008 static string_type from_ustring(const primo::ustring& u) {
2009 return u.wstr();
2010 }
2011};
2012
2013/**
2014 * Fluent wrapper for @c primo::avblocks::MediaSocket, an input or output point of a transcoder.
2015 *
2016 * A socket describes either a container (WAV, AVI, MP4, etc.) with one or more streams, or a single elementary
2017 * stream (MP3, M2V, etc.). Its pins (see @c pins()) describe the contained streams. Socket parameters, such as
2018 * muxer options, are added with @c addParam(). The setters can be chained and return the object by rvalue
2019 * reference on a temporary, so a whole socket can be built in one expression:
2020 * @code
2021 * TMediaSocket("out.mp4").addPin(TMediaPin().streamInfo(video));
2022 * @endcode
2023 * @tparam CharT @c char for UTF-8 @c std::string paths, @c wchar_t for @c std::wstring paths.
2024 * Use the aliases @c TMediaSocket and @c TMediaSocketW. Owns the raw object through a @c primo::ref.
2025 * Not copyable, movable.
2026 */
2027template<typename CharT = char>
2028class TMediaSocketT : public TParamsMixin<TMediaSocketT<CharT>> {
2029 friend class TParamsMixin<TMediaSocketT<CharT>>;
2030 primo::ref<primo::avblocks::MediaSocket> socket_;
2031
2032public:
2033 /**
2034 * The string type for paths: @c std::string for @c char, @c std::wstring for @c wchar_t.
2035 */
2036 using string_type = typename string_traits<CharT>::string_type;
2037
2038 /// Creates an empty media socket.
2039 TMediaSocketT()
2040 : socket_(primo::avblocks::Library::createMediaSocket()) {}
2041
2042 /**
2043 * Takes ownership of an existing @c MediaSocket reference.
2044 */
2045 explicit TMediaSocketT(primo::ref<primo::avblocks::MediaSocket> socket)
2046 : socket_(std::move(socket)) {}
2047
2048 /// Wraps a non-owned @c MediaSocket pointer, retaining it. Used by @c TMediaInfo::inputs() / @c outputs().
2049 explicit TMediaSocketT(primo::avblocks::MediaSocket* socket)
2050 : socket_(socket) { if (socket) socket->retain(); }
2051
2052 /// Creates a socket from a @c TMediaInfo, wrapping @c Library::createMediaSocket(MediaInfo*).
2053 /// The created socket contains the file path and pins from the media info, ready to be
2054 /// added as a transcoder input. Member template so the body is instantiation-checked,
2055 /// allowing @c TMediaInfo to be defined after @c TMediaSocketT without a circular dependency.
2056 template<typename TMediaInfoArg>
2057 explicit TMediaSocketT(const TMediaInfoArg& info)
2058 : socket_(primo::avblocks::Library::createMediaSocket(info.get())) {
2059 }
2060
2061 /// Creates a socket pre-configured with the named AVBlocks preset
2062 /// (e.g. @c Preset::Video::Generic::MP4::Base_H264_AAC).
2063 explicit TMediaSocketT(const char* preset)
2064 : socket_(primo::avblocks::Library::createMediaSocket(preset)) {}
2065
2066 // Delete copy operations
2067 TMediaSocketT(const TMediaSocketT&) = delete;
2068 TMediaSocketT& operator=(const TMediaSocketT&) = delete;
2069
2070 // Enable move operations
2071 /// @{
2072 /// Move construction/assignment transfers ownership of the underlying object. The moved-from object no longer wraps anything.
2073 TMediaSocketT(TMediaSocketT&&) = default;
2074 TMediaSocketT& operator=(TMediaSocketT&&) = default;
2075 /// @}
2076
2077 /// @{
2078 /**
2079 * Sets the file associated with the socket.
2080 * @param path File name.
2081 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2082 */
2083 TMediaSocketT&& file(const string_type& path) && {
2084 socket_->setFile(string_traits<CharT>::to_ustring(path));
2085 return std::move(*this);
2086 }
2087
2088 TMediaSocketT& file(const string_type& path) & {
2089 socket_->setFile(string_traits<CharT>::to_ustring(path));
2090 return *this;
2091 }
2092 /// @}
2093
2094 /// @{
2095 /**
2096 * Clears the file associated with the socket.
2097 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2098 */
2099 TMediaSocketT&& file(std::nullptr_t) && {
2100 socket_->setFile(nullptr);
2101 return std::move(*this);
2102 }
2103
2104 TMediaSocketT& file(std::nullptr_t) & {
2105 socket_->setFile(nullptr);
2106 return *this;
2107 }
2108 /// @}
2109
2110 /// Returns the file path as a @c string_type (UTF-8 @c std::string for @c char, @c std::wstring for @c wchar_t), or empty string if not set.
2111 string_type file() const {
2112 const char_t* f = socket_ ? socket_->file() : nullptr;
2113 return f ? string_traits<CharT>::from_ustring(primo::ustring(f)) : string_type{};
2114 }
2115
2116 /// @{
2117 /**
2118 * Sets explicitly the format of the associated file or stream, e.g. AVI, WAV or MP4. If the socket has a file and
2119 * no type, the type is deduced from the file name extension.
2120 * @param type Stream type.
2121 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2122 */
2123 TMediaSocketT&& streamType(primo::codecs::StreamType::Enum type) && {
2124 socket_->setStreamType(type);
2125 return std::move(*this);
2126 }
2127
2128 TMediaSocketT& streamType(primo::codecs::StreamType::Enum type) & {
2129 socket_->setStreamType(type);
2130 return *this;
2131 }
2132 /// @}
2133
2134 /// @{
2135 /**
2136 * Sets the user stream, an alternative to a file, that is the source or sink of the socket. The socket retains
2137 * the stream. When both a file and a stream are set, the transcoder uses the stream.
2138 * @param s The stream. Pass @c nullptr to clear a previously set stream.
2139 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2140 */
2141 TMediaSocketT&& stream(primo::Stream* s) && {
2142 socket_->setStream(s);
2143 return std::move(*this);
2144 }
2145
2146 TMediaSocketT& stream(primo::Stream* s) & {
2147 socket_->setStream(s);
2148 return *this;
2149 }
2150 /// @}
2151
2152 /// @{
2153 /**
2154 * Sets explicitly the stream subtype of the associated file or stream.
2155 * @param subType Stream subtype.
2156 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2157 */
2158 TMediaSocketT&& streamSubType(primo::codecs::StreamSubType::Enum subType) && {
2159 socket_->setStreamSubType(subType);
2160 return std::move(*this);
2161 }
2162
2163 TMediaSocketT& streamSubType(primo::codecs::StreamSubType::Enum subType) & {
2164 socket_->setStreamSubType(subType);
2165 return *this;
2166 }
2167 /// @}
2168
2169 /// @{
2170 /**
2171 * Adds a pin (elementary stream) to the socket. The pin list retains the pin.
2172 * @param pin The pin to add.
2173 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2174 */
2175 TMediaSocketT&& addPin(TMediaPin&& pin) && {
2176 socket_->pins()->add(pin.get());
2177 return std::move(*this);
2178 }
2179
2180 TMediaSocketT& addPin(TMediaPin&& pin) & {
2181 socket_->pins()->add(pin.get());
2182 return *this;
2183 }
2184 /// @}
2185
2186 /// @{
2187 /**
2188 * Sets the time position of the socket. On an input socket the transcoder seeks to this position before the
2189 * transcoding starts. It cannot be changed while the transcoder is open. Has no effect if the socket is immutable.
2190 * @param time Time position in seconds.
2191 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2192 */
2193 TMediaSocketT&& timePosition(double time) && {
2194 socket_->setTimePosition(time);
2195 return std::move(*this);
2196 }
2197
2198 TMediaSocketT& timePosition(double time) & {
2199 socket_->setTimePosition(time);
2200 return *this;
2201 }
2202 /// @}
2203
2204 /// @{
2205 /// Gives you a reference to the pin at @p index, so you can do something with it (read it or change it)
2206 /// without leaving a fluent chain.
2207 ///
2208 /// @p fn is called once, immediately, with a @c TMediaPin& that refers to the pin inside this socket (it is not a
2209 /// copy), so changes made through it apply to the socket. The socket itself is returned, so chaining continues.
2210 ///
2211 /// Use this instead of @c pins(index): that returns the pin and ends the chain, so the socket is no longer
2212 /// available to pass on, e.g. to @c TTranscoder::addOutput().
2213 /// @code
2214 /// TTranscoder()
2215 /// .addInput(TMediaSocket(mediaInfo))
2216 /// .addOutput(
2217 /// TMediaSocket(mediaInfo)
2218 /// .file("out.mp4")
2219 /// .pinRef(0, [](TMediaPin& pin) {
2220 /// pin.videoStreamInfo().frameRate(30.0);
2221 /// }))
2222 /// .open().run().close();
2223 /// @endcode
2224 /// @param index Zero-based index of the pin.
2225 /// @param fn Callable taking @c TMediaPin&.
2226 template<typename Fn>
2227 TMediaSocketT&& pinRef(int32_t index, Fn&& fn) && {
2228 TMediaPin pin = pins(index);
2229 std::forward<Fn>(fn)(pin);
2230 return std::move(*this);
2231 }
2232
2233 template<typename Fn>
2234 TMediaSocketT& pinRef(int32_t index, Fn&& fn) & {
2235 TMediaPin pin = pins(index);
2236 std::forward<Fn>(fn)(pin);
2237 return *this;
2238 }
2239 /// @}
2240
2241 /// @{
2242 /// Gives you a reference to the video stream info of the pin at @p index, so you can do something with it
2243 /// (read it or change it) without leaving a fluent chain. Shorter than @c pinRef() when only the stream info
2244 /// is needed.
2245 ///
2246 /// @p fn is called once, immediately, with a @c TVideoStreamInfo& that refers to the stream info inside the pin
2247 /// (it is not a copy), so changes made through it apply to the socket. The socket is returned, so chaining
2248 /// continues. The pin must be a video pin.
2249 /// @code
2250 /// TMediaSocket(mediaInfo).file("out.mp4")
2251 /// .videoInfoRef(0, [](TVideoStreamInfo& video) { video.frameRate(30.0); })
2252 /// @endcode
2253 template<typename Fn>
2254 TMediaSocketT&& videoInfoRef(int32_t index, Fn&& fn) && {
2255 TVideoStreamInfo info = pins(index).videoStreamInfo();
2256 std::forward<Fn>(fn)(info);
2257 return std::move(*this);
2258 }
2259
2260 template<typename Fn>
2261 TMediaSocketT& videoInfoRef(int32_t index, Fn&& fn) & {
2262 TVideoStreamInfo info = pins(index).videoStreamInfo();
2263 std::forward<Fn>(fn)(info);
2264 return *this;
2265 }
2266 /// @}
2267
2268 /// @{
2269 /// Gives you a reference to the audio stream info of the pin at @p index, so you can do something with it
2270 /// (read it or change it) without leaving a fluent chain. Same as @c videoInfoRef() for an audio pin.
2271 /// @code
2272 /// TMediaSocket(mediaInfo).file("out.mp3")
2273 /// .audioInfoRef(0, [](TAudioStreamInfo& audio) { audio.sampleRate(48000); })
2274 /// @endcode
2275 template<typename Fn>
2276 TMediaSocketT&& audioInfoRef(int32_t index, Fn&& fn) && {
2277 TAudioStreamInfo info = pins(index).audioStreamInfo();
2278 std::forward<Fn>(fn)(info);
2279 return std::move(*this);
2280 }
2281
2282 template<typename Fn>
2283 TMediaSocketT& audioInfoRef(int32_t index, Fn&& fn) & {
2284 TAudioStreamInfo info = pins(index).audioStreamInfo();
2285 std::forward<Fn>(fn)(info);
2286 return *this;
2287 }
2288 /// @}
2289
2290
2291 /// Returns the stream type of this socket (read from the underlying @c MediaSocket).
2292 primo::codecs::StreamType::Enum streamType() const {
2293 return socket_->streamType();
2294 }
2295
2296 /// Returns the stream sub-type of this socket (read from the underlying @c MediaSocket).
2297 primo::codecs::StreamSubType::Enum streamSubType() const {
2298 return socket_->streamSubType();
2299 }
2300
2301 /// Returns a non-owning view of the pin list.
2302 TMediaPinList pins() const { return TMediaPinList(socket_->pins()); }
2303
2304 /// Returns the pin at @p index, wrapping the existing (non-owned) pointer.
2305 TMediaPin pins(int32_t index) const {
2306 return TMediaPin(socket_->pins()->at(index));
2307 }
2308
2309 /// Returns the metadata associated with this socket as a @c TMetadata wrapper.
2310 /// The returned object is invalid (@c valid() == false) if the socket has no metadata.
2311 TMetadata metadata() const { return TMetadata(socket_->metadata()); }
2312
2313 /// Creates an independent deep copy of this socket (file, stream types and pins). Typical use is to start the
2314 /// output from the input: @c input.clone().file("out.mp4").
2315 TMediaSocketT clone() const {
2316 return TMediaSocketT(primo::ref<primo::avblocks::MediaSocket>(socket_->clone()));
2317 }
2318
2319 /// Returns the raw underlying pointer. For interop with the core API only.
2320 primo::avblocks::MediaSocket* get() const { return socket_.get(); }
2321
2322private:
2323 primo::avblocks::ParameterList* paramList() { return socket_->params(); }
2324};
2325
2326// Type aliases for convenience
2327using TMediaSocket = TMediaSocketT<char>;
2328using TMediaSocketW = TMediaSocketT<wchar_t>;
2329
2330/**
2331 * Non-owning view of a @c MediaSocketList. Returned by @c TMediaInfo::inputs() / @c outputs().
2332 */
2333class TMediaSocketList {
2334 primo::avblocks::MediaSocketList* list_;
2335
2336public:
2337 /// Wraps a non-owned @c MediaSocketList pointer.
2338 explicit TMediaSocketList(primo::avblocks::MediaSocketList* list) : list_(list) {}
2339
2340 /**
2341 * Proxy returned by the non-const lvalue @c operator[](int32_t).
2342 * Supports both read (implicit conversion to @c TMediaSocket) and
2343 * write (@c operator= calls @c setAt on the parent list).
2344 */
2345 struct ItemRef {
2346 /// The list this proxy refers to.
2347 TMediaSocketList& list_;
2348 /// Index of the item the proxy refers to.
2349 int32_t index_;
2350 /// Read — implicit conversion to a non-owning socket wrapper.
2351 operator TMediaSocket() const { return TMediaSocket(list_.list_->at(index_)); }
2352 /// Write — calls @c setAt; returns @c true on success.
2353 bool operator=(TMediaSocket&& s) { return list_.list_->setAt(index_, s.get()) == TRUE; }
2354 };
2355
2356 /// Returns the number of sockets in the collection.
2357 int32_t count() const { return list_ ? list_->count() : 0; }
2358
2359 /// Returns the socket at @p index, wrapping the existing (non-owned) pointer.
2360 TMediaSocket at(int32_t index) const { return TMediaSocket(list_->at(index)); }
2361
2362 /// Non-const lvalue subscript — returns a proxy supporting read and @c setAt write.
2363 ItemRef operator[](int32_t index) & { return {*this, index}; }
2364
2365 /// Const subscript — same as @c at(@p index).
2366 TMediaSocket operator[](int32_t index) const & { return TMediaSocket(list_->at(index)); }
2367
2368 /// Replaces the socket at @p index with @p socket. Returns @c true on success.
2369 bool setAt(int32_t index, TMediaSocket&& socket) {
2370 return list_ && list_->setAt(index, socket.get()) == TRUE;
2371 }
2372
2373 /// Inserts @p socket before @p index, shifting later items. Returns @c true on success.
2374 bool insert(int32_t index, TMediaSocket&& socket) {
2375 return list_ && list_->insert(index, socket.get()) == TRUE;
2376 }
2377
2378 /// Returns @c true when the list (and its parent @c Transcoder) is immutable.
2379 bool immutable() const { return list_ && list_->immutable() == TRUE; }
2380
2381 /// Removes the socket at @p index. Returns @c true on success.
2382 bool remove(int32_t index) { return list_ && list_->remove(index) == TRUE; }
2383
2384 /// Removes all sockets from the list. Returns @c true on success.
2385 bool clear() { return list_ && list_->clear() == TRUE; }
2386};
2387
2388/**
2389 * Fluent wrapper for @c primo::avblocks::MediaInfo, which analyzes a file or a stream and reports its type and
2390 * properties.
2391 *
2392 * Configure the input socket (see @c file() and @c inputs()), call @c open(), then read the detected streams from
2393 * @c outputs() and the metadata from the sockets. In push mode, feed data with @c push() until @c isReady().
2394 * @code
2395 * auto info = TMediaInfo().file("in.mp4").open();
2396 * int32_t pins = info.outputs(0).pins().count();
2397 * @endcode
2398 * @tparam CharT @c char for UTF-8 @c std::string paths, @c wchar_t for @c std::wstring paths.
2399 * Use the aliases @c TMediaInfo and @c TMediaInfoW. Owns the raw object through a @c primo::ref.
2400 * Not copyable, movable.
2401 */
2402template<typename CharT = char>
2403class TMediaInfoT {
2404 primo::ref<primo::avblocks::MediaInfo> info_;
2405
2406public:
2407 /// Creates a media info object with one default input socket.
2408 TMediaInfoT()
2409 : info_(primo::avblocks::Library::createMediaInfo()) {}
2410
2411 // Delete copy operations
2412 TMediaInfoT(const TMediaInfoT&) = delete;
2413 TMediaInfoT& operator=(const TMediaInfoT&) = delete;
2414
2415 // Enable move operations
2416 /// @{
2417 /// Move construction/assignment transfers ownership of the underlying object. The moved-from object no longer wraps anything.
2418 TMediaInfoT(TMediaInfoT&&) = default;
2419 TMediaInfoT& operator=(TMediaInfoT&&) = default;
2420 /// @}
2421
2422 /**
2423 * The string type for paths: @c std::string for @c char, @c std::wstring for @c wchar_t.
2424 */
2425 using string_type = typename string_traits<CharT>::string_type;
2426
2427 /// @{
2428 /**
2429 * Sets the file of the first input socket, so a probe can be written as @c TMediaInfo().file("in.mp4").open().
2430 * @param path File name.
2431 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2432 */
2433 TMediaInfoT&& file(const string_type& path) && {
2434 inputs(0).file(path);
2435 return std::move(*this);
2436 }
2437
2438 TMediaInfoT& file(const string_type& path) & {
2439 inputs(0).file(path);
2440 return *this;
2441 }
2442 /// @}
2443
2444 /// @{
2445 /**
2446 * Analyzes the input. If it succeeds, the detected streams and metadata can be read from the object.
2447 * On a temporary, @c auto @c info @c = @c TMediaInfo().file(f).open(); moves the opened object into @c info.
2448 * @throws TAVBlocksException if the input cannot be analyzed.
2449 * @return This object, for chaining.
2450 */
2451 TMediaInfoT& open() & {
2452 if (!info_->open()) {
2453 throw TAVBlocksException("Failed to open MediaInfo", TErrorInfo(info_->error()));
2454 }
2455 return *this;
2456 }
2457
2458 TMediaInfoT&& open() && {
2459 open();
2460 return std::move(*this);
2461 }
2462 /// @}
2463
2464 /// Opens the MediaInfo. Returns @c true on success, @c false on failure.
2465 bool tryOpen() {
2466 return info_->open() == TRUE;
2467 }
2468
2469 /// Returns @c true when stream info and metadata have been fully parsed in push mode.
2470 bool isReady() { return info_->isReady() == TRUE; }
2471
2472 /// Pushes a chunk of input data for the socket at @p inputIndex.
2473 /// Returns @c true on success.
2474 bool push(int32_t inputIndex, TMediaSample& sample) {
2475 return info_->push(inputIndex, sample.get()) == TRUE;
2476 }
2477
2478 /// Signals end-of-stream on the input socket at @p inputIndex.
2479 /// Equivalent to pushing a null (empty) sample.
2480 bool pushEos(int32_t inputIndex) {
2481 return info_->push(inputIndex, nullptr) == TRUE;
2482 }
2483
2484 /// Returns the error information for the last operation.
2485 TErrorInfo error() const {
2486 return TErrorInfo(info_->error());
2487 }
2488
2489 /// Returns a non-owning view of the input socket list.
2490 TMediaSocketList inputs() const { return TMediaSocketList(info_->inputs()); }
2491
2492 /// Returns the input socket at @p index, wrapping the existing (non-owned) pointer.
2493 TMediaSocketT<CharT> inputs(int32_t index) const {
2494 return TMediaSocketT<CharT>(info_->inputs()->at(index));
2495 }
2496
2497 /// Returns a non-owning view of the output socket list.
2498 TMediaSocketList outputs() const { return TMediaSocketList(info_->outputs()); }
2499
2500 /// Returns the output socket at @p index, wrapping the existing (non-owned) pointer.
2501 TMediaSocketT<CharT> outputs(int32_t index) const {
2502 return TMediaSocketT<CharT>(info_->outputs()->at(index));
2503 }
2504
2505 /// Returns the raw underlying pointer. For interop with the core API only.
2506 primo::avblocks::MediaInfo* get() const { return info_.get(); }
2507};
2508
2509// Type aliases for convenience
2510using TMediaInfo = TMediaInfoT<char>;
2511using TMediaInfoW = TMediaInfoT<wchar_t>;
2512
2513/**
2514 * Internal adapter that bridges @c std::function callbacks to the raw
2515 * @c primo::avblocks::TranscoderCallback interface.
2516 *
2517 * Owned by @c TTranscoderT via @c std::unique_ptr so its address stays
2518 * stable across moves. Only allocated when at least one lambda is set.
2519 */
2520class TTranscoderCallback : public primo::avblocks::TranscoderCallback {
2521 std::function<void(double, double)> onProgress_;
2522 std::function<void(primo::avblocks::TranscoderStatus::Enum)> onStatus_;
2523 std::function<bool(double)> onContinue_;
2524 std::function<void(int32_t)> onInputChange_;
2525public:
2526 /// Sets the function called periodically to report progress, with the current and total time in seconds.
2527 void setOnProgress(std::function<void(double, double)> f) { onProgress_ = std::move(f); }
2528 /// Sets the function called to report the status of the current operation.
2529 void setOnStatus(std::function<void(primo::avblocks::TranscoderStatus::Enum)> f) { onStatus_ = std::move(f); }
2530 /**
2531 * Sets the function called to let the user code stop a running transcoder. It returns @c true to continue.
2532 */
2533 void setOnContinue(std::function<bool(double)> f) { onContinue_ = std::move(f); }
2534 /// Sets the function called when an input format is detected or changes, with the index of the input socket.
2535 void setOnInputChange(std::function<void(int32_t)> f) { onInputChange_ = std::move(f); }
2536
2537 /// Calls the progress function, if set.
2538 void onProgress(double cur, double total) override {
2539 if (onProgress_) onProgress_(cur, total);
2540 }
2541 /// Calls the status function, if set.
2542 void onStatus(primo::avblocks::TranscoderStatus::Enum s) override {
2543 if (onStatus_) onStatus_(s);
2544 }
2545 /**
2546 * Calls the continue function, if set. Returns @c TRUE when no function is set, so the transcoder keeps running.
2547 */
2548 bool_t onContinue(double cur) override {
2549 return onContinue_ ? (onContinue_(cur) ? TRUE : FALSE) : TRUE;
2550 }
2551 /// Calls the input change function, if set.
2552 void onInputChange(int32_t idx) override {
2553 if (onInputChange_) onInputChange_(idx);
2554 }
2555};
2556
2557/**
2558 * Fluent wrapper for @c primo::avblocks::Transcoder, which encodes, decodes and transforms audio and video.
2559 *
2560 * Add input and output sockets, then either run the whole job with @c transcode() (file to file), or drive it
2561 * step by step: @c open(), @c run() or @c push() / @c pull() / @c flush(), then @c close(). Failures are reported with
2562 * @c TAVBlocksException; the @c try* variants return @c false instead. Progress and status are received through
2563 * lambdas (see @c onProgress()).
2564 * @code
2565 * TTranscoder()
2566 * .allowDemoMode(true)
2567 * .addInput(TMediaSocket(mediaInfo))
2568 * .addOutput(TMediaSocket("out.mp4"))
2569 * .transcode();
2570 * @endcode
2571 * @tparam CharT @c char or @c wchar_t, matching the sockets used. Use the aliases @c TTranscoder and @c TTranscoderW.
2572 * Owns the raw object through a @c primo::ref. Not copyable, movable.
2573 */
2574template<typename CharT = char>
2575class TTranscoderT {
2576 // callback_ must be declared BEFORE transcoder_ so that it is destroyed
2577 // AFTER the raw Transcoder (which holds a raw pointer to the callback).
2578 std::unique_ptr<TTranscoderCallback> callback_;
2579 primo::ref<primo::avblocks::Transcoder> transcoder_;
2580
2581public:
2582 /// Creates a transcoder with no inputs and outputs.
2583 TTranscoderT()
2584 : transcoder_(primo::avblocks::Library::createTranscoder()) {}
2585
2586 // Delete copy operations
2587 TTranscoderT(const TTranscoderT&) = delete;
2588 TTranscoderT& operator=(const TTranscoderT&) = delete;
2589
2590 // Enable move operations
2591 /// @{
2592 /// Move construction/assignment transfers ownership of the underlying object. The moved-from object no longer wraps anything.
2593 TTranscoderT(TTranscoderT&&) = default;
2594 TTranscoderT& operator=(TTranscoderT&&) = default;
2595 /// @}
2596
2597 /// Returns the callback adapter, creating it and installing it in the transcoder on first use.
2598 TTranscoderCallback& ensureCallback() {
2599 if (!callback_) {
2600 callback_ = std::make_unique<TTranscoderCallback>();
2601 transcoder_->setCallback(callback_.get());
2602 }
2603 return *callback_;
2604 }
2605
2606 /// @{
2607 /**
2608 * Sets whether demo mode (unlicensed transcoding) is allowed. When allowed, a demo overlay is applied if a
2609 * required codec is not licensed; otherwise the transcoder fails with @c AVBlocksError::UnlicensedFeature.
2610 * Demo mode is on by default in the Demo release and off in the OEM release.
2611 * @param allow @c true to allow demo mode.
2612 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2613 */
2614 TTranscoderT& allowDemoMode(bool allow = true) & {
2615 transcoder_->setAllowDemoMode(allow ? TRUE : FALSE);
2616 return *this;
2617 }
2618
2619 TTranscoderT&& allowDemoMode(bool allow = true) && {
2620 transcoder_->setAllowDemoMode(allow ? TRUE : FALSE);
2621 return std::move(*this);
2622 }
2623 /// @}
2624
2625 /// @{
2626 /**
2627 * Sets a function called periodically during @c run() to report progress.
2628 * @param f Function taking the current and total time in seconds.
2629 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2630 */
2631 TTranscoderT& onProgress(std::function<void(double, double)> f) & {
2632 ensureCallback().setOnProgress(std::move(f));
2633 return *this;
2634 }
2635
2636 TTranscoderT&& onProgress(std::function<void(double, double)> f) && {
2637 ensureCallback().setOnProgress(std::move(f));
2638 return std::move(*this);
2639 }
2640 /// @}
2641
2642 /// @{
2643 /**
2644 * Sets a function called during @c run() to report the status of the current operation.
2645 * @param f Function taking the @c TranscoderStatus.
2646 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2647 */
2648 TTranscoderT& onStatus(std::function<void(primo::avblocks::TranscoderStatus::Enum)> f) & {
2649 ensureCallback().setOnStatus(std::move(f));
2650 return *this;
2651 }
2652
2653 TTranscoderT&& onStatus(std::function<void(primo::avblocks::TranscoderStatus::Enum)> f) && {
2654 ensureCallback().setOnStatus(std::move(f));
2655 return std::move(*this);
2656 }
2657 /// @}
2658
2659 /// @{
2660 /**
2661 * Sets a function that controls whether @c run() continues. It is called with the current time in seconds.
2662 * Return @c true to continue or @c false to stop gracefully, leaving valid output.
2663 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2664 */
2665 TTranscoderT& onContinue(std::function<bool(double)> f) & {
2666 ensureCallback().setOnContinue(std::move(f));
2667 return *this;
2668 }
2669
2670 TTranscoderT&& onContinue(std::function<bool(double)> f) && {
2671 ensureCallback().setOnContinue(std::move(f));
2672 return std::move(*this);
2673 }
2674 /// @}
2675
2676 /// @{
2677 /**
2678 * Sets a function called when an input format is detected or changes in push mode, with the index of the input
2679 * socket. It can inspect the detected inputs and reconfigure outputs.
2680 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2681 */
2682 TTranscoderT& onInputChange(std::function<void(int32_t)> f) & {
2683 ensureCallback().setOnInputChange(std::move(f));
2684 return *this;
2685 }
2686
2687 TTranscoderT&& onInputChange(std::function<void(int32_t)> f) && {
2688 ensureCallback().setOnInputChange(std::move(f));
2689 return std::move(*this);
2690 }
2691 /// @}
2692
2693 /// @{
2694 /**
2695 * Adds an input socket. The transcoder retains the socket.
2696 * @param socket The input socket.
2697 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2698 */
2699 TTranscoderT& addInput(const TMediaSocketT<CharT>& socket) & {
2700 transcoder_->inputs()->add(socket.get());
2701 return *this;
2702 }
2703
2704 TTranscoderT&& addInput(const TMediaSocketT<CharT>& socket) && {
2705 transcoder_->inputs()->add(socket.get());
2706 return std::move(*this);
2707 }
2708 /// @}
2709
2710 /// @{
2711 /**
2712 * Removes the input socket at @p index.
2713 * @param index Zero-based index of the socket.
2714 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2715 */
2716 TTranscoderT& removeInput(int32_t index) & {
2717 transcoder_->inputs()->remove(index);
2718 return *this;
2719 }
2720
2721 TTranscoderT&& removeInput(int32_t index) && {
2722 transcoder_->inputs()->remove(index);
2723 return std::move(*this);
2724 }
2725 /// @}
2726
2727 /// @{
2728 /**
2729 * Adds an output socket. The transcoder retains the socket.
2730 * @param socket The output socket.
2731 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2732 */
2733 TTranscoderT& addOutput(const TMediaSocketT<CharT>& socket) & {
2734 transcoder_->outputs()->add(socket.get());
2735 return *this;
2736 }
2737
2738 TTranscoderT&& addOutput(const TMediaSocketT<CharT>& socket) && {
2739 transcoder_->outputs()->add(socket.get());
2740 return std::move(*this);
2741 }
2742 /// @}
2743
2744 /// @{
2745 /**
2746 * Removes the output socket at @p index.
2747 * @param index Zero-based index of the socket.
2748 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2749 */
2750 TTranscoderT& removeOutput(int32_t index) & {
2751 transcoder_->outputs()->remove(index);
2752 return *this;
2753 }
2754
2755 TTranscoderT&& removeOutput(int32_t index) && {
2756 transcoder_->outputs()->remove(index);
2757 return std::move(*this);
2758 }
2759 /// @}
2760
2761 /// Returns a non-owning view of the input socket list.
2762 TMediaSocketList inputs() const { return TMediaSocketList(transcoder_->inputs()); }
2763
2764 /// Returns the input socket at @p index, wrapping the existing (non-owned) pointer.
2765 TMediaSocketT<CharT> inputs(int32_t index) const {
2766 return TMediaSocketT<CharT>(transcoder_->inputs()->at(index));
2767 }
2768
2769 /// Returns a non-owning view of the output socket list.
2770 TMediaSocketList outputs() const { return TMediaSocketList(transcoder_->outputs()); }
2771
2772 /// Returns the output socket at @p index, wrapping the existing (non-owned) pointer.
2773 TMediaSocketT<CharT> outputs(int32_t index) const {
2774 return TMediaSocketT<CharT>(transcoder_->outputs()->at(index));
2775 }
2776
2777 /// @{
2778 /**
2779 * Initializes the transcoder from the configured inputs and outputs. When it succeeds the transcoder is ready
2780 * to process data with @c run(), or with @c push() and @c pull().
2781 * @throws TAVBlocksException if the transcoder cannot be opened.
2782 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2783 */
2784 TTranscoderT& open() & {
2785 if (!transcoder_->open()) {
2786 throw TAVBlocksException("Failed to open transcoder", TErrorInfo(transcoder_->error()));
2787 }
2788 return *this;
2789 }
2790
2791 TTranscoderT&& open() && {
2792 if (!transcoder_->open()) {
2793 throw TAVBlocksException("Failed to open transcoder", TErrorInfo(transcoder_->error()));
2794 }
2795 return std::move(*this);
2796 }
2797 /// @}
2798
2799 /// Opens the transcoder without throwing. Returns @c true on success.
2800 bool tryOpen() {
2801 return transcoder_->open() == TRUE;
2802 }
2803
2804 /**
2805 * Pulls output data from the transcoder.
2806 * @param[out] outputIndex Receives the index of the output socket the data belongs to.
2807 * @param[out] sample Receives the output data.
2808 * @return @c true on success.
2809 */
2810 bool pull(int32_t& outputIndex, TMediaSample& sample) {
2811 return transcoder_->pull(outputIndex, sample.get()) == TRUE;
2812 }
2813
2814 /**
2815 * Pushes input data to the transcoder. The sample is used only within this call and is not retained. The
2816 * transcoder may consume only part of it: on return the buffer's data offset and size show what is left, which
2817 * matters when more data is appended for the next push.
2818 * @param inputIndex Index of the input socket the data is for.
2819 * @param sample The input data.
2820 * @return @c true on success.
2821 */
2822 bool push(int32_t inputIndex, TMediaSample& sample) {
2823 return transcoder_->push(inputIndex, sample.get()) == TRUE;
2824 }
2825
2826 /// Signals end-of-stream on the input socket at @p inputIndex.
2827 /// Equivalent to pushing a null (empty) sample.
2828 bool pushEos(int32_t inputIndex) {
2829 return transcoder_->push(inputIndex, nullptr) == TRUE;
2830 }
2831
2832 /// @{
2833 /**
2834 * Runs an automatic transcoding. It returns when the transcoding is finished. All inputs and outputs must be
2835 * associated with files or user streams.
2836 * @throws TAVBlocksException if the transcoding fails or run mode cannot be used with these inputs and outputs.
2837 * @return This object, for chaining. On a temporary the rvalue overload returns the object by rvalue reference, so the chain can be returned or moved.
2838 */
2839 TTranscoderT& run() & {
2840 if (!transcoder_->run()) {
2841 throw TAVBlocksException("Failed to run transcoder", TErrorInfo(transcoder_->error()));
2842 }
2843 return *this;
2844 }
2845
2846 TTranscoderT&& run() && {
2847 if (!transcoder_->run()) {
2848 throw TAVBlocksException("Failed to run transcoder", TErrorInfo(transcoder_->error()));
2849 }
2850 return std::move(*this);
2851 }
2852 /// @}
2853
2854 /// Closes the transcoder. When closed it neither accepts nor delivers data. The inputs and outputs are not modified.
2855 void close() {
2856 transcoder_->close();
2857 }
2858
2859 /// Opens, runs and closes the transcoder (file to file mode): the whole @c open().run().close() sequence in
2860 /// one call. The transcoder is closed even if @c run() throws; @c TAVBlocksException is thrown if it cannot be
2861 /// opened or fails to run.
2862 /// @code
2863 /// TTranscoder().allowDemoMode(true).addInput(in).addOutput(out).transcode();
2864 /// @endcode
2865 void transcode() {
2866 open();
2867 try {
2868 run();
2869 } catch (...) {
2870 close();
2871 throw;
2872 }
2873 close();
2874 }
2875
2876 /**
2877 * Flushes the data buffered in the transcoder to the output and marks the end of the stream for all inputs. Push
2878 * mode only. Do not push data after flushing.
2879 * @return @c true on success.
2880 */
2881 bool flush() {
2882 return transcoder_->flush() == TRUE;
2883 }
2884
2885 /// Returns the error information for the last operation.
2886 TErrorInfo error() const {
2887 return TErrorInfo(transcoder_->error());
2888 }
2889
2890 /// Returns the raw underlying pointer. For interop with the core API only.
2891 primo::avblocks::Transcoder* get() const { return transcoder_.get(); }
2892};
2893
2894// Type aliases for convenience
2895using TTranscoder = TTranscoderT<char>;
2896using TTranscoderW = TTranscoderT<wchar_t>;
2897
2898} // namespace primo::avblocks::modern