MythTV  master
mythavutil.cpp
Go to the documentation of this file.
1 //
2 // mythavutil.cpp
3 // MythTV
4 //
5 // Created by Jean-Yves Avenard on 28/06/2014.
6 // Copyright (c) 2014 Bubblestuff Pty Ltd. All rights reserved.
7 //
8 
9 #include "mythframe.h"
10 #include "mythavutil.h"
11 #include "mythcorecontext.h"
12 #include "mythconfig.h"
13 #include "vaapi2context.h"
14 extern "C" {
15 #include "libswscale/swscale.h"
16 #include "libavfilter/avfilter.h"
17 #include "libavcodec/avcodec.h"
18 #include "libavfilter/buffersrc.h"
19 #include "libavfilter/buffersink.h"
20 #include "libavutil/imgutils.h"
21 #include "libavformat/avformat.h"
22 }
23 #include <QMutexLocker>
24 
26 {
27  switch (type)
28  {
29  case FMT_NV12:
30  return AV_PIX_FMT_NV12;
31  case FMT_YUV422P:
32  return AV_PIX_FMT_YUV422P;
33  case FMT_BGRA:
34  return AV_PIX_FMT_BGRA;
35  case FMT_YUY2:
36  return AV_PIX_FMT_UYVY422;
37  case FMT_RGB24:
38  return AV_PIX_FMT_RGB24;
39  case FMT_RGB32:
40  return AV_PIX_FMT_RGB32;
41  default:
42  return AV_PIX_FMT_YUV420P;
43  }
44 }
45 
47 {
48  switch (fmt)
49  {
50  case AV_PIX_FMT_NV12:
51  return FMT_NV12;
52  case AV_PIX_FMT_YUV422P:
53  return FMT_YUV422P;
54  case AV_PIX_FMT_RGB32:
55  return FMT_RGB32;
56  case AV_PIX_FMT_UYVY422:
57  return FMT_YUY2;
58  case AV_PIX_FMT_RGB24:
59  return FMT_RGB24;
60  default:
61  return FMT_YV12;
62  }
63 }
64 
65 int AVPictureFill(AVFrame *pic, const VideoFrame *frame, AVPixelFormat fmt)
66 {
67  if (fmt == AV_PIX_FMT_NONE)
68  {
69  fmt = FrameTypeToPixelFormat(frame->codec);
70  }
71 
72  av_image_fill_arrays(pic->data, pic->linesize, frame->buf,
73  fmt, frame->width, frame->height, IMAGE_ALIGN);
74  pic->data[1] = frame->buf + frame->offsets[1];
75  pic->data[2] = frame->buf + frame->offsets[2];
76  pic->linesize[0] = frame->pitches[0];
77  pic->linesize[1] = frame->pitches[1];
78  pic->linesize[2] = frame->pitches[2];
79  return (int)buffersize(frame->codec, frame->width, frame->height);
80 }
81 
83 {
84 private:
85  MythAVCopyPrivate(const MythAVCopyPrivate &) = delete; // not copyable
86  MythAVCopyPrivate &operator=(const MythAVCopyPrivate &) = delete; // not copyable
87 
88 public:
89  explicit MythAVCopyPrivate(bool uswc)
90  : swsctx(nullptr), copyctx(new MythUSWCCopy(4096, !uswc)),
91  width(0), height(0), size(0), format(AV_PIX_FMT_NONE)
92  {
93  }
94 
96  {
97  if (swsctx)
98  {
99  sws_freeContext(swsctx);
100  }
101  delete copyctx;
102  }
103 
104  int SizeData(int _width, int _height, AVPixelFormat _fmt)
105  {
106  if (_width == width && _height == height && _fmt == format)
107  {
108  return size;
109  }
110  size = av_image_get_buffer_size(_fmt, _width, _height, IMAGE_ALIGN);
111  width = _width;
112  height = _height;
113  format = _fmt;
114  return size;
115  }
116 
117  SwsContext *swsctx;
120  AVPixelFormat format;
121 };
122 
124 {
125 }
126 
128 {
129  delete d;
130 }
131 
132 void MythAVCopy::FillFrame(VideoFrame *frame, const AVFrame *pic, int pitch,
133  int width, int height, AVPixelFormat pix_fmt)
134 {
135  int size = av_image_get_buffer_size(pix_fmt, width, height, IMAGE_ALIGN);
136 
137  if (pix_fmt == AV_PIX_FMT_YUV420P)
138  {
139  int chroma_pitch = pitch >> 1;
140  int chroma_height = height >> 1;
141  int offsets[3] =
142  { 0,
143  pitch * height,
144  pitch * height + chroma_pitch * chroma_height };
145  int pitches[3] = { pitch, chroma_pitch, chroma_pitch };
146 
147  init(frame, FMT_YV12, pic->data[0], width, height, size, pitches, offsets);
148  }
149  else if (pix_fmt == AV_PIX_FMT_NV12)
150  {
151  int offsets[3] = { 0, pitch * height, 0 };
152  int pitches[3] = { pitch, pitch, 0 };
153 
154  init(frame, FMT_NV12, pic->data[0], width, height, size, pitches, offsets);
155  }
156 }
157 
158 int MythAVCopy::Copy(AVFrame *dst, AVPixelFormat dst_pix_fmt,
159  const AVFrame *src, AVPixelFormat pix_fmt,
160  int width, int height)
161 {
162  if ((pix_fmt == AV_PIX_FMT_YUV420P || pix_fmt == AV_PIX_FMT_NV12) &&
163  (dst_pix_fmt == AV_PIX_FMT_YUV420P || dst_pix_fmt == AV_PIX_FMT_NV12))
164  {
165  VideoFrame framein, frameout;
166 
167  FillFrame(&framein, src, width, width, height, pix_fmt);
168  FillFrame(&frameout, dst, width, width, height, dst_pix_fmt);
169 
170  d->copyctx->copy(&frameout, &framein);
171  return frameout.size;
172  }
173 
174  int new_width = width;
175 #if ARCH_ARM
176  // The ARM build of FFMPEG has a bug that if sws_scale is
177  // called with source and dest sizes the same, and
178  // formats as shown below, it causes a bus error and the
179  // application core dumps. To avoid this I make a -1
180  // difference in the new width, causing it to bypass
181  // the code optimization which is failing.
182  if (pix_fmt == AV_PIX_FMT_YUV420P
183  && dst_pix_fmt == AV_PIX_FMT_BGRA)
184  new_width = width - 1;
185 #endif
186  d->swsctx = sws_getCachedContext(d->swsctx, width, height, pix_fmt,
187  new_width, height, dst_pix_fmt,
188  SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
189  if (d->swsctx == nullptr)
190  {
191  return -1;
192  }
193 
194  sws_scale(d->swsctx, src->data, src->linesize,
195  0, height, dst->data, dst->linesize);
196 
197  return d->SizeData(width, height, dst_pix_fmt);
198 }
199 
201 {
202  if ((src->codec == FMT_YV12 || src->codec == FMT_NV12) &&
203  (dst->codec == FMT_YV12 || dst->codec == FMT_NV12))
204  {
205  d->copyctx->copy(dst, src);
206  return dst->size;
207  }
208 
209  AVFrame srcpic, dstpic;
210 
211  AVPictureFill(&srcpic, src);
212  AVPictureFill(&dstpic, dst);
213 
214  return Copy(&dstpic, FrameTypeToPixelFormat(dst->codec),
215  &srcpic, FrameTypeToPixelFormat(src->codec),
216  src->width, src->height);
217 }
218 
219 int MythAVCopy::Copy(AVFrame *pic, const VideoFrame *frame,
220  unsigned char *buffer, AVPixelFormat fmt)
221 {
223  int size = buffersize(type, frame->width, frame->height, 0) + 16;
224  unsigned char *sbuf = buffer ? buffer : (unsigned char*)av_malloc(size);
225 
226  if (!sbuf)
227  {
228  return 0;
229  }
230 
231  AVFrame pic_in;
232  AVPixelFormat fmt_in = FrameTypeToPixelFormat(frame->codec);
233 
234  AVPictureFill(&pic_in, frame, fmt_in);
235  av_image_fill_arrays(pic->data, pic->linesize, sbuf, fmt, frame->width, frame->height, IMAGE_ALIGN);
236  return Copy(pic, fmt, &pic_in, fmt_in, frame->width, frame->height);
237 }
238 
239 int MythAVCopy::Copy(VideoFrame *frame, const AVFrame *pic, AVPixelFormat fmt)
240 {
241  if (fmt == AV_PIX_FMT_NV12 || AV_PIX_FMT_YUV420P)
242  {
243  VideoFrame framein;
244  FillFrame(&framein, pic, frame->width, frame->width, frame->height, fmt);
245  return Copy(frame, &framein);
246  }
247 
248  AVFrame frame_out;
249  AVPixelFormat fmt_out = FrameTypeToPixelFormat(frame->codec);
250 
251  AVPictureFill(&frame_out, frame, fmt_out);
252  return Copy(&frame_out, fmt_out, pic, fmt, frame->width, frame->height);
253 }
254 
256  int width, int height, float ar)
257  : m_filter_graph(nullptr)
258  , m_buffersink_ctx(nullptr)
259  , m_buffersrc_ctx(nullptr)
260  , m_pixfmt(pixfmt)
261  , m_width(width)
262  , m_height(height)
263  , m_ar(ar)
264  , m_errored(false)
265 {
266  if (Flush() < 0)
267  {
268  m_errored = true;
269  }
270 }
271 
273 {
274  if (m_errored)
275  {
276  return -1;
277  }
278  if (src)
279  {
280  memcpy(m_filter_frame->data, src->data, sizeof(src->data));
281  memcpy(m_filter_frame->linesize, src->linesize, sizeof(src->linesize));
282  m_filter_frame->width = m_width;
283  m_filter_frame->height = m_height;
284  m_filter_frame->format = m_pixfmt;
285  }
286  int res = av_buffersrc_add_frame(m_buffersrc_ctx, m_filter_frame);
287  if (res < 0)
288  {
289  return res;
290  }
291  res = av_buffersink_get_frame(m_buffersink_ctx, m_filter_frame);
292  if (res < 0)
293  {
294  return res;
295  }
296 
297  av_image_copy(dst->data, dst->linesize,
298  (const uint8_t **)((AVFrame*)m_filter_frame)->data,
299  (const int*)((AVFrame*)m_filter_frame)->linesize,
301 
302  av_frame_unref(m_filter_frame);
303 
304  return 0;
305 }
306 
308 {
309  if (m_errored)
310  {
311  return -1;
312  }
313  if (!m_filter_graph && Flush() < 0)
314  {
315  return -1;
316  }
317  int res = Deinterlace(dst, src);
318  if (res == AVERROR(EAGAIN))
319  {
320  res = Deinterlace(dst, nullptr);
321  // We have drained the filter, we need to recreate it on the next run.
322  avfilter_graph_free(&m_filter_graph);
323  }
324  return res;
325 }
326 
328 {
329  if (m_filter_graph)
330  {
331  avfilter_graph_free(&m_filter_graph);
332  }
333 
334  m_filter_graph = avfilter_graph_alloc();
335  if (!m_filter_graph)
336  {
337  return -1;
338  }
339 
340  AVFilterInOut *inputs = nullptr, *outputs = nullptr;
341  AVRational ar = av_d2q(m_ar, 100000);
342  QString args = QString("buffer=video_size=%1x%2:pix_fmt=%3:time_base=1/1:pixel_aspect=%4/%5[in];"
343  "[in]yadif[out];[out] buffersink")
344  .arg(m_width).arg(m_height).arg(m_pixfmt).arg(ar.num).arg(ar.den);
345  int res = avfilter_graph_parse2(m_filter_graph, args.toLatin1().data(), &inputs, &outputs);
346  while (true)
347  {
348  if (res < 0 || inputs || outputs)
349  {
350  break;
351  }
352  res = avfilter_graph_config(m_filter_graph, nullptr);
353  if (res < 0)
354  {
355  break;
356  }
357  if (!(m_buffersrc_ctx = avfilter_graph_get_filter(m_filter_graph, "Parsed_buffer_0")))
358  {
359  break;
360  }
361  if (!(m_buffersink_ctx = avfilter_graph_get_filter(m_filter_graph, "Parsed_buffersink_2")))
362  {
363  break;
364  }
365  return 0;
366  }
367  avfilter_inout_free(&inputs);
368  avfilter_inout_free(&outputs);
369  return -1;
370 }
371 
373 {
374  if (m_filter_graph)
375  {
376  avfilter_graph_free(&m_filter_graph);
377  }
378 }
379 
380 
382 
383 MythCodecMap::MythCodecMap() : mapLock(QMutex::Recursive)
384 {
385 }
386 
388 {
390 }
391 
392 AVCodecContext *MythCodecMap::getCodecContext(const AVStream *stream,
393  const AVCodec *pCodec, bool nullCodec)
394 {
395  QMutexLocker lock(&mapLock);
396  AVCodecContext *avctx = streamMap.value(stream, nullptr);
397  if (!avctx)
398  {
399  if (stream == nullptr || stream->codecpar == nullptr)
400  return nullptr;
401  if (nullCodec)
402  pCodec = nullptr;
403  else
404  {
405  if (!pCodec)
406  pCodec = avcodec_find_decoder(stream->codecpar->codec_id);
407  if (!pCodec)
408  {
409  LOG(VB_GENERAL, LOG_WARNING,
410  QString("avcodec_find_decoder fail for %1").arg(stream->codecpar->codec_id));
411  return nullptr;
412  }
413  }
414  avctx = avcodec_alloc_context3(pCodec);
415  if (avcodec_parameters_to_context(avctx, stream->codecpar) < 0)
416  avcodec_free_context(&avctx);
417  if (avctx)
418  {
419  avctx->pkt_timebase = stream->time_base;
420  streamMap.insert(stream, avctx);
421  }
422  }
423  return avctx;
424 }
425 
426 AVCodecContext *MythCodecMap::hasCodecContext(const AVStream *stream)
427 {
428  return streamMap.value(stream, nullptr);
429 }
430 
431 void MythCodecMap::freeCodecContext(const AVStream *stream)
432 {
433  QMutexLocker lock(&mapLock);
434  AVCodecContext *avctx = streamMap.take(stream);
435  if (avctx)
436  avcodec_free_context(&avctx);
437 }
438 
440 {
441  QMutexLocker lock(&mapLock);
442  QMap<const AVStream*, AVCodecContext*>::iterator i = streamMap.begin();
443  while (i != streamMap.end()) {
444  const AVStream *stream = i.key();
445  ++i;
446  freeCodecContext(stream);
447  }
448 }
int pitches[3]
Y, U, & V pitches.
Definition: mythframe.h:63
QMutex mapLock
Definition: mythavutil.h:101
int Copy(VideoFrame *dst, const VideoFrame *src)
Definition: mythavutil.cpp:200
MythAVCopyPrivate(const MythAVCopyPrivate &)=delete
virtual ~MythAVCopy()
Definition: mythavutil.cpp:127
int SizeData(int _width, int _height, AVPixelFormat _fmt)
Definition: mythavutil.cpp:104
struct AVFrame AVFrame
void freeCodecContext(const AVStream *)
Definition: mythavutil.cpp:431
AVPixelFormat FrameTypeToPixelFormat(VideoFrameType type)
Convert VideoFrameType into FFmpeg's PixelFormat equivalent and vice-versa.
Definition: mythavutil.cpp:25
VideoFrameType PixelFormatToFrameType(AVPixelFormat fmt)
Definition: mythavutil.cpp:46
void FillFrame(VideoFrame *frame, const AVFrame *pic, int pitch, int width, int height, AVPixelFormat pix_fmt)
Definition: mythavutil.cpp:132
AVPixelFormat format
Definition: mythavutil.cpp:120
enum FrameType_ VideoFrameType
MythAVFrame m_filter_frame
Definition: mythavutil.h:186
int offsets[3]
Y, U, & V offsets.
Definition: mythframe.h:64
AVFilterContext * m_buffersrc_ctx
Definition: mythavutil.h:188
MythAVCopyPrivate & operator=(const MythAVCopyPrivate &)=delete
int AVPictureFill(AVFrame *pic, const VideoFrame *frame, AVPixelFormat fmt)
AVPictureFill Initialise AVFrame pic with content from VideoFrame frame.
Definition: mythavutil.cpp:65
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
AVFilterContext * m_buffersink_ctx
Definition: mythavutil.h:187
MythCodecMap * gCodecMap
This global variable contains the MythCodecMap instance for the app.
Definition: mythavutil.cpp:381
void copy(VideoFrame *dst, const VideoFrame *src)
Definition: mythframe.cpp:594
MythAVCopyPrivate(bool uswc)
Definition: mythavutil.cpp:89
int height
Definition: mythframe.h:42
static const uint16_t * d
int DeinterlaceSingle(AVFrame *dst, const AVFrame *src)
Definition: mythavutil.cpp:307
MythAVCopyPrivate * d
Definition: mythavutil.h:148
AVCodecContext * getCodecContext(const AVStream *, const AVCodec *pCodec=nullptr, bool nullCodec=false)
Definition: mythavutil.cpp:392
void * av_malloc(unsigned int size)
int Deinterlace(AVFrame *dst, const AVFrame *src)
Definition: mythavutil.cpp:272
AVFilterGraph * m_filter_graph
Definition: mythavutil.h:185
MythPictureDeinterlacer(AVPixelFormat pixfmt, int width, int height, float ar=1.0F)
Definition: mythavutil.cpp:255
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
AVPixelFormat m_pixfmt
Definition: mythavutil.h:189
static void init(VideoFrame *vf, VideoFrameType _codec, unsigned char *_buf, int _width, int _height, int _size, const int *p=nullptr, const int *o=nullptr, float _aspect=-1.0F, double _rate=-1.0F, int _aligned=64)
Definition: mythframe.h:115
void freeAllCodecContexts()
Definition: mythavutil.cpp:439
MythAVCopy(bool USWC=true)
Definition: mythavutil.cpp:123
MythCodecMap Utility class that keeps pointers to an AVStream and its AVCodecContext.
Definition: mythavutil.h:88
static uint buffersize(VideoFrameType type, int width, int height, int _aligned=64)
Definition: mythframe.h:297
SwsContext * swsctx
Definition: mythavutil.cpp:117
unsigned char * buf
Definition: mythframe.h:39
QMap< const AVStream *, AVCodecContext * > streamMap
Definition: mythavutil.h:100
endian dependent format, ARGB or BGRA
Definition: mythframe.h:24
AVCodecContext * hasCodecContext(const AVStream *)
Definition: mythavutil.cpp:426
MythUSWCCopy * copyctx
Definition: mythavutil.cpp:118
VideoFrameType codec
Definition: mythframe.h:38