MythTV  master
privatedecoder_vda.cpp
Go to the documentation of this file.
1 // Based upon CDVDVideoCodecVDA from the xbmc project, originally written by
2 // Scott Davilla (davilla@xbmc.org) and released under the GPLv2
3 
4 #include "mythlogging.h"
5 #define LOC QString("VDADec: ")
6 #define ERR QString("VDADec error: ")
7 
8 #include "mythframe.h"
9 #include "mythavutil.h"
10 #include "util-osx-cocoa.h"
11 #include "privatedecoder_vda.h"
12 #include "util-osx.h"
13 
14 #include "H264Parser.h"
15 
16 #include <CoreServices/CoreServices.h>
17 
18 extern "C" {
19 #include "libavformat/avformat.h"
20 #include "libavutil/imgutils.h"
21 }
22 VDALibrary *gVDALib = nullptr;
23 
25 {
26  static QMutex vda_create_lock;
27  QMutexLocker locker(&vda_create_lock);
28  if (gVDALib)
29  return gVDALib;
30  gVDALib = new VDALibrary();
31  if (gVDALib)
32  {
33  if (gVDALib->IsValid())
34  return gVDALib;
35  delete gVDALib;
36  }
37  gVDALib = nullptr;
38  return gVDALib;
39 }
40 
42  : decoderCreate(nullptr), decoderDecode(nullptr), decoderFlush(nullptr),
43  decoderDestroy(nullptr), decoderConfigWidth(nullptr),
44  decoderConfigHeight(nullptr), decoderConfigSourceFmt(nullptr),
45  decoderConfigAVCCData(nullptr), m_lib(nullptr), m_valid(false)
46 {
47  m_lib = new QLibrary(VDA_DECODER_PATH);
48  if (m_lib)
49  {
51  m_lib->resolve("VDADecoderCreate");
53  m_lib->resolve("VDADecoderDecode");
55  m_lib->resolve("VDADecoderFlush");
57  m_lib->resolve("VDADecoderDestroy");
58  decoderConfigWidth = (CFStringRef*)
59  m_lib->resolve("kVDADecoderConfiguration_Width");
60  decoderConfigHeight = (CFStringRef*)
61  m_lib->resolve("kVDADecoderConfiguration_Height");
62  decoderConfigSourceFmt = (CFStringRef*)
63  m_lib->resolve("kVDADecoderConfiguration_SourceFormat");
64  decoderConfigAVCCData = (CFStringRef*)
65  m_lib->resolve("kVDADecoderConfiguration_avcCData");
66  }
67 
70  decoderConfigAVCCData && m_lib->isLoaded())
71  {
72  m_valid = true;
73  LOG(VB_PLAYBACK, LOG_INFO, LOC +
74  "Loaded VideoDecodeAcceleration library.");
75  }
76  else
77  LOG(VB_GENERAL, LOG_ERR, LOC +
78  "Failed to load VideoDecodeAcceleration library.");
79 }
80 
81 #define INIT_ST OSStatus vda_st; bool ok = true
82 #define CHECK_ST \
83  ok &= (vda_st == kVDADecoderNoErr); \
84  if (!ok) \
85  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error at %1:%2 (#%3, %4)") \
86  .arg(__FILE__).arg( __LINE__).arg(vda_st) \
87  .arg(vda_err_to_string(vda_st)))
88 
89 QString vda_err_to_string(OSStatus err)
90 {
91  switch (err)
92  {
94  return "Hardware not supported";
96  return "Format not supported";
98  return "Configuration error";
100  return "Decoder failed";
101  case paramErr:
102  return "Parameter error";
103  }
104  return "Unknown error";
105 }
106 
108 // TODO: refactor this so as not to need these ffmpeg routines.
109 // These are not exposed in ffmpeg's API so we dupe them here.
110 // AVC helper functions for muxers,
111 // * Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@smartjog.com>
112 // This is part of FFmpeg
113 // * License as published by the Free Software Foundation; either
114 // * version 2.1 of the License, or (at your option) any later version.
115 #define VDA_RB16(x) \
116  ((((const uint8_t*)(x))[0] << 8) | \
117  ((const uint8_t*)(x)) [1])
118 
119 #define VDA_RB24(x) \
120  ((((const uint8_t*)(x))[0] << 16) | \
121  (((const uint8_t*)(x))[1] << 8) | \
122  ((const uint8_t*)(x))[2])
123 
124 #define VDA_RB32(x) \
125  ((((const uint8_t*)(x))[0] << 24) | \
126  (((const uint8_t*)(x))[1] << 16) | \
127  (((const uint8_t*)(x))[2] << 8) | \
128  ((const uint8_t*)(x))[3])
129 
130 #define VDA_WB32(p, d) { \
131  ((uint8_t*)(p))[3] = (d); \
132  ((uint8_t*)(p))[2] = (d) >> 8; \
133  ((uint8_t*)(p))[1] = (d) >> 16; \
134  ((uint8_t*)(p))[0] = (d) >> 24; }
135 
136 static const uint8_t *avc_find_startcode_internal(const uint8_t *p, const uint8_t *end)
137 {
138  const uint8_t *a = p + 4 - ((intptr_t)p & 3);
139 
140  for (end -= 3; p < a && p < end; p++)
141  {
142  if (p[0] == 0 && p[1] == 0 && p[2] == 1)
143  return p;
144  }
145 
146  for (end -= 3; p < end; p += 4)
147  {
148  uint32_t x = *(const uint32_t*)p;
149  if ((x - 0x01010101) & (~x) & 0x80808080) // generic
150  {
151  if (p[1] == 0)
152  {
153  if (p[0] == 0 && p[2] == 1)
154  return p;
155  if (p[2] == 0 && p[3] == 1)
156  return p+1;
157  }
158  if (p[3] == 0)
159  {
160  if (p[2] == 0 && p[4] == 1)
161  return p+2;
162  if (p[4] == 0 && p[5] == 1)
163  return p+3;
164  }
165  }
166  }
167 
168  for (end += 3; p < end; p++)
169  {
170  if (p[0] == 0 && p[1] == 0 && p[2] == 1)
171  return p;
172  }
173 
174  return end + 3;
175 }
176 
177 const uint8_t *avc_find_startcode(const uint8_t *p, const uint8_t *end)
178 {
179  const uint8_t *out= avc_find_startcode_internal(p, end);
180  if (p<out && out<end && !out[-1])
181  out--;
182  return out;
183 }
184 
185 int avc_parse_nal_units(AVIOContext *pb, const uint8_t *buf_in, int size)
186 {
187  const uint8_t *p = buf_in;
188  const uint8_t *end = p + size;
189  const uint8_t *nal_start, *nal_end;
190 
191  size = 0;
192  nal_start = avc_find_startcode(p, end);
193  while (nal_start < end)
194  {
195  while (!*(nal_start++));
196  nal_end = avc_find_startcode(nal_start, end);
197  avio_wb32(pb, nal_end - nal_start);
198  avio_write(pb, nal_start, nal_end - nal_start);
199  size += 4 + nal_end - nal_start;
200  nal_start = nal_end;
201  }
202  return size;
203 }
204 
205 int avc_parse_nal_units_buf(const uint8_t *buf_in,
206  uint8_t **buf, int *size)
207 {
208  AVIOContext *pb;
209  int ret = avio_open_dyn_buf(&pb);
210  if (ret < 0)
211  return ret;
212 
213  avc_parse_nal_units(pb, buf_in, *size);
214 
215  av_freep(buf);
216  *size = avio_close_dyn_buf(pb, buf);
217  return 0;
218 }
219 
220 int isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
221 {
222  // extradata from bytestream h264, convert to avcC atom data for bitstream
223  if (len > 6)
224  {
225  /* check for h264 start code */
226  if (VDA_RB32(data) == 0x00000001 || VDA_RB24(data) == 0x000001)
227  {
228  uint8_t *buf=nullptr, *end, *start;
229  uint32_t sps_size=0, pps_size=0;
230  uint8_t *sps=nullptr, *pps=nullptr;
231 
232  int ret = avc_parse_nal_units_buf(data, &buf, &len);
233  if (ret < 0)
234  return ret;
235  start = buf;
236  end = buf + len;
237 
238  /* look for sps and pps */
239  while (buf < end)
240  {
241  unsigned int size;
242  uint8_t nal_type;
243  size = VDA_RB32(buf);
244  nal_type = buf[4] & 0x1f;
245  if (nal_type == 7) /* SPS */
246  {
247  sps = buf + 4;
248  sps_size = size;
249 
250  //parse_sps(sps+1, sps_size-1);
251  }
252  else if (nal_type == 8) /* PPS */
253  {
254  pps = buf + 4;
255  pps_size = size;
256  }
257  buf += size + 4;
258  }
259  if (!sps)
260  {
261  LOG(VB_GENERAL, LOG_ERR, LOC + "Invalid data (sps)");
262  return -1;
263  }
264 
265  avio_w8(pb, 1); /* version */
266  avio_w8(pb, sps[1]); /* profile */
267  avio_w8(pb, sps[2]); /* profile compat */
268  avio_w8(pb, sps[3]); /* level */
269  avio_w8(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */
270  avio_w8(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */
271 
272  avio_wb16(pb, sps_size);
273  avio_write(pb, sps, sps_size);
274  if (pps)
275  {
276  avio_w8(pb, 1); /* number of pps */
277  avio_wb16(pb, pps_size);
278  avio_write(pb, pps, pps_size);
279  }
280  av_free(start);
281  }
282  else
283  {
284  avio_write(pb, data, len);
285  }
286  }
287  return 0;
288 }
289 
291 {
292  opts.decoders->append("vda");
293  (*opts.equiv_decoders)["vda"].append("nuppel");
294  (*opts.equiv_decoders)["vda"].append("ffmpeg");
295  (*opts.equiv_decoders)["vda"].append("dummy");
296 }
297 
299  : PrivateDecoder(), m_lib(nullptr), m_decoder(nullptr), m_size(QSize()),
300  m_frame_lock(QMutex::Recursive), m_frames_decoded(0), m_annexb(false),
301  m_slice_count(0), m_convert_3byteTo4byteNALSize(false), m_max_ref_frames(0)
302 {
303 }
304 
306 {
307  Reset();
308  if (m_decoder)
309  {
310  INIT_ST;
312  CHECK_ST;
313  }
314  m_decoder = nullptr;
315 }
316 
317 bool PrivateDecoderVDA::Init(const QString &decoder,
318  PlayerFlags flags,
319  AVCodecContext *avctx)
320 {
321  if ((decoder != "vda") || !avctx || (avctx->codec_id != AV_CODEC_ID_H264) ||
322  !(flags & kDecodeAllowEXT))
323  return false;
324 
326  if (!m_lib)
327  return false;
328 
329  uint8_t *extradata = avctx->extradata;
330  int extrasize = avctx->extradata_size;
331  if (!extradata || extrasize < 7)
332  return false;
333 
334  CFDataRef avc_cdata = nullptr;
335  if (extradata[0] != 1)
336  {
337  if (extradata[0] == 0 && extradata[1] == 0 && extradata[2] == 0 &&
338  extradata[3] == 1)
339  {
340  // video content is from x264 or from bytestream h264 (AnnexB format)
341  // NAL reformating to bitstream format needed
342  AVIOContext *pb;
343  if (avio_open_dyn_buf(&pb) < 0)
344  {
345  return false;
346  }
347 
348  m_annexb = true;
349  isom_write_avcc(pb, extradata, extrasize);
350  // unhook from ffmpeg's extradata
351  extradata = nullptr;
352  // extract the avcC atom data into extradata then write it into avcCData for VDADecoder
353  extrasize = avio_close_dyn_buf(pb, &extradata);
354  // CFDataCreate makes a copy of extradata contents
355  avc_cdata = CFDataCreate(kCFAllocatorDefault,
356  (const uint8_t*)extradata, extrasize);
357  // done with the converted extradata, we MUST free using av_free
358  av_free(extradata);
359  }
360  else
361  {
362  LOG(VB_GENERAL, LOG_ERR, LOC + "Invalid avcC atom data");
363  return false;
364  }
365  }
366  else
367  {
368  if (extradata[4] == 0xFE)
369  {
370  // video content is from so silly encoder that think 3 byte NAL sizes
371  // are valid, setup to convert 3 byte NAL sizes to 4 byte.
372  extradata[4] = 0xFF;
374  }
375  // CFDataCreate makes a copy of extradata contents
376  avc_cdata = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)extradata,
377  extrasize);
378  }
379 
380  OSType format = 'avc1';
381 
382  // check the avcC atom's sps for number of reference frames and
383  // bail if interlaced, VDA does not handle interlaced h264.
384  uint32_t avcc_len = CFDataGetLength(avc_cdata);
385  if (avcc_len < 8)
386  {
387  // avcc atoms with length less than 8 are borked.
388  CFRelease(avc_cdata);
389  return false;
390  }
391  bool interlaced = false;
392  uint8_t *spc = (uint8_t*)CFDataGetBytePtr(avc_cdata) + 6;
393  uint32_t sps_size = VDA_RB16(spc);
394  if (sps_size)
395  {
396  H264Parser *h264_parser = new H264Parser();
397  h264_parser->parse_SPS(spc+3, sps_size-1,
398  interlaced, m_max_ref_frames);
399  delete h264_parser;
400  }
401  else
402  {
403  m_max_ref_frames = avctx->refs;
404  }
405 
406  bool isMountainLion = false;
407  int32_t majorVersion, minorVersion;
408 
409  GetOSXVersion(&majorVersion, &minorVersion);
410 
411  if (majorVersion >= 10 && minorVersion >= 8)
412  {
413  isMountainLion = true;
414  }
415 
416  if (!isMountainLion && interlaced)
417  {
418  LOG(VB_GENERAL, LOG_ERR, LOC + "Possible interlaced content. Aborting");
419  CFRelease(avc_cdata);
420  return false;
421  }
422  if (m_max_ref_frames == 0)
423  {
424  m_max_ref_frames = 2;
425  }
426 
427  if (avctx->profile == FF_PROFILE_H264_MAIN && avctx->level == 32 &&
428  m_max_ref_frames > 4)
429  {
430  // Main@L3.2, VDA cannot handle greater than 4 reference frames
431  LOG(VB_GENERAL, LOG_ERR,
432  LOC + "Main@L3.2 detected, VDA cannot decode.");
433  CFRelease(avc_cdata);
434  return false;
435  }
436 
437  int32_t width = avctx->coded_width;
438  int32_t height = avctx->coded_height;
439  m_size = QSize(width, height);
440  m_slice_count = avctx->slice_count;
441 
442  int mbs = ceil((double)width / 16.0F);
443  if (((mbs == 49) || (mbs == 54 ) || (mbs == 59 ) || (mbs == 64) ||
444  (mbs == 113) || (mbs == 118) || (mbs == 123) || (mbs == 128)))
445  {
446  LOG(VB_PLAYBACK, LOG_WARNING, LOC +
447  QString("Warning: VDA decoding may not be supported for this "
448  "video stream (width %1)").arg(width));
449  }
450 
451  CFMutableDictionaryRef destinationImageBufferAttributes =
452  CFDictionaryCreateMutable(kCFAllocatorDefault, 1,
453  &kCFTypeDictionaryKeyCallBacks,
454  &kCFTypeDictionaryValueCallBacks);
455  OSType cvPixelFormatType = kCVPixelFormatType_422YpCbCr8;
456  CFNumberRef pixelFormat = CFNumberCreate(kCFAllocatorDefault,
457  kCFNumberSInt32Type,
458  &cvPixelFormatType);
459  CFDictionarySetValue(destinationImageBufferAttributes,
460  kCVPixelBufferPixelFormatTypeKey,
461  pixelFormat);
462 
463  //CFDictionaryRef emptyDictionary =
464  // CFDictionaryCreate(kCFAllocatorDefault, nullptr, nullptr, 0,
465  // &kCFTypeDictionaryKeyCallBacks,
466  // &kCFTypeDictionaryValueCallBacks);
467  //CFDictionarySetValue(destinationImageBufferAttributes,
468  // kCVPixelBufferIOSurfacePropertiesKey,
469  // emptyDictionary);
470 
471  CFMutableDictionaryRef decoderConfig =
472  CFDictionaryCreateMutable(
473  kCFAllocatorDefault, 4,
474  &kCFTypeDictionaryKeyCallBacks,
475  &kCFTypeDictionaryValueCallBacks);
476  CFNumberRef avc_width = CFNumberCreate(kCFAllocatorDefault,
477  kCFNumberSInt32Type, &width);
478  CFNumberRef avc_height = CFNumberCreate(kCFAllocatorDefault,
479  kCFNumberSInt32Type, &height);
480  CFNumberRef avc_format = CFNumberCreate(kCFAllocatorDefault,
481  kCFNumberSInt32Type, &format);
482 
483  CFDictionarySetValue(decoderConfig, *m_lib->decoderConfigHeight, avc_height);
484  CFDictionarySetValue(decoderConfig, *m_lib->decoderConfigWidth, avc_width);
485  CFDictionarySetValue(decoderConfig, *m_lib->decoderConfigSourceFmt, avc_format);
486  CFDictionarySetValue(decoderConfig, *m_lib->decoderConfigAVCCData, avc_cdata);
487  CFRelease(avc_width);
488  CFRelease(avc_height);
489  CFRelease(avc_format);
490  CFRelease(avc_cdata);
491 
492  INIT_ST;
493  vda_st = m_lib->decoderCreate(decoderConfig, destinationImageBufferAttributes,
495  this, (VDADecoder*)&m_decoder);
496  CHECK_ST;
497  CFRelease(decoderConfig);
498  CFRelease(destinationImageBufferAttributes);
499  //CFRelease(emptyDictionary);
500  if (ok)
501  {
502  LOG(VB_PLAYBACK, LOG_INFO, LOC +
503  QString("Created VDA decoder: Size %1x%2 Ref Frames %3 "
504  "Slices %5 AnnexB %6")
505  .arg(width).arg(height).arg(m_max_ref_frames)
506  .arg(m_slice_count).arg(m_annexb ? "Yes" : "No"));
507  }
508  m_max_ref_frames = std::min(m_max_ref_frames, 5);
509  return ok;
510 }
511 
513 {
514  if (m_lib && m_decoder)
515  m_lib->decoderFlush((VDADecoder)m_decoder, 0 /*dont emit*/);
516 
517  m_frames_decoded = 0;
518  m_frame_lock.lock();
519  while (!m_decoded_frames.empty())
520  PopDecodedFrame();
521  m_frame_lock.unlock();
522  return true;
523 }
524 
526 {
527  QMutexLocker lock(&m_frame_lock);
528  if (m_decoded_frames.isEmpty())
529  return;
530  CVPixelBufferRelease(m_decoded_frames.last().buffer);
531  m_decoded_frames.removeLast();
532 }
533 
535 {
536  m_frame_lock.lock();
537  bool result = m_decoded_frames.size() > 0;
538  m_frame_lock.unlock();
539  return result;
540 }
541 
542 int PrivateDecoderVDA::GetFrame(AVStream *stream,
543  AVFrame *picture,
544  int *got_picture_ptr,
545  AVPacket *pkt)
546 {
547  if (!pkt)
548 
550  int result = -1;
551  if (!m_lib || !stream)
552  return result;
553 
554  AVCodecContext *avctx = gCodecMap->getCodecContext(stream);
555  if (!avctx)
556  return result;
557 
558  if (pkt)
559  {
560  CFDataRef avc_demux;
561  CFDictionaryRef params;
562  if (m_annexb)
563  {
564  // convert demuxer packet from bytestream (AnnexB) to bitstream
565  AVIOContext *pb;
566  int demuxer_bytes;
567  uint8_t *demuxer_content;
568 
569  if(avio_open_dyn_buf(&pb) < 0)
570  {
571  return result;
572  }
573  demuxer_bytes = avc_parse_nal_units(pb, pkt->data, pkt->size);
574  demuxer_bytes = avio_close_dyn_buf(pb, &demuxer_content);
575  avc_demux = CFDataCreate(kCFAllocatorDefault, demuxer_content, demuxer_bytes);
576  av_free(demuxer_content);
577  }
579  {
580  // convert demuxer packet from 3 byte NAL sizes to 4 byte
581  AVIOContext *pb;
582  if (avio_open_dyn_buf(&pb) < 0)
583  {
584  return result;
585  }
586 
587  uint8_t *end = pkt->data + pkt->size;
588  uint8_t *nal_start = pkt->data;
589  while (nal_start < end)
590  {
591  uint32_t nal_size = VDA_RB24(nal_start);
592  avio_wb32(pb, nal_size);
593  nal_start += 3;
594  avio_write(pb, nal_start, nal_size);
595  nal_start += nal_size;
596  }
597 
598  uint8_t *demuxer_content;
599  int demuxer_bytes = avio_close_dyn_buf(pb, &demuxer_content);
600  avc_demux = CFDataCreate(kCFAllocatorDefault, demuxer_content, demuxer_bytes);
601  av_free(demuxer_content);
602  }
603  else
604  {
605  avc_demux = CFDataCreate(kCFAllocatorDefault, pkt->data, pkt->size);
606  }
607 
608  CFStringRef keys[4] = { CFSTR("FRAME_PTS"),
609  CFSTR("FRAME_INTERLACED"), CFSTR("FRAME_TFF"),
610  CFSTR("FRAME_REPEAT") };
611  CFNumberRef values[5];
612  values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type,
613  &pkt->pts);
614  values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt8Type,
615  &picture->interlaced_frame);
616  values[2] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt8Type,
617  &picture->top_field_first);
618  values[3] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt8Type,
619  &picture->repeat_pict);
620  params = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&keys,
621  (const void **)&values, 4,
622  &kCFTypeDictionaryKeyCallBacks,
623  &kCFTypeDictionaryValueCallBacks);
624 
625  INIT_ST;
626  vda_st = m_lib->decoderDecode((VDADecoder)m_decoder, 0, avc_demux, params);
627  CHECK_ST;
628  if (vda_st == kVDADecoderNoErr)
629  result = pkt->size;
630  CFRelease(avc_demux);
631  CFRelease(params);
632  }
633 
634  if (m_decoded_frames.size() < m_max_ref_frames)
635  return result;
636 
637  *got_picture_ptr = 1;
638  m_frame_lock.lock();
639  VDAFrame vdaframe = m_decoded_frames.takeLast();
640  m_frame_lock.unlock();
641 
642  if (avctx->get_buffer2(avctx, picture, 0) < 0)
643  return -1;
644 
645  picture->reordered_opaque = vdaframe.pts;
646  picture->interlaced_frame = vdaframe.interlaced_frame;
647  picture->top_field_first = vdaframe.top_field_first;
648  picture->repeat_pict = vdaframe.repeat_pict;
649  VideoFrame *frame = (VideoFrame*)picture->opaque;
650 
651  AVPixelFormat in_fmt = AV_PIX_FMT_NONE;
652  if (vdaframe.format == 'BGRA')
653  in_fmt = AV_PIX_FMT_BGRA;
654  else if (vdaframe.format == '2vuy')
655  in_fmt = AV_PIX_FMT_UYVY422;
656 
657  if (frame->codec == FMT_YV12 && in_fmt != AV_PIX_FMT_NONE && frame->buf)
658  {
659  CVPixelBufferLockBaseAddress(vdaframe.buffer, 0);
660  uint8_t* base = (uint8_t*)CVPixelBufferGetBaseAddressOfPlane(vdaframe.buffer, 0);
661  AVFrame img_in;
662  av_image_fill_arrays(img_in.data, img_in.linesize,
663  base, in_fmt, frame->width, frame->height, IMAGE_ALIGN);
664  m_copyCtx.Copy(frame, &img_in, in_fmt);
665  CVPixelBufferUnlockBaseAddress(vdaframe.buffer, 0);
666  }
667  else
668  {
669  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to convert decoded frame.");
670  }
671 
672  CVPixelBufferRelease(vdaframe.buffer);
673  return result;
674 }
675 
676 void PrivateDecoderVDA::VDADecoderCallback(void *decompressionOutputRefCon,
677  CFDictionaryRef frameInfo,
678  OSStatus status,
679  uint32_t infoFlags,
680  CVImageBufferRef imageBuffer)
681 {
683  PrivateDecoderVDA *decoder = (PrivateDecoderVDA*)decompressionOutputRefCon;
684 
685  if (kVDADecodeInfo_FrameDropped & infoFlags)
686  {
687  LOG(VB_GENERAL, LOG_ERR, LOC + "Callback: Decoder dropped frame");
688  return;
689  }
690 
691  if (!imageBuffer)
692  {
693  LOG(VB_GENERAL, LOG_ERR, LOC +
694  "Callback: decoder returned empty buffer.");
695  return;
696  }
697 
698  INIT_ST;
699  vda_st = status;
700  CHECK_ST;
701 
702  OSType format_type = CVPixelBufferGetPixelFormatType(imageBuffer);
703  if ((format_type != '2vuy') && (format_type != 'BGRA'))
704  {
705  LOG(VB_GENERAL, LOG_ERR, LOC +
706  QString("Callback: image buffer format unknown (%1)")
707  .arg(format_type));
708  return;
709  }
710 
711  int64_t pts = AV_NOPTS_VALUE;
712  int8_t interlaced = 0;
713  int8_t topfirst = 0;
714  int8_t repeatpic = 0;
715  CFNumberRef ptsref = (CFNumberRef)CFDictionaryGetValue(frameInfo,
716  CFSTR("FRAME_PTS"));
717  CFNumberRef intref = (CFNumberRef)CFDictionaryGetValue(frameInfo,
718  CFSTR("FRAME_INTERLACED"));
719  CFNumberRef topref = (CFNumberRef)CFDictionaryGetValue(frameInfo,
720  CFSTR("FRAME_TFF"));
721  CFNumberRef repref = (CFNumberRef)CFDictionaryGetValue(frameInfo,
722  CFSTR("FRAME_REPEAT"));
723 
724  if (ptsref)
725  {
726  CFNumberGetValue(ptsref, kCFNumberSInt64Type, &pts);
727  CFRelease(ptsref);
728  }
729  if (intref)
730  {
731  CFNumberGetValue(intref, kCFNumberSInt8Type, &interlaced);
732  CFRelease(intref);
733  }
734  if (topref)
735  {
736  CFNumberGetValue(topref, kCFNumberSInt8Type, &topfirst);
737  CFRelease(topref);
738  }
739  if (repref)
740  {
741  CFNumberGetValue(repref, kCFNumberSInt8Type, &repeatpic);
742  CFRelease(repref);
743  }
744 
745  int64_t time = (pts != (int64_t)AV_NOPTS_VALUE) ? pts : 0;
746  {
747  QMutexLocker lock(&decoder->m_frame_lock);
748  bool found = false;
749  int i = 0;
750  for (; i < decoder->m_decoded_frames.size(); i++)
751  {
752  int64_t pts2 = decoder->m_decoded_frames[i].pts;
753  if (pts2 != (int64_t)AV_NOPTS_VALUE && time > pts2)
754  {
755  found = true;
756  break;
757  }
758  }
759 
760  VDAFrame frame(CVPixelBufferRetain(imageBuffer), format_type,
761  pts, interlaced, topfirst, repeatpic);
762  if (!found)
763  i = decoder->m_decoded_frames.size();
764  decoder->m_decoded_frames.insert(i, frame);
765  decoder->m_frames_decoded++;
766  }
767 }
int8_t interlaced_frame
CFStringRef * decoderConfigAVCCData
bool Init(const QString &decoder, PlayerFlags flags, AVCodecContext *avctx) override
static void VDADecoderCallback(void *decompressionOutputRefCon, CFDictionaryRef frameInfo, OSStatus status, uint32_t infoFlags, CVImageBufferRef imageBuffer)
PlayerFlags
Definition: mythplayer.h:88
int Copy(VideoFrame *dst, const VideoFrame *src)
Definition: mythavutil.cpp:200
#define VDA_DECODER_PATH
CVPixelBufferRef buffer
MythAVCopy m_copyCtx
struct AVFrame AVFrame
FourCharCode format
#define VDA_RB16(x)
MYTH_VDADECODERCREATE decoderCreate
CFStringRef * decoderConfigSourceFmt
struct OpaqueVDADecoder * VDADecoder
MYTH_VDADECODERDESTROY decoderDestroy
OSStatus(* MYTH_VDADECODERDECODE)(VDADecoder decoder, uint32_t decodeFlags, CFTypeRef compressedBuffer, CFDictionaryRef frameInfo)
void parse_SPS(uint8_t *sps, uint32_t sps_size, bool &interlaced, int32_t &max_ref_frames)
OSStatus(* MYTH_VDADECODERCREATE)(CFDictionaryRef decoderConfiguration, CFDictionaryRef destinationImageBufferAttributes, VDADecoderOutputCallback *outputCallback, void *decoderOutputCallbackRefcon, VDADecoder *decoderOut)
CFStringRef * decoderConfigHeight
VDADecoder * m_decoder
int avc_parse_nal_units(AVIOContext *pb, const uint8_t *buf_in, int size)
const uint8_t * avc_find_startcode(const uint8_t *p, const uint8_t *end)
CFStringRef * decoderConfigWidth
int avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size)
bool Reset(void) override
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
OSStatus(* MYTH_VDADECODERDESTROY)(VDADecoder decoder)
QLibrary * m_lib
MythCodecMap * gCodecMap
This global variable contains the MythCodecMap instance for the app.
Definition: mythavutil.cpp:381
int height
Definition: mythframe.h:42
QList< VDAFrame > m_decoded_frames
OSStatus(* MYTH_VDADECODERFLUSH)(VDADecoder decoder, uint32_t flushFlags)
#define CHECK_ST
AVCodecContext * getCodecContext(const AVStream *, const AVCodec *pCodec=nullptr, bool nullCodec=false)
Definition: mythavutil.cpp:392
int8_t repeat_pict
int isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
#define INIT_ST
#define LOC
#define VDA_RB24(x)
int GetFrame(AVStream *stream, AVFrame *picture, int *got_picture_ptr, AVPacket *pkt) override
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
bool IsValid(void) const
#define VDA_RB32(x)
int8_t top_field_first
static MTV_PUBLIC VDALibrary * GetVDALibrary(void)
void GetOSXVersion(int32_t *aMajorVersion, int32_t *aMinorVersion)
Definition: util-osx.mm:23
VDALibrary * gVDALib
static void GetDecoders(render_opts &opts)
MYTH_VDADECODERFLUSH decoderFlush
void av_free(void *ptr)
static const uint8_t * avc_find_startcode_internal(const uint8_t *p, const uint8_t *end)
unsigned char * buf
Definition: mythframe.h:39
bool HasBufferedFrames(void) override
QString vda_err_to_string(OSStatus err)
void(* VDADecoderOutputCallback)(void *decompressionOutputRefCon, CFDictionaryRef frameInfo, OSStatus status, uint32_t infoFlags, CVImageBufferRef imageBuffer)
MYTH_VDADECODERDECODE decoderDecode
VideoFrameType codec
Definition: mythframe.h:38