You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

274 lines
8.0KB

  1. /*
  2. * Copyright (c) 2012, Xidorn Quan
  3. *
  4. * This file is part of FFmpeg.
  5. *
  6. * FFmpeg is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * FFmpeg is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with FFmpeg; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. */
  20. /**
  21. * @file
  22. * H.264 decoder via VDA
  23. * @author Xidorn Quan <quanxunzhen@gmail.com>
  24. */
  25. #include <string.h>
  26. #include <CoreFoundation/CoreFoundation.h>
  27. #include "vda.h"
  28. #include "h264.h"
  29. #include "avcodec.h"
  30. #ifndef kCFCoreFoundationVersionNumber10_7
  31. #define kCFCoreFoundationVersionNumber10_7 635.00
  32. #endif
  33. extern AVCodec ff_h264_decoder, ff_h264_vda_decoder;
  34. static const enum AVPixelFormat vda_pixfmts_prior_10_7[] = {
  35. AV_PIX_FMT_UYVY422,
  36. AV_PIX_FMT_YUV420P,
  37. AV_PIX_FMT_NONE
  38. };
  39. static const enum AVPixelFormat vda_pixfmts[] = {
  40. AV_PIX_FMT_UYVY422,
  41. AV_PIX_FMT_YUYV422,
  42. AV_PIX_FMT_NV12,
  43. AV_PIX_FMT_YUV420P,
  44. AV_PIX_FMT_NONE
  45. };
  46. typedef struct {
  47. H264Context h264ctx;
  48. int h264_initialized;
  49. struct vda_context vda_ctx;
  50. enum AVPixelFormat pix_fmt;
  51. /* for backing-up fields set by user.
  52. * we have to gain full control of such fields here */
  53. void *hwaccel_context;
  54. enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt);
  55. int (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, int flags);
  56. #if FF_API_GET_BUFFER
  57. int (*get_buffer)(struct AVCodecContext *c, AVFrame *pic);
  58. #endif
  59. } VDADecoderContext;
  60. static enum AVPixelFormat get_format(struct AVCodecContext *avctx,
  61. const enum AVPixelFormat *fmt)
  62. {
  63. return AV_PIX_FMT_VDA_VLD;
  64. }
  65. typedef struct {
  66. CVPixelBufferRef cv_buffer;
  67. } VDABufferContext;
  68. static void release_buffer(void *opaque, uint8_t *data)
  69. {
  70. VDABufferContext *context = opaque;
  71. CVPixelBufferUnlockBaseAddress(context->cv_buffer, 0);
  72. CVPixelBufferRelease(context->cv_buffer);
  73. av_free(context);
  74. }
  75. static int get_buffer2(AVCodecContext *avctx, AVFrame *pic, int flag)
  76. {
  77. VDABufferContext *context = av_mallocz(sizeof(VDABufferContext));
  78. AVBufferRef *buffer = av_buffer_create(NULL, 0, release_buffer, context, 0);
  79. if (!context || !buffer) {
  80. av_free(context);
  81. return AVERROR(ENOMEM);
  82. }
  83. pic->buf[0] = buffer;
  84. pic->data[0] = (void *)1;
  85. return 0;
  86. }
  87. static inline void set_context(AVCodecContext *avctx)
  88. {
  89. VDADecoderContext *ctx = avctx->priv_data;
  90. ctx->hwaccel_context = avctx->hwaccel_context;
  91. avctx->hwaccel_context = &ctx->vda_ctx;
  92. ctx->get_format = avctx->get_format;
  93. avctx->get_format = get_format;
  94. ctx->get_buffer2 = avctx->get_buffer2;
  95. avctx->get_buffer2 = get_buffer2;
  96. #if FF_API_GET_BUFFER
  97. ctx->get_buffer = avctx->get_buffer;
  98. avctx->get_buffer = NULL;
  99. #endif
  100. }
  101. static inline void restore_context(AVCodecContext *avctx)
  102. {
  103. VDADecoderContext *ctx = avctx->priv_data;
  104. avctx->hwaccel_context = ctx->hwaccel_context;
  105. avctx->get_format = ctx->get_format;
  106. avctx->get_buffer2 = ctx->get_buffer2;
  107. #if FF_API_GET_BUFFER
  108. avctx->get_buffer = ctx->get_buffer;
  109. #endif
  110. }
  111. static int vdadec_decode(AVCodecContext *avctx,
  112. void *data, int *got_frame, AVPacket *avpkt)
  113. {
  114. VDADecoderContext *ctx = avctx->priv_data;
  115. AVFrame *pic = data;
  116. int ret;
  117. set_context(avctx);
  118. ret = ff_h264_decoder.decode(avctx, data, got_frame, avpkt);
  119. restore_context(avctx);
  120. if (*got_frame) {
  121. AVBufferRef *buffer = pic->buf[0];
  122. VDABufferContext *context = av_buffer_get_opaque(buffer);
  123. CVPixelBufferRef cv_buffer = (CVPixelBufferRef)pic->data[3];
  124. CVPixelBufferRetain(cv_buffer);
  125. CVPixelBufferLockBaseAddress(cv_buffer, 0);
  126. context->cv_buffer = cv_buffer;
  127. pic->format = ctx->pix_fmt;
  128. if (CVPixelBufferIsPlanar(cv_buffer)) {
  129. int i, count = CVPixelBufferGetPlaneCount(cv_buffer);
  130. av_assert0(count < 4);
  131. for (i = 0; i < count; i++) {
  132. pic->data[i] = CVPixelBufferGetBaseAddressOfPlane(cv_buffer, i);
  133. pic->linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(cv_buffer, i);
  134. }
  135. } else {
  136. pic->data[0] = CVPixelBufferGetBaseAddress(cv_buffer);
  137. pic->linesize[0] = CVPixelBufferGetBytesPerRow(cv_buffer);
  138. }
  139. }
  140. avctx->pix_fmt = ctx->pix_fmt;
  141. return ret;
  142. }
  143. static av_cold int vdadec_close(AVCodecContext *avctx)
  144. {
  145. VDADecoderContext *ctx = avctx->priv_data;
  146. /* release buffers and decoder */
  147. ff_vda_destroy_decoder(&ctx->vda_ctx);
  148. /* close H.264 decoder */
  149. if (ctx->h264_initialized) {
  150. set_context(avctx);
  151. ff_h264_decoder.close(avctx);
  152. restore_context(avctx);
  153. }
  154. return 0;
  155. }
  156. static av_cold int vdadec_init(AVCodecContext *avctx)
  157. {
  158. VDADecoderContext *ctx = avctx->priv_data;
  159. struct vda_context *vda_ctx = &ctx->vda_ctx;
  160. OSStatus status;
  161. int ret;
  162. ctx->h264_initialized = 0;
  163. /* init pix_fmts of codec */
  164. if (!ff_h264_vda_decoder.pix_fmts) {
  165. if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber10_7)
  166. ff_h264_vda_decoder.pix_fmts = vda_pixfmts_prior_10_7;
  167. else
  168. ff_h264_vda_decoder.pix_fmts = vda_pixfmts;
  169. }
  170. /* init vda */
  171. memset(vda_ctx, 0, sizeof(struct vda_context));
  172. vda_ctx->width = avctx->width;
  173. vda_ctx->height = avctx->height;
  174. vda_ctx->format = 'avc1';
  175. vda_ctx->use_sync_decoding = 1;
  176. vda_ctx->use_ref_buffer = 1;
  177. ctx->pix_fmt = avctx->get_format(avctx, avctx->codec->pix_fmts);
  178. switch (ctx->pix_fmt) {
  179. case AV_PIX_FMT_UYVY422:
  180. vda_ctx->cv_pix_fmt_type = '2vuy';
  181. break;
  182. case AV_PIX_FMT_YUYV422:
  183. vda_ctx->cv_pix_fmt_type = 'yuvs';
  184. break;
  185. case AV_PIX_FMT_NV12:
  186. vda_ctx->cv_pix_fmt_type = '420v';
  187. break;
  188. case AV_PIX_FMT_YUV420P:
  189. vda_ctx->cv_pix_fmt_type = 'y420';
  190. break;
  191. default:
  192. av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format: %d\n", avctx->pix_fmt);
  193. goto failed;
  194. }
  195. status = ff_vda_create_decoder(vda_ctx,
  196. avctx->extradata, avctx->extradata_size);
  197. if (status != kVDADecoderNoErr) {
  198. av_log(avctx, AV_LOG_ERROR,
  199. "Failed to init VDA decoder: %d.\n", status);
  200. goto failed;
  201. }
  202. /* init H.264 decoder */
  203. set_context(avctx);
  204. ret = ff_h264_decoder.init(avctx);
  205. restore_context(avctx);
  206. if (ret < 0) {
  207. av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 decoder.\n");
  208. goto failed;
  209. }
  210. ctx->h264_initialized = 1;
  211. for (int i = 0; i < MAX_SPS_COUNT; i++) {
  212. SPS *sps = ctx->h264ctx.sps_buffers[i];
  213. if (sps && (sps->bit_depth_luma != 8 ||
  214. sps->chroma_format_idc == 2 ||
  215. sps->chroma_format_idc == 3)) {
  216. av_log(avctx, AV_LOG_ERROR, "Format is not supported.\n");
  217. goto failed;
  218. }
  219. }
  220. return 0;
  221. failed:
  222. vdadec_close(avctx);
  223. return -1;
  224. }
  225. static void vdadec_flush(AVCodecContext *avctx)
  226. {
  227. set_context(avctx);
  228. ff_h264_decoder.flush(avctx);
  229. restore_context(avctx);
  230. }
  231. AVCodec ff_h264_vda_decoder = {
  232. .name = "h264_vda",
  233. .type = AVMEDIA_TYPE_VIDEO,
  234. .id = AV_CODEC_ID_H264,
  235. .priv_data_size = sizeof(VDADecoderContext),
  236. .init = vdadec_init,
  237. .close = vdadec_close,
  238. .decode = vdadec_decode,
  239. .capabilities = CODEC_CAP_DELAY,
  240. .flush = vdadec_flush,
  241. .long_name = NULL_IF_CONFIG_SMALL("H.264 (VDA acceleration)"),
  242. };