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.

264 lines
7.7KB

  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. } VDADecoderContext;
  57. static enum AVPixelFormat get_format(struct AVCodecContext *avctx,
  58. const enum AVPixelFormat *fmt)
  59. {
  60. return AV_PIX_FMT_VDA_VLD;
  61. }
  62. typedef struct {
  63. CVPixelBufferRef cv_buffer;
  64. } VDABufferContext;
  65. static void release_buffer(void *opaque, uint8_t *data)
  66. {
  67. VDABufferContext *context = opaque;
  68. CVPixelBufferUnlockBaseAddress(context->cv_buffer, 0);
  69. CVPixelBufferRelease(context->cv_buffer);
  70. av_free(context);
  71. }
  72. static int get_buffer2(AVCodecContext *avctx, AVFrame *pic, int flag)
  73. {
  74. VDABufferContext *context = av_mallocz(sizeof(VDABufferContext));
  75. AVBufferRef *buffer = av_buffer_create(NULL, 0, release_buffer, context, 0);
  76. if (!context || !buffer) {
  77. av_free(context);
  78. return AVERROR(ENOMEM);
  79. }
  80. pic->buf[0] = buffer;
  81. pic->data[0] = (void *)1;
  82. return 0;
  83. }
  84. static inline void set_context(AVCodecContext *avctx)
  85. {
  86. VDADecoderContext *ctx = avctx->priv_data;
  87. ctx->hwaccel_context = avctx->hwaccel_context;
  88. avctx->hwaccel_context = &ctx->vda_ctx;
  89. ctx->get_format = avctx->get_format;
  90. avctx->get_format = get_format;
  91. ctx->get_buffer2 = avctx->get_buffer2;
  92. avctx->get_buffer2 = get_buffer2;
  93. }
  94. static inline void restore_context(AVCodecContext *avctx)
  95. {
  96. VDADecoderContext *ctx = avctx->priv_data;
  97. avctx->hwaccel_context = ctx->hwaccel_context;
  98. avctx->get_format = ctx->get_format;
  99. avctx->get_buffer2 = ctx->get_buffer2;
  100. }
  101. static int vdadec_decode(AVCodecContext *avctx,
  102. void *data, int *got_frame, AVPacket *avpkt)
  103. {
  104. VDADecoderContext *ctx = avctx->priv_data;
  105. AVFrame *pic = data;
  106. int ret;
  107. set_context(avctx);
  108. ret = ff_h264_decoder.decode(avctx, data, got_frame, avpkt);
  109. restore_context(avctx);
  110. if (*got_frame) {
  111. AVBufferRef *buffer = pic->buf[0];
  112. VDABufferContext *context = av_buffer_get_opaque(buffer);
  113. CVPixelBufferRef cv_buffer = (CVPixelBufferRef)pic->data[3];
  114. CVPixelBufferRetain(cv_buffer);
  115. CVPixelBufferLockBaseAddress(cv_buffer, 0);
  116. context->cv_buffer = cv_buffer;
  117. pic->format = ctx->pix_fmt;
  118. if (CVPixelBufferIsPlanar(cv_buffer)) {
  119. int i, count = CVPixelBufferGetPlaneCount(cv_buffer);
  120. av_assert0(count < 4);
  121. for (i = 0; i < count; i++) {
  122. pic->data[i] = CVPixelBufferGetBaseAddressOfPlane(cv_buffer, i);
  123. pic->linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(cv_buffer, i);
  124. }
  125. } else {
  126. pic->data[0] = CVPixelBufferGetBaseAddress(cv_buffer);
  127. pic->linesize[0] = CVPixelBufferGetBytesPerRow(cv_buffer);
  128. }
  129. }
  130. avctx->pix_fmt = ctx->pix_fmt;
  131. return ret;
  132. }
  133. static av_cold int vdadec_close(AVCodecContext *avctx)
  134. {
  135. VDADecoderContext *ctx = avctx->priv_data;
  136. /* release buffers and decoder */
  137. ff_vda_destroy_decoder(&ctx->vda_ctx);
  138. /* close H.264 decoder */
  139. if (ctx->h264_initialized) {
  140. set_context(avctx);
  141. ff_h264_decoder.close(avctx);
  142. restore_context(avctx);
  143. }
  144. return 0;
  145. }
  146. static av_cold int vdadec_init(AVCodecContext *avctx)
  147. {
  148. VDADecoderContext *ctx = avctx->priv_data;
  149. struct vda_context *vda_ctx = &ctx->vda_ctx;
  150. OSStatus status;
  151. int ret, i;
  152. ctx->h264_initialized = 0;
  153. /* init pix_fmts of codec */
  154. if (!ff_h264_vda_decoder.pix_fmts) {
  155. if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber10_7)
  156. ff_h264_vda_decoder.pix_fmts = vda_pixfmts_prior_10_7;
  157. else
  158. ff_h264_vda_decoder.pix_fmts = vda_pixfmts;
  159. }
  160. /* init vda */
  161. memset(vda_ctx, 0, sizeof(struct vda_context));
  162. vda_ctx->width = avctx->width;
  163. vda_ctx->height = avctx->height;
  164. vda_ctx->format = 'avc1';
  165. vda_ctx->use_sync_decoding = 1;
  166. vda_ctx->use_ref_buffer = 1;
  167. ctx->pix_fmt = avctx->get_format(avctx, avctx->codec->pix_fmts);
  168. switch (ctx->pix_fmt) {
  169. case AV_PIX_FMT_UYVY422:
  170. vda_ctx->cv_pix_fmt_type = '2vuy';
  171. break;
  172. case AV_PIX_FMT_YUYV422:
  173. vda_ctx->cv_pix_fmt_type = 'yuvs';
  174. break;
  175. case AV_PIX_FMT_NV12:
  176. vda_ctx->cv_pix_fmt_type = '420v';
  177. break;
  178. case AV_PIX_FMT_YUV420P:
  179. vda_ctx->cv_pix_fmt_type = 'y420';
  180. break;
  181. default:
  182. av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format: %d\n", avctx->pix_fmt);
  183. goto failed;
  184. }
  185. status = ff_vda_create_decoder(vda_ctx,
  186. avctx->extradata, avctx->extradata_size);
  187. if (status != kVDADecoderNoErr) {
  188. av_log(avctx, AV_LOG_ERROR,
  189. "Failed to init VDA decoder: %d.\n", status);
  190. goto failed;
  191. }
  192. /* init H.264 decoder */
  193. set_context(avctx);
  194. ret = ff_h264_decoder.init(avctx);
  195. restore_context(avctx);
  196. if (ret < 0) {
  197. av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 decoder.\n");
  198. goto failed;
  199. }
  200. ctx->h264_initialized = 1;
  201. for (i = 0; i < MAX_SPS_COUNT; i++) {
  202. SPS *sps = ctx->h264ctx.sps_buffers[i];
  203. if (sps && (sps->bit_depth_luma != 8 ||
  204. sps->chroma_format_idc == 2 ||
  205. sps->chroma_format_idc == 3)) {
  206. av_log(avctx, AV_LOG_ERROR, "Format is not supported.\n");
  207. goto failed;
  208. }
  209. }
  210. return 0;
  211. failed:
  212. vdadec_close(avctx);
  213. return -1;
  214. }
  215. static void vdadec_flush(AVCodecContext *avctx)
  216. {
  217. set_context(avctx);
  218. ff_h264_decoder.flush(avctx);
  219. restore_context(avctx);
  220. }
  221. AVCodec ff_h264_vda_decoder = {
  222. .name = "h264_vda",
  223. .type = AVMEDIA_TYPE_VIDEO,
  224. .id = AV_CODEC_ID_H264,
  225. .priv_data_size = sizeof(VDADecoderContext),
  226. .init = vdadec_init,
  227. .close = vdadec_close,
  228. .decode = vdadec_decode,
  229. .capabilities = AV_CODEC_CAP_DELAY,
  230. .flush = vdadec_flush,
  231. .long_name = NULL_IF_CONFIG_SMALL("H.264 (VDA acceleration)"),
  232. };