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