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 public:
85  explicit MythAVCopyPrivate(bool uswc)
86  : swsctx(nullptr), copyctx(new MythUSWCCopy(4096, !uswc)),
87  width(0), height(0), size(0), format(AV_PIX_FMT_NONE)
88  {
89  }
90 
92  {
93  if (swsctx)
94  {
95  sws_freeContext(swsctx);
96  }
97  delete copyctx;
98  }
99 
100  int SizeData(int _width, int _height, AVPixelFormat _fmt)
101  {
102  if (_width == width && _height == height && _fmt == format)
103  {
104  return size;
105  }
106  size = av_image_get_buffer_size(_fmt, _width, _height, IMAGE_ALIGN);
107  width = _width;
108  height = _height;
109  format = _fmt;
110  return size;
111  }
112 
113  SwsContext *swsctx;
116  AVPixelFormat format;
117 };
118 
120 {
121 }
122 
124 {
125  delete d;
126 }
127 
128 void MythAVCopy::FillFrame(VideoFrame *frame, const AVFrame *pic, int pitch,
129  int width, int height, AVPixelFormat pix_fmt)
130 {
131  int size = av_image_get_buffer_size(pix_fmt, width, height, IMAGE_ALIGN);
132 
133  if (pix_fmt == AV_PIX_FMT_YUV420P)
134  {
135  int chroma_pitch = pitch >> 1;
136  int chroma_height = height >> 1;
137  int offsets[3] =
138  { 0,
139  pitch * height,
140  pitch * height + chroma_pitch * chroma_height };
141  int pitches[3] = { pitch, chroma_pitch, chroma_pitch };
142 
143  init(frame, FMT_YV12, pic->data[0], width, height, size, pitches, offsets);
144  }
145  else if (pix_fmt == AV_PIX_FMT_NV12)
146  {
147  int offsets[3] = { 0, pitch * height, 0 };
148  int pitches[3] = { pitch, pitch, 0 };
149 
150  init(frame, FMT_NV12, pic->data[0], width, height, size, pitches, offsets);
151  }
152 }
153 
154 int MythAVCopy::Copy(AVFrame *dst, AVPixelFormat dst_pix_fmt,
155  const AVFrame *src, AVPixelFormat pix_fmt,
156  int width, int height)
157 {
158  if ((pix_fmt == AV_PIX_FMT_YUV420P || pix_fmt == AV_PIX_FMT_NV12) &&
159  (dst_pix_fmt == AV_PIX_FMT_YUV420P || dst_pix_fmt == AV_PIX_FMT_NV12))
160  {
161  VideoFrame framein, frameout;
162 
163  FillFrame(&framein, src, width, width, height, pix_fmt);
164  FillFrame(&frameout, dst, width, width, height, dst_pix_fmt);
165 
166  d->copyctx->copy(&frameout, &framein);
167  return frameout.size;
168  }
169 
170  int new_width = width;
171 #if ARCH_ARM
172  // The ARM build of FFMPEG has a bug that if sws_scale is
173  // called with source and dest sizes the same, and
174  // formats as shown below, it causes a bus error and the
175  // application core dumps. To avoid this I make a -1
176  // difference in the new width, causing it to bypass
177  // the code optimization which is failing.
178  if (pix_fmt == AV_PIX_FMT_YUV420P
179  && dst_pix_fmt == AV_PIX_FMT_BGRA)
180  new_width = width - 1;
181 #endif
182  d->swsctx = sws_getCachedContext(d->swsctx, width, height, pix_fmt,
183  new_width, height, dst_pix_fmt,
184  SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
185  if (d->swsctx == nullptr)
186  {
187  return -1;
188  }
189 
190  sws_scale(d->swsctx, src->data, src->linesize,
191  0, height, dst->data, dst->linesize);
192 
193  return d->SizeData(width, height, dst_pix_fmt);
194 }
195 
197 {
198  if ((src->codec == FMT_YV12 || src->codec == FMT_NV12) &&
199  (dst->codec == FMT_YV12 || dst->codec == FMT_NV12))
200  {
201  d->copyctx->copy(dst, src);
202  return dst->size;
203  }
204 
205  AVFrame srcpic, dstpic;
206 
207  AVPictureFill(&srcpic, src);
208  AVPictureFill(&dstpic, dst);
209 
210  return Copy(&dstpic, FrameTypeToPixelFormat(dst->codec),
211  &srcpic, FrameTypeToPixelFormat(src->codec),
212  src->width, src->height);
213 }
214 
215 int MythAVCopy::Copy(AVFrame *pic, const VideoFrame *frame,
216  unsigned char *buffer, AVPixelFormat fmt)
217 {
219  int size = buffersize(type, frame->width, frame->height, 0) + 16;
220  unsigned char *sbuf = buffer ? buffer : (unsigned char*)av_malloc(size);
221 
222  if (!sbuf)
223  {
224  return 0;
225  }
226 
227  AVFrame pic_in;
228  AVPixelFormat fmt_in = FrameTypeToPixelFormat(frame->codec);
229 
230  AVPictureFill(&pic_in, frame, fmt_in);
231  av_image_fill_arrays(pic->data, pic->linesize, sbuf, fmt, frame->width, frame->height, IMAGE_ALIGN);
232  return Copy(pic, fmt, &pic_in, fmt_in, frame->width, frame->height);
233 }
234 
235 int MythAVCopy::Copy(VideoFrame *frame, const AVFrame *pic, AVPixelFormat fmt)
236 {
237  if (fmt == AV_PIX_FMT_NV12 || AV_PIX_FMT_YUV420P)
238  {
239  VideoFrame framein;
240  FillFrame(&framein, pic, frame->width, frame->width, frame->height, fmt);
241  return Copy(frame, &framein);
242  }
243 
244  AVFrame frame_out;
245  AVPixelFormat fmt_out = FrameTypeToPixelFormat(frame->codec);
246 
247  AVPictureFill(&frame_out, frame, fmt_out);
248  return Copy(&frame_out, fmt_out, pic, fmt, frame->width, frame->height);
249 }
250 
252  int width, int height, float ar)
253  : m_filter_graph(nullptr)
254  , m_buffersink_ctx(nullptr)
255  , m_buffersrc_ctx(nullptr)
256  , m_pixfmt(pixfmt)
257  , m_width(width)
258  , m_height(height)
259  , m_ar(ar)
260  , m_errored(false)
261 {
262  if (Flush() < 0)
263  {
264  m_errored = true;
265  }
266 }
267 
269 {
270  if (m_errored)
271  {
272  return -1;
273  }
274  if (src)
275  {
276  memcpy(m_filter_frame->data, src->data, sizeof(src->data));
277  memcpy(m_filter_frame->linesize, src->linesize, sizeof(src->linesize));
278  m_filter_frame->width = m_width;
279  m_filter_frame->height = m_height;
280  m_filter_frame->format = m_pixfmt;
281  }
282  int res = av_buffersrc_add_frame(m_buffersrc_ctx, m_filter_frame);
283  if (res < 0)
284  {
285  return res;
286  }
287  res = av_buffersink_get_frame(m_buffersink_ctx, m_filter_frame);
288  if (res < 0)
289  {
290  return res;
291  }
292 
293  av_image_copy(dst->data, dst->linesize,
294  (const uint8_t **)((AVFrame*)m_filter_frame)->data,
295  (const int*)((AVFrame*)m_filter_frame)->linesize,
297 
298  av_frame_unref(m_filter_frame);
299 
300  return 0;
301 }
302 
304 {
305  if (m_errored)
306  {
307  return -1;
308  }
309  if (!m_filter_graph && Flush() < 0)
310  {
311  return -1;
312  }
313  int res = Deinterlace(dst, src);
314  if (res == AVERROR(EAGAIN))
315  {
316  res = Deinterlace(dst, nullptr);
317  // We have drained the filter, we need to recreate it on the next run.
318  avfilter_graph_free(&m_filter_graph);
319  }
320  return res;
321 }
322 
324 {
325  if (m_filter_graph)
326  {
327  avfilter_graph_free(&m_filter_graph);
328  }
329 
330  m_filter_graph = avfilter_graph_alloc();
331  if (!m_filter_graph)
332  {
333  return -1;
334  }
335 
336  AVFilterInOut *inputs = nullptr, *outputs = nullptr;
337  AVRational ar = av_d2q(m_ar, 100000);
338  QString args = QString("buffer=video_size=%1x%2:pix_fmt=%3:time_base=1/1:pixel_aspect=%4/%5[in];"
339  "[in]yadif[out];[out] buffersink")
340  .arg(m_width).arg(m_height).arg(m_pixfmt).arg(ar.num).arg(ar.den);
341  int res = avfilter_graph_parse2(m_filter_graph, args.toLatin1().data(), &inputs, &outputs);
342  while (true)
343  {
344  if (res < 0 || inputs || outputs)
345  {
346  break;
347  }
348  res = avfilter_graph_config(m_filter_graph, nullptr);
349  if (res < 0)
350  {
351  break;
352  }
353  if (!(m_buffersrc_ctx = avfilter_graph_get_filter(m_filter_graph, "Parsed_buffer_0")))
354  {
355  break;
356  }
357  if (!(m_buffersink_ctx = avfilter_graph_get_filter(m_filter_graph, "Parsed_buffersink_2")))
358  {
359  break;
360  }
361  return 0;
362  }
363  avfilter_inout_free(&inputs);
364  avfilter_inout_free(&outputs);
365  return -1;
366 }
367 
369 {
370  if (m_filter_graph)
371  {
372  avfilter_graph_free(&m_filter_graph);
373  }
374 }
375 
376 
378 
379 MythCodecMap::MythCodecMap() : mapLock(QMutex::Recursive)
380 {
381 }
382 
384 {
386 }
387 
388 AVCodecContext *MythCodecMap::getCodecContext(const AVStream *stream,
389  const AVCodec *pCodec, bool nullCodec)
390 {
391  QMutexLocker lock(&mapLock);
392  AVCodecContext *avctx = streamMap.value(stream, nullptr);
393  if (!avctx)
394  {
395  if (stream == nullptr || stream->codecpar == nullptr)
396  return nullptr;
397  if (nullCodec)
398  pCodec = nullptr;
399  else
400  {
401  if (!pCodec)
402  pCodec = avcodec_find_decoder(stream->codecpar->codec_id);
403  if (!pCodec)
404  {
405  LOG(VB_GENERAL, LOG_WARNING,
406  QString("avcodec_find_decoder fail for %1").arg(stream->codecpar->codec_id));
407  return nullptr;
408  }
409  }
410  avctx = avcodec_alloc_context3(pCodec);
411  if (avcodec_parameters_to_context(avctx, stream->codecpar) < 0)
412  avcodec_free_context(&avctx);
413  if (avctx)
414  {
415  avctx->pkt_timebase = stream->time_base;
416  streamMap.insert(stream, avctx);
417  }
418  }
419  return avctx;
420 }
421 
422 AVCodecContext *MythCodecMap::hasCodecContext(const AVStream *stream)
423 {
424  return streamMap.value(stream, nullptr);
425 }
426 
427 void MythCodecMap::freeCodecContext(const AVStream *stream)
428 {
429  QMutexLocker lock(&mapLock);
430  AVCodecContext *avctx = streamMap.take(stream);
431  if (avctx)
432  avcodec_free_context(&avctx);
433 }
434 
436 {
437  QMutexLocker lock(&mapLock);
438  QMap<const AVStream*, AVCodecContext*>::iterator i = streamMap.begin();
439  while (i != streamMap.end()) {
440  const AVStream *stream = i.key();
441  ++i;
442  freeCodecContext(stream);
443  }
444 }
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:196
virtual ~MythAVCopy()
Definition: mythavutil.cpp:123
int SizeData(int _width, int _height, AVPixelFormat _fmt)
Definition: mythavutil.cpp:100
struct AVFrame AVFrame
void freeCodecContext(const AVStream *)
Definition: mythavutil.cpp:427
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:128
AVPixelFormat format
Definition: mythavutil.cpp:116
enum FrameType_ VideoFrameType
MythAVFrame m_filter_frame
Definition: mythavutil.h:184
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:109
#define IMAGE_ALIGN
Definition: mythconfig.h:19
int offsets[3]
Y, U, & V offsets.
Definition: mythframe.h:64
AVFilterContext * m_buffersrc_ctx
Definition: mythavutil.h:186
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:185
MythCodecMap * gCodecMap
This global variable contains the MythCodecMap instance for the app.
Definition: mythavutil.cpp:377
void copy(VideoFrame *dst, const VideoFrame *src)
Definition: mythframe.cpp:614
MythAVCopyPrivate(bool uswc)
Definition: mythavutil.cpp:85
int height
Definition: mythframe.h:42
static const uint16_t * d
int DeinterlaceSingle(AVFrame *dst, const AVFrame *src)
Definition: mythavutil.cpp:303
MythAVCopyPrivate * d
Definition: mythavutil.h:146
MythPictureDeinterlacer(AVPixelFormat pixfmt, int width, int height, float ar=1.0f)
Definition: mythavutil.cpp:251
AVCodecContext * getCodecContext(const AVStream *, const AVCodec *pCodec=nullptr, bool nullCodec=false)
Definition: mythavutil.cpp:388
void * av_malloc(unsigned int size)
int Deinterlace(AVFrame *dst, const AVFrame *src)
Definition: mythavutil.cpp:268
AVFilterGraph * m_filter_graph
Definition: mythavutil.h:183
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
AVPixelFormat m_pixfmt
Definition: mythavutil.h:187
void freeAllCodecContexts()
Definition: mythavutil.cpp:435
MythAVCopy(bool USWC=true)
Definition: mythavutil.cpp:119
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:291
SwsContext * swsctx
Definition: mythavutil.cpp:113
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:422
MythUSWCCopy * copyctx
Definition: mythavutil.cpp:114
VideoFrameType codec
Definition: mythframe.h:38