avcpp  2.0
Wrapper for the FFmpeg that simplify usage from C++ projects.
avutils.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "avcpp/avconfig.h"
4 
5 #include <ranges>
6 #include <string>
7 #include <vector>
8 #include <deque>
9 #include <memory>
10 #include <mutex>
11 #include <sstream>
12 #include <algorithm>
13 #include <functional>
14 #include <type_traits>
15 #include <limits>
16 
17 #if AVCPP_CXX_STANDARD >= 20
18 # include <span>
19 #endif
20 
21 #include "ffmpeg.h"
22 #include "avtime.h"
23 
24 #if AVCPP_HAS_AVFORMAT
25 extern "C" {
26 #include <libavformat/avformat.h>
27 }
28 #endif
29 
30 //
31 // Functions
32 //
33 namespace av {
34 
35 // Basic FFmpeg constants
36 constexpr auto NoPts = static_cast<int64_t>(AV_NOPTS_VALUE);
37 constexpr auto TimeBase = static_cast<int>(AV_TIME_BASE);
38 constexpr auto TimeBaseQ = AVRational{1, AV_TIME_BASE};
39 
40 
41 template<typename R, typename T>
42 R lexical_cast(const T& v)
43 {
44  R result;
45  std::stringstream ss;
46  ss << v;
47  ss >> result;
48  return result;
49 }
50 
52 {
53 protected:
54  noncopyable() = default;
55  noncopyable( const noncopyable& ) = delete;
56  void operator=( const noncopyable& ) = delete;
57 };
58 
66 void set_logging_level(int32_t level);
67 
68 
78 void set_logging_level(const std::string& level);
79 
80 // Compat code
81 #define setFFmpegLoggingLevel set_logging_level
82 
90 [[deprecated("Use av::hex_dump()")]]
91 void dumpBinaryBuffer(uint8_t *buffer, int buffer_size, int width = 16);
92 
93 
99 std::string error2string(int error);
100 
101 }
102 
103 
104 
105 
106 //
107 // Classes
108 //
109 namespace av {
110 
112 {
113  void operator()(void *) {}
114 };
115 
121 namespace v1 {
122 struct AvDeleter
123 {
124  bool operator() (struct SwsContext* &swsContext);
125  bool operator() (struct AVCodecContext* &codecContext);
126 #if AVCPP_HAS_AVFORMAT
127  bool operator() (struct AVOutputFormat* &format);
128  bool operator() (struct AVFormatContext* &formatContext);
129 #endif // if AVCPP_HAS_AVFORMAT
130  bool operator() (struct AVFrame* &frame);
131  bool operator() (struct AVPacket* &packet);
132  bool operator() (struct AVDictionary* &dictionary);
133 #if AVCPP_HAS_AVFILTER
134  bool operator ()(struct AVFilterInOut* &filterInOut);
135 #endif // if AVCPP_HAS_AVFILTER
136  bool operator() (struct AVBufferRef* &bufferRef);
137 };
138 } // ::v1
139 
140 inline namespace v2 {
142 {
143  template<typename T>
144  bool operator() (T *ptr) {
145  return v1::AvDeleter()(ptr);
146  }
147 };
148 }
149 
150 template<typename T>
151 std::unique_ptr<T, void(*)(void*)> malloc(size_t size)
152 {
153  return {static_cast<T*>(av_malloc(size)), av_free};
154 }
155 
156 template<typename T>
157 std::unique_ptr<T, void(*)(void*)> mallocz(size_t size)
158 {
159  return {static_cast<T*>(av_mallocz(size)), av_free};
160 }
161 
162 template<typename T>
163 std::unique_ptr<T, void(*)(void*)> memdup(const void *p, size_t size)
164 {
165  return {static_cast<T*>(av_memdup(p, size)), av_free};
166 }
167 
171 #if 0
172 struct AvNextElement
173 {
174  AVFilterInOut * operator()(AVFilterInOut * x) const
175  {
176  if (x)
177  return x->next;
178  else
179  return 0;
180  }
181 };
182 #endif
183 
184 
185 
198 template<typename T, typename V = T>
200 {
201 public:
207  ScopedValue(T &var, const V& outValue)
208  : var(var),
209  outValue(outValue)
210  {
211  }
212 
219  ScopedValue(T &var, const V &inValue, const V &outValue)
220  : var(var),
221  outValue(outValue)
222  {
223  this->var = inValue;
224  }
225 
227  {
228  var = outValue;
229  }
230 
231 private:
232  T& var;
233  V outValue;
234 };
235 
236 
265 {
266 public:
267  template<typename Proc>
268  ScopeOutAction(const Proc& proc)
269  : m_proc(proc)
270  {}
271 
272  template<typename Proc>
273  ScopeOutAction(Proc&& proc)
274  : m_proc(std::forward<Proc>(proc))
275  {}
276 
278  {
279  if (m_proc)
280  m_proc();
281  }
282 
283 private:
284  std::function<void()> m_proc;
285 };
286 
287 
289 
290 #if AVCPP_CXX_STANDARD >= 20
291 
295 template<class T>
296 struct SentinelEndPolicy
297 {
298  using value_type = std::remove_reference_t<T>;
299  value_type* end{};
300  constexpr bool isEnd(T* it) const noexcept {
301  return it == end;
302  }
303 };
304 
308 template<class T>
309 struct SentinelUntilPolicy
310 {
311  using value_type = std::remove_cvref_t<T>;
312  value_type value{};
313  constexpr bool isEnd(T* it) const noexcept {
314  return it == nullptr || *it == value;
315  }
316 };
317 
318 
322 template<class T, class Policy>
323 struct ArraySentinel
324 {
325  Policy policy;
326  friend constexpr bool operator==(T* it, const ArraySentinel& s) noexcept {
327  return s.policy.isEnd(it);
328  }
329 };
330 
331 template<class T, class U, bool UseProxy>
332 struct ReferenceSelector;
333 
334 template<class T, class U>
335 struct ReferenceSelector<T, U, true>
336 {
337  using Type = T&;
338 };
339 
340 template<class T, class U>
341 struct ReferenceSelector<T, U, false>
342 {
343  using Type = U;
344 };
345 
352 template<typename T, typename U>
353 struct ArrayIterator
354 {
355  static constexpr bool UseProxy = !std::is_same_v<std::remove_cvref_t<T>, std::remove_cvref_t<U>>;
356 
357  using difference_type = std::ptrdiff_t;
358  using value_type = std::remove_reference_t<U>;
359  using pointer = std::remove_reference_t<T>*; // or also value_type*
360 
361  using reference = typename ReferenceSelector<T, U, !UseProxy>::Type;
362  using iterator_category =
363  std::conditional_t<
364  UseProxy,
365  std::random_access_iterator_tag,
366  std::contiguous_iterator_tag>;
367 
368  ArrayIterator() noexcept = default; // semiregular
369  ArrayIterator(pointer ptr) noexcept : m_ptr(ptr) {}
370 
371  reference operator*() const noexcept {
372  if constexpr (UseProxy)
373  return reference{*m_ptr};
374  else
375  return *m_ptr;
376  }
377 
378  ArrayIterator& operator++() noexcept { m_ptr++; return *this; }
379  ArrayIterator operator++(int) noexcept { ArrayIterator tmp = *this; ++(*this); return tmp; }
380 
381  ArrayIterator& operator--() noexcept { m_ptr--; return *this; }
382  ArrayIterator operator--(int) noexcept { ArrayIterator tmp = *this; --(*this); return tmp; }
383 
384  ArrayIterator& operator+=(int n) noexcept { m_ptr+=n; return *this; }
385  ArrayIterator& operator-=(int n) noexcept { m_ptr-=n; return *this; }
386 
387  // i[n]
388  reference operator[](int n) noexcept {
389  if constexpr (UseProxy)
390  return reference{m_ptr[n]};
391  else
392  return m_ptr[n];
393  }
394  const reference operator[](int n) const noexcept {
395  if constexpr (UseProxy)
396  return reference{m_ptr[n]};
397  else
398  return m_ptr[n];
399  }
400  //reference operator&() noexcept { return }
401  // a + n
402  // n + a
403  friend ArrayIterator operator+(const ArrayIterator& a, int n) noexcept { return {a.m_ptr + n}; }
404  friend ArrayIterator operator+(int n, const ArrayIterator& a) noexcept { return {a.m_ptr + n}; }
405  // i - n
406  friend ArrayIterator operator-(const ArrayIterator& a, int n) noexcept { return {a.m_ptr - n}; }
407  // b - a
408  friend difference_type operator-(const ArrayIterator& b, const ArrayIterator& a) noexcept { return b.m_ptr - a.m_ptr; }
409 
410  // a<=>b
411  friend std::strong_ordering operator<=>(const ArrayIterator& a, const ArrayIterator& b) noexcept {
412  return a.m_ptr == b.m_ptr ? std::strong_ordering::equal
413  : a.m_ptr < b.m_ptr ? std::strong_ordering::less
414  : std::strong_ordering::greater;
415  }
416  friend bool operator== (const ArrayIterator& a, const ArrayIterator& b) { return a.m_ptr == b.m_ptr; };
417  friend bool operator!= (const ArrayIterator& a, const ArrayIterator& b) { return !(a == b); };
418 
419  //
420  // Sentinels
421  //
422  friend bool operator==(ArrayIterator it, std::default_sentinel_t) = delete;
423 
424  friend bool operator==(ArrayIterator it, auto sentinel) { return it.m_ptr == sentinel; }
425  friend bool operator!=(ArrayIterator it, auto sentinel) { return it.m_ptr != sentinel; }
426  friend bool operator==(auto sentinel, ArrayIterator it) { return it.m_ptr == sentinel; }
427  friend bool operator!=(auto sentinel, ArrayIterator it) { return it.m_ptr != sentinel; }
428 
429 private:
430  pointer m_ptr{};
431 };
432 
438 template<typename T, typename U, class Policy>
439 class ArrayView : public std::ranges::view_interface<ArrayView<T, U, Policy>>
440 {
441 public:
442  constexpr ArrayView() = default;
443  constexpr ArrayView(T *ptr, Policy policy)
444  : m_ptr(ptr), m_policy(std::move(policy))
445  {}
446 
447  auto constexpr begin() const noexcept
448  {
449  return ArrayIterator<T, U>{m_ptr};
450  }
451 
452  auto constexpr end() const noexcept
453  {
454  // special case to allow back()/size()/etc method for well-defined sizes
455  if constexpr (std::is_same_v<Policy, std::size_t>) {
456  return ArrayIterator<T, U>{m_ptr + m_policy};
457  } else {
458  return ArraySentinel<T, Policy>{m_policy};
459  }
460  }
461 
462 private:
463  T *m_ptr{};
464  Policy m_policy{};
465 };
466 
472 template<class U>
473 auto make_array_view_size(auto* ptr, std::size_t size)
474 {
475  using T = std::remove_reference_t<decltype(*ptr)>;
476  return ArrayView<T, U, std::size_t>(ptr, size);
477 }
478 
484 template<class U>
485 auto make_array_view_until(auto* ptr, auto value)
486 {
487  using T = std::remove_reference_t<decltype(*ptr)>;
488  return ArrayView<T, U, SentinelUntilPolicy<T>>(ptr, SentinelUntilPolicy<T>{value});
489 }
490 
505 template<typename T, typename L>
506  requires std::ranges::range<L> &&
507  requires(L& r) {
508  std::ranges::empty(r);
509  }
510 T guessValue(const T& value, L list)
511 {
512  if (list.empty())
513  return value;
514 
515  T best = value;
516  T bestDistance = (std::numeric_limits<T>::max)();
517 
518  for (auto&& cur : list) {
519  auto const distance = (std::max)(cur, value) - (std::min)(cur, value);
520  if (distance < bestDistance) {
521  bestDistance = distance;
522  best = cur;
523  }
524  }
525 
526  return best;
527 }
528 
529 #endif // AVCPP_CXX_STANDARD
530 
531 template<typename T>
533 {
535  : value(value)
536  {}
537 
538  bool operator() (const T& value) const
539  {
540  if (this->value == value)
541  return true;
542 
543  return false;
544  }
545 
546  const T& value;
547 };
548 
564 template<typename T, typename L, typename C>
565 T guessValue(const T& value, const L * list, C endListComparator)
566 {
567  if (!list)
568  return value;
569 
570  T best = value;
571  T bestDistance = (std::numeric_limits<T>::max)();
572 
573  for (const L * ptr = list; !endListComparator(*ptr); ++ptr) {
574  auto const cur = *ptr;
575  auto const distance = (std::max)(cur, value) - (std::min)(cur, value);
576  if (distance < bestDistance) {
577  bestDistance = distance;
578  best = cur;
579  }
580  }
581 
582  return best;
583 }
584 
585 
586 template<typename T, typename Container>
587 void array_to_container(const T* array, std::size_t nelements, Container &container)
588 {
589  if (!array || nelements == 0)
590  return;
591  std::copy_n(array, array + nelements, std::back_inserter(container));
592 }
593 
594 template<typename T, typename Container, typename Callable>
595 void array_to_container(const T* array, std::size_t nelements, Container &container, Callable convert)
596 {
597  if (!array || nelements == 0)
598  return;
599  // TBD: implement in more clean way
600  //std::copy_n(array, array + nelemnts, std::back_inserter(container));
601  for (auto i = 0u; i < nelements; ++i) {
602  container.push_back(convert(array[i]));
603  }
604 }
605 
606 template<typename T, typename Container, typename Compare>
607 void array_to_container(const T* array, Container &container, Compare isEnd)
608 {
609  if (!array)
610  return;
611  T value;
612  while (!isEnd(value = *array++))
613  container.push_back(value);
614 }
615 
616 template<typename T, typename Container, typename Compare, typename Callable>
617 void array_to_container(const T* array, Container &container, Compare isEnd, Callable convert)
618 {
619  if (!array)
620  return;
621  T value;
622  while (!isEnd(value = *array++))
623  container.push_back(convert(value));
624 }
625 
627 
628 //
629 // Allow to use without AVFORMAT library
630 //
631 void hex_dump(FILE *f, const uint8_t *buf, std::size_t size);
632 void hex_dump_log(void *avcl, int level, const uint8_t *buf, std::size_t size);
633 
634 #if AVCPP_CXX_STANDARD >= 20
635 void hex_dump(FILE *f, std::span<const uint8_t> buf);
636 void hex_dump_log(void *avcl, int level, std::span<const uint8_t> buf);
637 #endif // if AVCPP_CXX_STANDARD >= 20
638 
639 } // ::av
640 
642 
643 #ifdef __cpp_lib_format
644 # include <format>
645 
646 namespace av {
647 template <typename B>
648 concept has_name_method_with_ec = requires(const B& type, std::error_code ec) {
649  { type.name(ec) } -> std::convertible_to<std::string_view>;
650 };
651 
652 template <typename B>
653 concept has_name_method_without_ec = requires(const B& type) {
654  { type.name() } -> std::convertible_to<std::string_view>;
655 };
656 
657 template <typename B>
658 concept has_long_name_method_with_ec = requires(const B& type, std::error_code ec) {
659  { type.longName(ec) } -> std::convertible_to<std::string_view>;
660 };
661 
662 template <typename B>
663 concept has_long_name_method_without_ec = requires(const B& type) {
664  { type.longName() } -> std::convertible_to<std::string_view>;
665 };
666 } // ::av
667 
668 template <class T, class CharT>
669  requires av::has_name_method_with_ec<T> || av::has_name_method_without_ec<T>
670 struct std::formatter<T, CharT>
671 {
672  bool longName = false;
673 
674  template<typename ParseContext>
675  constexpr ParseContext::iterator parse(ParseContext& ctx)
676  {
677  auto it = ctx.begin();
678  if constexpr (requires { requires av::has_long_name_method_with_ec<T> || av::has_long_name_method_without_ec<T>; }) {
679  if (it == ctx.end())
680  return it;
681  if (*it == 'l') {
682  longName = true;
683  ++it;
684  }
685  if (it != ctx.end() && *it != '}')
686  throw std::format_error("Invalid format args");
687  }
688  return it;
689  }
690 
691  template<typename ParseContext>
692  auto format(const T& value, ParseContext& ctx) const
693  {
694  if (longName) {
695  if constexpr (requires { requires av::has_long_name_method_with_ec<T>; }) {
696  std::error_code dummy;
697  return std::format_to(ctx.out(), "{}", value.longName(dummy));
698  } else if constexpr (requires { requires av::has_long_name_method_without_ec<T>; }) {
699  return std::format_to(ctx.out(), "{}", value.longName());
700  }
701  } else {
702  if constexpr (requires { requires av::has_name_method_with_ec<T>; }) {
703  std::error_code dummy;
704  return std::format_to(ctx.out(), "{}", value.name(dummy));
705  } else {
706  return std::format_to(ctx.out(), "{}", value.name());
707  }
708  }
709  return ctx.out();
710  }
711 };
712 #endif
The ScopeOutAction class - guard-type class that allows points callback that will be called at the sc...
Definition: avutils.h:265
~ScopeOutAction()
Definition: avutils.h:277
ScopeOutAction(Proc &&proc)
Definition: avutils.h:273
ScopeOutAction(const Proc &proc)
Definition: avutils.h:268
Functor to take next element in list/array.
Definition: avutils.h:200
ScopedValue(T &var, const V &outValue)
Ctor.
Definition: avutils.h:207
~ScopedValue()
Definition: avutils.h:226
ScopedValue(T &var, const V &inValue, const V &outValue)
Ctor.
Definition: avutils.h:219
Definition: avutils.h:52
void operator=(const noncopyable &)=delete
noncopyable()=default
noncopyable(const noncopyable &)=delete
Definition: audioresampler.cpp:8
R lexical_cast(const T &v)
Definition: avutils.h:42
string error2string(int error)
C++ verstion of the av_err2str()
Definition: avutils.cpp:211
Timestamp operator-(const Timestamp &left, const Timestamp &right) noexcept
Definition: timestamp.cpp:102
Timestamp operator+(const Timestamp &left, const Timestamp &right) noexcept
Definition: timestamp.cpp:90
std::unique_ptr< T, void(*)(void *)> memdup(const void *p, size_t size)
Definition: avutils.h:163
Timestamp operator*(const Timestamp &left, const Timestamp &right) noexcept
Definition: timestamp.cpp:114
std::unique_ptr< T, void(*)(void *)> malloc(size_t size)
Definition: avutils.h:151
void hex_dump_log(void *avcl, int level, const uint8_t *buf, std::size_t size)
Definition: avutils.cpp:330
void dumpBinaryBuffer(uint8_t *buffer, int buffer_size, int width)
dump_binary_buffer Dump binary buffer to std out in HEX view
Definition: avutils.cpp:77
T guessValue(const T &value, const L *list, C endListComparator)
Select more approptiate value from given value list.
Definition: avutils.h:565
constexpr auto TimeBaseQ
Definition: avutils.h:38
void hex_dump(FILE *f, const uint8_t *buf, std::size_t size)
Definition: avutils.cpp:325
bool operator==(const Dictionary::Entry &lhs, const Dictionary::Entry &rhs)
Definition: dictionary.cpp:382
constexpr auto TimeBase
Definition: avutils.h:37
bool operator!=(const Dictionary::Entry &lhs, const Dictionary::Entry &rhs)
Definition: dictionary.cpp:387
void array_to_container(const T *array, std::size_t nelements, Container &container)
Definition: avutils.h:587
void set_logging_level(int32_t level)
This method can be used to turn up or down FFmpeg's logging level.
Definition: avutils.cpp:26
std::unique_ptr< T, void(*)(void *)> mallocz(size_t size)
Definition: avutils.h:157
constexpr auto NoPts
Definition: avutils.h:36
Definition: averror.h:230
Definition: avutils.h:112
void operator()(void *)
Definition: avutils.h:113
Definition: avutils.h:533
bool operator()(const T &value) const
Definition: avutils.h:538
EqualComparator(const T &value)
Definition: avutils.h:534
const T & value
Definition: avutils.h:546
Definition: avutils.h:123
bool operator()(struct SwsContext *&swsContext)
Definition: avutils.cpp:219
Definition: avutils.h:142
bool operator()(T *ptr)
Definition: avutils.h:144