avcpp  2.0
Wrapper for the FFmpeg that simplify usage from C++ projects.
frame.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <vector>
4 #include <memory>
5 #include <stdexcept>
6 
7 #if __has_include(<span>)
8 #include <span>
9 #endif
10 
11 #include "ffmpeg.h"
12 #include "rational.h"
13 #include "timestamp.h"
14 #include "pixelformat.h"
15 #include "sampleformat.h"
16 #include "avutils.h"
17 
18 extern "C" {
19 #include <libavutil/imgutils.h>
20 #include <libavutil/attributes.h>
21 }
22 
23 namespace av
24 {
25 
26 namespace frame {
27 
28 namespace priv {
29 void channel_layout_copy(AVFrame &dst, const AVFrame &src);
30 }
31 
32 static inline int64_t get_best_effort_timestamp(const AVFrame* frame) {
33 #if LIBAVUTIL_VERSION_MAJOR < 56 // < FFmpeg 4.0
34  return av_frame_get_best_effort_timestamp(frame);
35 #else
36  return frame->best_effort_timestamp;
37 #endif
38 }
39 
40 // Based on db6efa1815e217ed76f39aee8b15ee5c64698537
41 static inline uint64_t get_channel_layout(const AVFrame* frame) {
42 #if LIBAVUTIL_VERSION_MAJOR < 56 // < FFmpeg 4.0
43  return static_cast<uint64_t>(av_frame_get_channel_layout(frame));
44 #elif API_NEW_CHANNEL_LAYOUT
45  return frame->ch_layout.order == AV_CHANNEL_ORDER_NATIVE ? frame->ch_layout.u.mask : 0;
46 #else
47  return frame->channel_layout;
48 #endif
49 }
50 
51 static inline void set_channel_layout(AVFrame* frame, uint64_t layout) {
52 #if LIBAVUTIL_VERSION_MAJOR < 56 // < FFmpeg 4.0
53  av_frame_set_channel_layout(frame, static_cast<int64_t>(layout));
54 #elif API_NEW_CHANNEL_LAYOUT
55  av_channel_layout_uninit(&frame->ch_layout);
56  av_channel_layout_from_mask(&frame->ch_layout, layout);
57 #else
58  frame->channel_layout = layout;
59 #endif
60 }
61 
62 
63 static inline int get_channels(const AVFrame* frame) {
64 #if LIBAVUTIL_VERSION_MAJOR < 56 // < FFmpeg 4.0
65  return av_frame_get_channels(frame);
66 #elif API_NEW_CHANNEL_LAYOUT
67  return frame->ch_layout.nb_channels;
68 #else
69  return frame->channels;
70 #endif
71 }
72 
73 static inline bool is_valid_channel_layout(const AVFrame *frame)
74 {
75 #if API_NEW_CHANNEL_LAYOUT
76  return av_channel_layout_check(&frame->ch_layout);
77 #else
78  return frame->channel_layout;
79 #endif
80 }
81 
82 static inline int get_sample_rate(const AVFrame* frame) {
83 #if LIBAVUTIL_VERSION_MAJOR < 56 // < FFmpeg 4.0
84  return av_frame_get_sample_rate(frame);
85 #else
86  return frame->sample_rate;
87 #endif
88 }
89 
90 static inline void set_sample_rate(AVFrame* frame, int sampleRate) {
91 #if LIBAVUTIL_VERSION_MAJOR < 56 // < FFmpeg 4.0
92  av_frame_set_sample_rate(frame, sampleRate);
93 #else
94  frame->sample_rate = sampleRate;
95 #endif
96 }
97 
98 
99 } // ::frame
100 
101 template<typename T>
102 class Frame : public FFWrapperPtr<AVFrame>
103 {
104 protected:
105  T& assignOperator(const T &rhs) {
106  if (this == &rhs)
107  return static_cast<T&>(*this);
108  T(rhs).swap(static_cast<T&>(*this));
109  return static_cast<T&>(*this);
110  }
111 
112  T& moveOperator(T &&rhs) {
113  if (this == &rhs)
114  return static_cast<T&>(*this);
115  T(std::move(rhs)).swap(static_cast<T&>(*this));
116  return static_cast<T&>(*this);
117  }
118 
119 public:
120  Frame() {
121  m_raw = av_frame_alloc();
122  m_raw->opaque = this;
123  }
124 
125  ~Frame() {
126  av_frame_free(&m_raw);
127  }
128 
129  Frame(const AVFrame *frame) {
130  if (frame) {
131  m_raw = av_frame_alloc();
132  m_raw->opaque = this;
133  av_frame_ref(m_raw, frame);
134  }
135  }
136 
137  // Helper ctors to implement move/copy ctors
138  Frame(const T& other) : Frame(other.m_raw) {
139  if (m_raw)
140  copyInfoFrom(other);
141  }
142 
143  Frame(T&& other) : FFWrapperPtr<AVFrame>(nullptr) {
144  if (other.m_raw) {
145  m_raw = av_frame_alloc();
146  m_raw->opaque = this;
147  av_frame_move_ref(m_raw, other.m_raw);
148  copyInfoFrom(other);
149  }
150  }
151 
152  static T null() {
153  return T(nullptr);
154  }
155 
156  // You must implement operators in deveritive classes using assignOperator() and moveOperator()
157  void operator=(const Frame&) = delete;
158 
159  void swap(Frame &other) {
160  using std::swap;
161 #define FRAME_SWAP(x) swap(x, other.x)
162  FRAME_SWAP(m_raw);
166 #undef FRAME_SWAP
167  }
168 
169  void copyInfoFrom(const T& other) {
170  m_timeBase = other.m_timeBase;
171  m_streamIndex = other.m_streamIndex;
172  m_isComplete = other.m_isComplete;
173  }
174 
175  bool isReferenced() const {
176  return m_raw && m_raw->buf[0];
177  }
178 
179  int refCount() const {
180  if (m_raw && m_raw->buf[0])
181  return av_buffer_get_ref_count(m_raw->buf[0]);
182  else
183  return 0;
184  }
185 
186  AVFrame* makeRef() const {
187  return m_raw ? av_frame_clone(m_raw) : nullptr;
188  }
189 
190  T clone(size_t align = 1) const {
191  T result;
192 
193  // Setup data required for buffer allocation
194  result.m_raw->format = m_raw->format;
195  result.m_raw->width = m_raw->width;
196  result.m_raw->height = m_raw->height;
197  result.m_raw->nb_samples = m_raw->nb_samples;
198 
199  frame::priv::channel_layout_copy(*result.m_raw, *m_raw);
200 
201  result.copyInfoFrom(static_cast<const T&>(*this));
202 
203  av_frame_get_buffer(result.m_raw, align);
204  av_frame_copy(result.m_raw, m_raw);
205  av_frame_copy_props(result.m_raw, m_raw);
206  return result;
207  }
208 
209  Timestamp pts() const
210  {
211  return {RAW_GET(pts, av::NoPts), m_timeBase};
212  }
213 
214  attribute_deprecated void setPts(int64_t pts, Rational ptsTimeBase)
215  {
216  RAW_SET(pts, ptsTimeBase.rescale(pts, m_timeBase));
217  }
218 
219  void setPts(const Timestamp &ts)
220  {
221  if (m_timeBase == Rational())
222  m_timeBase = ts.timebase();
224  }
225 
226  const Rational& timeBase() const { return m_timeBase; }
227 
228  void setTimeBase(const Rational &value) {
229  if (m_timeBase == value)
230  return;
231 
232  if (!m_raw)
233  return;
234 
235  int64_t rescaledPts = NoPts;
236  int64_t rescaledBestEffortTs = NoPts;
237 
238  if (m_timeBase != Rational() && value != Rational()) {
239  if (m_raw->pts != av::NoPts)
240  rescaledPts = m_timeBase.rescale(m_raw->pts, value);
241 
242  if (m_raw->best_effort_timestamp != av::NoPts)
243  rescaledBestEffortTs = m_timeBase.rescale(m_raw->best_effort_timestamp, value);
244  } else {
245  rescaledPts = m_raw->pts;
246  rescaledBestEffortTs = m_raw->best_effort_timestamp;
247  }
248 
249  if (m_timeBase != Rational()) {
250  m_raw->pts = rescaledPts;
251  m_raw->best_effort_timestamp = rescaledBestEffortTs;
252  }
253 
254  m_timeBase = value;
255  }
256 
257  int streamIndex() const {
258  return m_streamIndex;
259  }
260 
263  }
264 
265  void setComplete(bool isComplete) {
267  }
268 
269  bool isComplete() const { return m_isComplete; }
270 
271  bool isValid() const {
272  return (!isNull() &&
273  ((m_raw->data[0] && m_raw->linesize[0]) ||
274  ((m_raw->format == AV_PIX_FMT_VAAPI) && ((intptr_t)m_raw->data[3] > 0)))
275  );
276  }
277 
278  operator bool() const { return isValid() && isComplete(); }
279 
280  uint8_t *data(size_t plane = 0) {
281  if (!m_raw || plane >= size_t(AV_NUM_DATA_POINTERS + m_raw->nb_extended_buf))
282  return nullptr;
283  return m_raw->extended_data[plane];
284  }
285 
286  const uint8_t *data(size_t plane = 0) const {
287  if (!m_raw || plane >= size_t(AV_NUM_DATA_POINTERS + m_raw->nb_extended_buf))
288  return nullptr;
289  return m_raw->extended_data[plane];;
290  }
291 
292  size_t size(size_t plane) const {
293  if (!m_raw || plane >= size_t(AV_NUM_DATA_POINTERS + m_raw->nb_extended_buf))
294  return 0;
295  AVBufferRef *buf = plane < AV_NUM_DATA_POINTERS ?
296  m_raw->buf[plane] :
297  m_raw->extended_buf[plane - AV_NUM_DATA_POINTERS];
298  if (buf == nullptr)
299  return 0;
300  return size_t(buf->size);
301  }
302 
303  size_t size() const {
304  if (!m_raw)
305  return 0;
306  size_t total = 0;
307  if (m_raw->buf[0]) {
308  for (auto i = 0; i < AV_NUM_DATA_POINTERS && m_raw->buf[i]; i++) {
309  total += m_raw->buf[i]->size;
310  }
311 
312  for (auto i = 0; i < m_raw->nb_extended_buf; ++i) {
313  total += m_raw->extended_buf[i]->size;
314  }
315  } else if (m_raw->data[0]) {
316  if (m_raw->width && m_raw->height) {
317  uint8_t data[4] = {0};
318  int linesizes[4] = {
319  m_raw->linesize[0],
320  m_raw->linesize[1],
321  m_raw->linesize[2],
322  m_raw->linesize[3],
323  };
324  total = av_image_fill_pointers(reinterpret_cast<uint8_t**>(&data),
325  static_cast<AVPixelFormat>(m_raw->format),
326  m_raw->height,
327  nullptr,
328  linesizes);
329  } else if (m_raw->nb_samples && frame::is_valid_channel_layout(m_raw)) {
330  for (auto i = 0; i < m_raw->nb_extended_buf + AV_NUM_DATA_POINTERS && m_raw->extended_data[i]; ++i) {
331  // According docs, all planes must have same size
332  total += m_raw->linesize[0];
333  }
334  }
335  }
336  return total;
337  }
338 
339  void dump() const {
340  if (!m_raw)
341  return;
342  if (m_raw->buf[0]) {
343  for (size_t i = 0; i < AV_NUM_DATA_POINTERS && m_raw->buf[i]; i++) {
344  av_hex_dump(stdout, m_raw->buf[i]->data, m_raw->buf[i]->size);
345  }
346  } else if (m_raw->data[0]) {
347  av_hex_dump(stdout, m_raw->data[0], size());
348  }
349  }
350 
351 protected:
353  int m_streamIndex {-1};
354  bool m_isComplete {false};
355 };
356 
357 
358 class VideoFrame : public Frame<VideoFrame>
359 {
360 public:
362 
363  VideoFrame() = default;
364  VideoFrame(PixelFormat pixelFormat, int width, int height, int align = 1);
365  VideoFrame(const uint8_t *data, size_t size, PixelFormat pixelFormat, int width, int height, int align = 1);
366 
367  VideoFrame(const VideoFrame &other);
368  VideoFrame(VideoFrame &&other);
369 
370  VideoFrame& operator=(const VideoFrame &rhs);
372 
373  PixelFormat pixelFormat() const;
374  int width() const;
375  int height() const;
376 
377  bool isKeyFrame() const;
378  void setKeyFrame(bool isKey);
379 
380  int quality() const;
381  void setQuality(int quality);
382 
383  AVPictureType pictureType() const;
384  void setPictureType(AVPictureType type = AV_PICTURE_TYPE_NONE);
385 
386  Rational sampleAspectRatio() const;
388 
389  size_t bufferSize(int align = 1, OptionalErrorCode ec = throws()) const;
390  bool copyToBuffer(uint8_t *dst, size_t size, int align = 1, OptionalErrorCode ec = throws());
391  bool copyToBuffer(std::vector<uint8_t>& dst, int align = 1, OptionalErrorCode ec = throws());
392 
393 
408  static VideoFrame wrap(const void *data, size_t size, PixelFormat pixelFormat, int width, int height, int align = 1);
409 
410 #ifdef __cpp_lib_span
423  static VideoFrame wrap(std::span<const std::byte> data, PixelFormat pixelFormat, int width, int height, int align = 1);
424 
439  static VideoFrame wrap(std::span<const std::byte> data, void (*deleter)(void *opaque, uint8_t *data),
440  void *opaque, PixelFormat pixelFormat, int width, int height, int align = 1);
441 #endif
442 };
443 
444 
445 class AudioSamples : public Frame<AudioSamples>
446 {
447 public:
449 
450  AudioSamples() = default;
451  AudioSamples(SampleFormat sampleFormat, int samplesCount, uint64_t channelLayout, int sampleRate, int align = SampleFormat::AlignDefault);
452  AudioSamples(const uint8_t *data, size_t size,
453  SampleFormat sampleFormat, int samplesCount, uint64_t channelLayout, int sampleRate, int align = SampleFormat::AlignDefault);
454 
455  AudioSamples(const AudioSamples &other);
456  AudioSamples(AudioSamples &&other);
457 
458  AudioSamples& operator=(const AudioSamples &rhs);
460 
461  int init(SampleFormat sampleFormat, int samplesCount, uint64_t channelLayout, int sampleRate, int align = SampleFormat::AlignDefault);
462 
463  SampleFormat sampleFormat() const;
464  int samplesCount() const;
465  int channelsCount() const;
466  uint64_t channelsLayout() const;
467  int sampleRate() const;
468  size_t sampleBitDepth(OptionalErrorCode ec = throws()) const;
469  bool isPlanar() const;
470 
471  std::string channelsLayoutString() const;
472 };
473 
474 
475 } // ::av
476 
Definition: frame.h:446
uint64_t channelsLayout() const
Definition: frame.cpp:371
SampleFormat sampleFormat() const
Definition: frame.cpp:356
size_t sampleBitDepth(OptionalErrorCode ec=throws()) const
Definition: frame.cpp:381
int channelsCount() const
Definition: frame.cpp:366
int sampleRate() const
Definition: frame.cpp:376
std::string channelsLayoutString() const
Definition: frame.cpp:393
bool isPlanar() const
Definition: frame.cpp:388
int samplesCount() const
Definition: frame.cpp:361
AudioSamples()=default
AudioSamples & operator=(const AudioSamples &rhs)
Definition: frame.cpp:346
int init(SampleFormat sampleFormat, int samplesCount, uint64_t channelLayout, int sampleRate, int align=SampleFormat::AlignDefault)
Definition: frame.cpp:287
Definition: frame.h:103
void setTimeBase(const Rational &value)
Definition: frame.h:228
void setStreamIndex(int streamIndex)
Definition: frame.h:261
bool isReferenced() const
Definition: frame.h:175
T & moveOperator(T &&rhs)
Definition: frame.h:112
bool isValid() const
Definition: frame.h:271
size_t size(size_t plane) const
Definition: frame.h:292
Frame(const T &other)
Definition: frame.h:138
attribute_deprecated void setPts(int64_t pts, Rational ptsTimeBase)
Definition: frame.h:214
void copyInfoFrom(const T &other)
Definition: frame.h:169
int m_streamIndex
Definition: frame.h:353
bool isComplete() const
Definition: frame.h:269
T clone(size_t align=1) const
Definition: frame.h:190
int refCount() const
Definition: frame.h:179
bool m_isComplete
Definition: frame.h:354
~Frame()
Definition: frame.h:125
Timestamp pts() const
Definition: frame.h:209
size_t size() const
Definition: frame.h:303
void setPts(const Timestamp &ts)
Definition: frame.h:219
Frame(T &&other)
Definition: frame.h:143
AVFrame * makeRef() const
Definition: frame.h:186
void dump() const
Definition: frame.h:339
T & assignOperator(const T &rhs)
Definition: frame.h:105
Frame()
Definition: frame.h:120
const uint8_t * data(size_t plane=0) const
Definition: frame.h:286
void swap(Frame &other)
Definition: frame.h:159
int streamIndex() const
Definition: frame.h:257
Rational m_timeBase
Definition: frame.h:352
uint8_t * data(size_t plane=0)
Definition: frame.h:280
const Rational & timeBase() const
Definition: frame.h:226
void setComplete(bool isComplete)
Definition: frame.h:265
Frame(const AVFrame *frame)
Definition: frame.h:129
void operator=(const Frame &)=delete
Definition: averror.h:64
The PixelFormat class is a simple wrapper for AVPixelFormat that allow to acces it it properties.
Definition: pixelformat.h:27
Definition: rational.h:26
int64_t rescale(int64_t srcValue, const Rational &dstBase) const noexcept
Definition: rational.cpp:36
The SampleFormat class is a simple proxy class for AVSampleFormat.
Definition: sampleformat.h:22
@ AlignDefault
Definition: sampleformat.h:26
The Timestamp class represents timestamp value and it timebase.
Definition: timestamp.h:14
int64_t timestamp() const noexcept
Definition: timestamp.cpp:19
const Rational & timebase() const noexcept
Definition: timestamp.cpp:29
Definition: frame.h:359
VideoFrame()=default
bool isKeyFrame() const
Definition: frame.cpp:153
VideoFrame & operator=(const VideoFrame &rhs)
Definition: frame.cpp:128
void setQuality(int quality)
Definition: frame.cpp:182
Rational sampleAspectRatio() const
Definition: frame.cpp:197
void setSampleAspectRatio(const Rational &sampleAspectRatio)
Definition: frame.cpp:202
size_t bufferSize(int align=1, OptionalErrorCode ec=throws()) const
Definition: frame.cpp:207
bool copyToBuffer(uint8_t *dst, size_t size, int align=1, OptionalErrorCode ec=throws())
Definition: frame.cpp:218
int height() const
Definition: frame.cpp:148
int width() const
Definition: frame.cpp:143
static VideoFrame wrap(const void *data, size_t size, PixelFormat pixelFormat, int width, int height, int align=1)
Wrap external data into VideoFrame object ready to use with FFmpeg/AvCpp.
Definition: frame.cpp:264
void setPictureType(AVPictureType type=AV_PICTURE_TYPE_NONE)
Definition: frame.cpp:192
PixelFormat pixelFormat() const
Definition: frame.cpp:138
void setKeyFrame(bool isKey)
Definition: frame.cpp:162
int quality() const
Definition: frame.cpp:177
AVPictureType pictureType() const
Definition: frame.cpp:187
#define RAW_GET(field, def)
Definition: ffmpeg.h:92
#define RAW_SET(field, val)
Definition: ffmpeg.h:93
#define FRAME_SWAP(x)
void channel_layout_copy(AVFrame &dst, const AVFrame &src)
Definition: frame.cpp:409
static int get_sample_rate(const AVFrame *frame)
Definition: frame.h:82
static int64_t get_best_effort_timestamp(const AVFrame *frame)
Definition: frame.h:32
static int get_channels(const AVFrame *frame)
Definition: frame.h:63
static void set_sample_rate(AVFrame *frame, int sampleRate)
Definition: frame.h:90
static bool is_valid_channel_layout(const AVFrame *frame)
Definition: frame.h:73
static void set_channel_layout(AVFrame *frame, uint64_t layout)
Definition: frame.h:51
static uint64_t get_channel_layout(const AVFrame *frame)
Definition: frame.h:41
Definition: audioresampler.cpp:8
constexpr auto NoPts
Definition: avutils.h:69
Definition: ffmpeg.h:67
AVFrame * m_raw
Definition: ffmpeg.h:89
bool isNull() const
Definition: ffmpeg.h:75