ffmpeg_videotoolbox.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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: vt->tmp_frame->format = AV_PIX_FMT_NV12; break;
  47. #endif
  48. #if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE
  49. case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange: vt->tmp_frame->format = AV_PIX_FMT_P010; break;
  50. #endif
  51. default:
  52. av_log(NULL, AV_LOG_ERROR,
  53. "%s: Unsupported pixel format: %s\n",
  54. av_fourcc2str(s->codec_tag), videotoolbox_pixfmt);
  55. return AVERROR(ENOSYS);
  56. }
  57. vt->tmp_frame->width = frame->width;
  58. vt->tmp_frame->height = frame->height;
  59. ret = av_frame_get_buffer(vt->tmp_frame, 32);
  60. if (ret < 0)
  61. return ret;
  62. err = CVPixelBufferLockBaseAddress(pixbuf, kCVPixelBufferLock_ReadOnly);
  63. if (err != kCVReturnSuccess) {
  64. av_log(NULL, AV_LOG_ERROR, "Error locking the pixel buffer.\n");
  65. return AVERROR_UNKNOWN;
  66. }
  67. if (CVPixelBufferIsPlanar(pixbuf)) {
  68. planes = CVPixelBufferGetPlaneCount(pixbuf);
  69. for (i = 0; i < planes; i++) {
  70. data[i] = CVPixelBufferGetBaseAddressOfPlane(pixbuf, i);
  71. linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(pixbuf, i);
  72. }
  73. } else {
  74. data[0] = CVPixelBufferGetBaseAddress(pixbuf);
  75. linesize[0] = CVPixelBufferGetBytesPerRow(pixbuf);
  76. }
  77. av_image_copy(vt->tmp_frame->data, vt->tmp_frame->linesize,
  78. (const uint8_t **)data, linesize, vt->tmp_frame->format,
  79. frame->width, frame->height);
  80. ret = av_frame_copy_props(vt->tmp_frame, frame);
  81. CVPixelBufferUnlockBaseAddress(pixbuf, kCVPixelBufferLock_ReadOnly);
  82. if (ret < 0)
  83. return ret;
  84. av_frame_unref(frame);
  85. av_frame_move_ref(frame, vt->tmp_frame);
  86. return 0;
  87. }
  88. static void videotoolbox_uninit(AVCodecContext *s)
  89. {
  90. InputStream *ist = s->opaque;
  91. VTContext *vt = ist->hwaccel_ctx;
  92. ist->hwaccel_uninit = NULL;
  93. ist->hwaccel_retrieve_data = NULL;
  94. av_frame_free(&vt->tmp_frame);
  95. av_videotoolbox_default_free(s);
  96. av_freep(&ist->hwaccel_ctx);
  97. }
  98. int videotoolbox_init(AVCodecContext *s)
  99. {
  100. InputStream *ist = s->opaque;
  101. int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
  102. int ret = 0;
  103. VTContext *vt;
  104. vt = av_mallocz(sizeof(*vt));
  105. if (!vt)
  106. return AVERROR(ENOMEM);
  107. ist->hwaccel_ctx = vt;
  108. ist->hwaccel_uninit = videotoolbox_uninit;
  109. ist->hwaccel_retrieve_data = videotoolbox_retrieve_data;
  110. vt->tmp_frame = av_frame_alloc();
  111. if (!vt->tmp_frame) {
  112. ret = AVERROR(ENOMEM);
  113. goto fail;
  114. }
  115. // TODO: reindent
  116. if (!videotoolbox_pixfmt) {
  117. ret = av_videotoolbox_default_init(s);
  118. } else {
  119. AVVideotoolboxContext *vtctx = av_videotoolbox_alloc_context();
  120. CFStringRef pixfmt_str = CFStringCreateWithCString(kCFAllocatorDefault,
  121. videotoolbox_pixfmt,
  122. kCFStringEncodingUTF8);
  123. #if HAVE_UTGETOSTYPEFROMSTRING
  124. vtctx->cv_pix_fmt_type = UTGetOSTypeFromString(pixfmt_str);
  125. #else
  126. av_log(s, loglevel, "UTGetOSTypeFromString() is not available "
  127. "on this platform, %s pixel format can not be honored from "
  128. "the command line\n", videotoolbox_pixfmt);
  129. #endif
  130. ret = av_videotoolbox_default_init2(s, vtctx);
  131. CFRelease(pixfmt_str);
  132. }
  133. if (ret < 0) {
  134. av_log(NULL, loglevel, "Error creating Videotoolbox decoder.\n");
  135. goto fail;
  136. }
  137. return 0;
  138. fail:
  139. videotoolbox_uninit(s);
  140. return ret;
  141. }