ffmpeg_videotoolbox.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*
  2. * This file is part of FFmpeg.
  3. *
  4. * FFmpeg is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * FFmpeg is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with FFmpeg; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include "config.h"
  19. #if HAVE_UTGETOSTYPEFROMSTRING
  20. #include <CoreServices/CoreServices.h>
  21. #endif
  22. #include "libavcodec/avcodec.h"
  23. #include "libavcodec/videotoolbox.h"
  24. #include "libavutil/imgutils.h"
  25. #include "ffmpeg.h"
  26. typedef struct VTContext {
  27. AVFrame *tmp_frame;
  28. } VTContext;
  29. char *videotoolbox_pixfmt;
  30. static int videotoolbox_retrieve_data(AVCodecContext *s, AVFrame *frame)
  31. {
  32. InputStream *ist = s->opaque;
  33. VTContext *vt = ist->hwaccel_ctx;
  34. CVPixelBufferRef pixbuf = (CVPixelBufferRef)frame->data[3];
  35. OSType pixel_format = CVPixelBufferGetPixelFormatType(pixbuf);
  36. CVReturn err;
  37. uint8_t *data[4] = { 0 };
  38. int linesize[4] = { 0 };
  39. int planes, ret, i;
  40. av_frame_unref(vt->tmp_frame);
  41. switch (pixel_format) {
  42. case kCVPixelFormatType_420YpCbCr8Planar: vt->tmp_frame->format = AV_PIX_FMT_YUV420P; break;
  43. case kCVPixelFormatType_422YpCbCr8: vt->tmp_frame->format = AV_PIX_FMT_UYVY422; break;
  44. case kCVPixelFormatType_32BGRA: vt->tmp_frame->format = AV_PIX_FMT_BGRA; break;
  45. #ifdef kCFCoreFoundationVersionNumber10_7
  46. case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
  47. case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange: vt->tmp_frame->format = AV_PIX_FMT_NV12; break;
  48. #endif
  49. #if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE
  50. case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
  51. case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange: vt->tmp_frame->format = AV_PIX_FMT_P010; break;
  52. #endif
  53. default:
  54. av_log(NULL, AV_LOG_ERROR,
  55. "%s: Unsupported pixel format: %s\n",
  56. av_fourcc2str(s->codec_tag), videotoolbox_pixfmt);
  57. return AVERROR(ENOSYS);
  58. }
  59. vt->tmp_frame->width = frame->width;
  60. vt->tmp_frame->height = frame->height;
  61. ret = av_frame_get_buffer(vt->tmp_frame, 0);
  62. if (ret < 0)
  63. return ret;
  64. err = CVPixelBufferLockBaseAddress(pixbuf, kCVPixelBufferLock_ReadOnly);
  65. if (err != kCVReturnSuccess) {
  66. av_log(NULL, AV_LOG_ERROR, "Error locking the pixel buffer.\n");
  67. return AVERROR_UNKNOWN;
  68. }
  69. if (CVPixelBufferIsPlanar(pixbuf)) {
  70. planes = CVPixelBufferGetPlaneCount(pixbuf);
  71. for (i = 0; i < planes; i++) {
  72. data[i] = CVPixelBufferGetBaseAddressOfPlane(pixbuf, i);
  73. linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(pixbuf, i);
  74. }
  75. } else {
  76. data[0] = CVPixelBufferGetBaseAddress(pixbuf);
  77. linesize[0] = CVPixelBufferGetBytesPerRow(pixbuf);
  78. }
  79. av_image_copy(vt->tmp_frame->data, vt->tmp_frame->linesize,
  80. (const uint8_t **)data, linesize, vt->tmp_frame->format,
  81. frame->width, frame->height);
  82. ret = av_frame_copy_props(vt->tmp_frame, frame);
  83. CVPixelBufferUnlockBaseAddress(pixbuf, kCVPixelBufferLock_ReadOnly);
  84. if (ret < 0)
  85. return ret;
  86. av_frame_unref(frame);
  87. av_frame_move_ref(frame, vt->tmp_frame);
  88. return 0;
  89. }
  90. static void videotoolbox_uninit(AVCodecContext *s)
  91. {
  92. InputStream *ist = s->opaque;
  93. VTContext *vt = ist->hwaccel_ctx;
  94. ist->hwaccel_uninit = NULL;
  95. ist->hwaccel_retrieve_data = NULL;
  96. av_frame_free(&vt->tmp_frame);
  97. av_videotoolbox_default_free(s);
  98. av_freep(&ist->hwaccel_ctx);
  99. }
  100. int videotoolbox_init(AVCodecContext *s)
  101. {
  102. InputStream *ist = s->opaque;
  103. int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
  104. int ret = 0;
  105. VTContext *vt;
  106. vt = av_mallocz(sizeof(*vt));
  107. if (!vt)
  108. return AVERROR(ENOMEM);
  109. ist->hwaccel_ctx = vt;
  110. ist->hwaccel_uninit = videotoolbox_uninit;
  111. ist->hwaccel_retrieve_data = videotoolbox_retrieve_data;
  112. vt->tmp_frame = av_frame_alloc();
  113. if (!vt->tmp_frame) {
  114. ret = AVERROR(ENOMEM);
  115. goto fail;
  116. }
  117. // TODO: reindent
  118. if (!videotoolbox_pixfmt) {
  119. ret = av_videotoolbox_default_init(s);
  120. } else {
  121. AVVideotoolboxContext *vtctx = av_videotoolbox_alloc_context();
  122. CFStringRef pixfmt_str = CFStringCreateWithCString(kCFAllocatorDefault,
  123. videotoolbox_pixfmt,
  124. kCFStringEncodingUTF8);
  125. #if HAVE_UTGETOSTYPEFROMSTRING
  126. vtctx->cv_pix_fmt_type = UTGetOSTypeFromString(pixfmt_str);
  127. #else
  128. av_log(s, loglevel, "UTGetOSTypeFromString() is not available "
  129. "on this platform, %s pixel format can not be honored from "
  130. "the command line\n", videotoolbox_pixfmt);
  131. #endif
  132. ret = av_videotoolbox_default_init2(s, vtctx);
  133. CFRelease(pixfmt_str);
  134. }
  135. if (ret < 0) {
  136. av_log(NULL, loglevel, "Error creating Videotoolbox decoder.\n");
  137. goto fail;
  138. }
  139. return 0;
  140. fail:
  141. videotoolbox_uninit(s);
  142. return ret;
  143. }