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.

272 lines
7.6KB

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