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