ffmpeg_videotoolbox.c 5.3 KB

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