Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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. /**
  22.  * @file
  23.  * H.264 decoder via VDA
  24.  * @author Xidorn Quan <quanxunzhen@gmail.com>
  25.  */
  26.  
  27. #include <string.h>
  28. #include <CoreFoundation/CoreFoundation.h>
  29.  
  30. #include "vda.h"
  31. #include "h264.h"
  32. #include "avcodec.h"
  33.  
  34. #ifndef kCFCoreFoundationVersionNumber10_7
  35. #define kCFCoreFoundationVersionNumber10_7      635.00
  36. #endif
  37.  
  38. extern AVCodec ff_h264_decoder, ff_h264_vda_decoder;
  39.  
  40. static const enum AVPixelFormat vda_pixfmts_prior_10_7[] = {
  41.     AV_PIX_FMT_UYVY422,
  42.     AV_PIX_FMT_YUV420P,
  43.     AV_PIX_FMT_NONE
  44. };
  45.  
  46. static const enum AVPixelFormat vda_pixfmts[] = {
  47.     AV_PIX_FMT_UYVY422,
  48.     AV_PIX_FMT_YUYV422,
  49.     AV_PIX_FMT_NV12,
  50.     AV_PIX_FMT_YUV420P,
  51.     AV_PIX_FMT_NONE
  52. };
  53.  
  54. typedef struct {
  55.     H264Context h264ctx;
  56.     int h264_initialized;
  57.     struct vda_context vda_ctx;
  58.     enum AVPixelFormat pix_fmt;
  59.  
  60.     /* for backing-up fields set by user.
  61.      * we have to gain full control of such fields here */
  62.     void *hwaccel_context;
  63.     enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt);
  64.     int (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, int flags);
  65. #if FF_API_GET_BUFFER
  66.     int (*get_buffer)(struct AVCodecContext *c, AVFrame *pic);
  67. #endif
  68. } VDADecoderContext;
  69.  
  70. static enum AVPixelFormat get_format(struct AVCodecContext *avctx,
  71.         const enum AVPixelFormat *fmt)
  72. {
  73.     return AV_PIX_FMT_VDA_VLD;
  74. }
  75.  
  76. typedef struct {
  77.     CVPixelBufferRef cv_buffer;
  78. } VDABufferContext;
  79.  
  80. static void release_buffer(void *opaque, uint8_t *data)
  81. {
  82.     VDABufferContext *context = opaque;
  83.     CVPixelBufferUnlockBaseAddress(context->cv_buffer, 0);
  84.     CVPixelBufferRelease(context->cv_buffer);
  85.     av_free(context);
  86. }
  87.  
  88. static int get_buffer2(AVCodecContext *avctx, AVFrame *pic, int flag)
  89. {
  90.     VDABufferContext *context = av_mallocz(sizeof(VDABufferContext));
  91.     AVBufferRef *buffer = av_buffer_create(NULL, 0, release_buffer, context, 0);
  92.     if (!context || !buffer) {
  93.         av_free(context);
  94.         return AVERROR(ENOMEM);
  95.     }
  96.  
  97.     pic->buf[0] = buffer;
  98.     pic->data[0] = (void *)1;
  99.     return 0;
  100. }
  101.  
  102. static inline void set_context(AVCodecContext *avctx)
  103. {
  104.     VDADecoderContext *ctx = avctx->priv_data;
  105.     ctx->hwaccel_context = avctx->hwaccel_context;
  106.     avctx->hwaccel_context = &ctx->vda_ctx;
  107.     ctx->get_format = avctx->get_format;
  108.     avctx->get_format = get_format;
  109.     ctx->get_buffer2 = avctx->get_buffer2;
  110.     avctx->get_buffer2 = get_buffer2;
  111. #if FF_API_GET_BUFFER
  112.     ctx->get_buffer = avctx->get_buffer;
  113.     avctx->get_buffer = NULL;
  114. #endif
  115. }
  116.  
  117. static inline void restore_context(AVCodecContext *avctx)
  118. {
  119.     VDADecoderContext *ctx = avctx->priv_data;
  120.     avctx->hwaccel_context = ctx->hwaccel_context;
  121.     avctx->get_format = ctx->get_format;
  122.     avctx->get_buffer2 = ctx->get_buffer2;
  123. #if FF_API_GET_BUFFER
  124.     avctx->get_buffer = ctx->get_buffer;
  125. #endif
  126. }
  127.  
  128. static int vdadec_decode(AVCodecContext *avctx,
  129.         void *data, int *got_frame, AVPacket *avpkt)
  130. {
  131.     VDADecoderContext *ctx = avctx->priv_data;
  132.     AVFrame *pic = data;
  133.     int ret;
  134.  
  135.     set_context(avctx);
  136.     ret = ff_h264_decoder.decode(avctx, data, got_frame, avpkt);
  137.     restore_context(avctx);
  138.     if (*got_frame) {
  139.         AVBufferRef *buffer = pic->buf[0];
  140.         VDABufferContext *context = av_buffer_get_opaque(buffer);
  141.         CVPixelBufferRef cv_buffer = (CVPixelBufferRef)pic->data[3];
  142.  
  143.         CVPixelBufferRetain(cv_buffer);
  144.         CVPixelBufferLockBaseAddress(cv_buffer, 0);
  145.         context->cv_buffer = cv_buffer;
  146.         pic->format = ctx->pix_fmt;
  147.         if (CVPixelBufferIsPlanar(cv_buffer)) {
  148.             int i, count = CVPixelBufferGetPlaneCount(cv_buffer);
  149.             av_assert0(count < 4);
  150.             for (i = 0; i < count; i++) {
  151.                 pic->data[i] = CVPixelBufferGetBaseAddressOfPlane(cv_buffer, i);
  152.                 pic->linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(cv_buffer, i);
  153.             }
  154.         } else {
  155.             pic->data[0] = CVPixelBufferGetBaseAddress(cv_buffer);
  156.             pic->linesize[0] = CVPixelBufferGetBytesPerRow(cv_buffer);
  157.         }
  158.     }
  159.     avctx->pix_fmt = ctx->pix_fmt;
  160.  
  161.     return ret;
  162. }
  163.  
  164. static av_cold int vdadec_close(AVCodecContext *avctx)
  165. {
  166.     VDADecoderContext *ctx = avctx->priv_data;
  167.     /* release buffers and decoder */
  168.     ff_vda_destroy_decoder(&ctx->vda_ctx);
  169.     /* close H.264 decoder */
  170.     if (ctx->h264_initialized) {
  171.         set_context(avctx);
  172.         ff_h264_decoder.close(avctx);
  173.         restore_context(avctx);
  174.     }
  175.     return 0;
  176. }
  177.  
  178. static av_cold int vdadec_init(AVCodecContext *avctx)
  179. {
  180.     VDADecoderContext *ctx = avctx->priv_data;
  181.     struct vda_context *vda_ctx = &ctx->vda_ctx;
  182.     OSStatus status;
  183.     int ret, i;
  184.  
  185.     ctx->h264_initialized = 0;
  186.  
  187.     /* init pix_fmts of codec */
  188.     if (!ff_h264_vda_decoder.pix_fmts) {
  189.         if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber10_7)
  190.             ff_h264_vda_decoder.pix_fmts = vda_pixfmts_prior_10_7;
  191.         else
  192.             ff_h264_vda_decoder.pix_fmts = vda_pixfmts;
  193.     }
  194.  
  195.     /* init vda */
  196.     memset(vda_ctx, 0, sizeof(struct vda_context));
  197.     vda_ctx->width = avctx->width;
  198.     vda_ctx->height = avctx->height;
  199.     vda_ctx->format = 'avc1';
  200.     vda_ctx->use_sync_decoding = 1;
  201.     vda_ctx->use_ref_buffer = 1;
  202.     ctx->pix_fmt = avctx->get_format(avctx, avctx->codec->pix_fmts);
  203.     switch (ctx->pix_fmt) {
  204.     case AV_PIX_FMT_UYVY422:
  205.         vda_ctx->cv_pix_fmt_type = '2vuy';
  206.         break;
  207.     case AV_PIX_FMT_YUYV422:
  208.         vda_ctx->cv_pix_fmt_type = 'yuvs';
  209.         break;
  210.     case AV_PIX_FMT_NV12:
  211.         vda_ctx->cv_pix_fmt_type = '420v';
  212.         break;
  213.     case AV_PIX_FMT_YUV420P:
  214.         vda_ctx->cv_pix_fmt_type = 'y420';
  215.         break;
  216.     default:
  217.         av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format: %d\n", avctx->pix_fmt);
  218.         goto failed;
  219.     }
  220.     status = ff_vda_create_decoder(vda_ctx,
  221.                                    avctx->extradata, avctx->extradata_size);
  222.     if (status != kVDADecoderNoErr) {
  223.         av_log(avctx, AV_LOG_ERROR,
  224.                 "Failed to init VDA decoder: %d.\n", status);
  225.         goto failed;
  226.     }
  227.  
  228.     /* init H.264 decoder */
  229.     set_context(avctx);
  230.     ret = ff_h264_decoder.init(avctx);
  231.     restore_context(avctx);
  232.     if (ret < 0) {
  233.         av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 decoder.\n");
  234.         goto failed;
  235.     }
  236.     ctx->h264_initialized = 1;
  237.  
  238.     for (i = 0; i < MAX_SPS_COUNT; i++) {
  239.         SPS *sps = ctx->h264ctx.sps_buffers[i];
  240.         if (sps && (sps->bit_depth_luma != 8 ||
  241.                 sps->chroma_format_idc == 2 ||
  242.                 sps->chroma_format_idc == 3)) {
  243.             av_log(avctx, AV_LOG_ERROR, "Format is not supported.\n");
  244.             goto failed;
  245.         }
  246.     }
  247.  
  248.     return 0;
  249.  
  250. failed:
  251.     vdadec_close(avctx);
  252.     return -1;
  253. }
  254.  
  255. static void vdadec_flush(AVCodecContext *avctx)
  256. {
  257.     set_context(avctx);
  258.     ff_h264_decoder.flush(avctx);
  259.     restore_context(avctx);
  260. }
  261.  
  262. AVCodec ff_h264_vda_decoder = {
  263.     .name           = "h264_vda",
  264.     .type           = AVMEDIA_TYPE_VIDEO,
  265.     .id             = AV_CODEC_ID_H264,
  266.     .priv_data_size = sizeof(VDADecoderContext),
  267.     .init           = vdadec_init,
  268.     .close          = vdadec_close,
  269.     .decode         = vdadec_decode,
  270.     .capabilities   = AV_CODEC_CAP_DELAY,
  271.     .flush          = vdadec_flush,
  272.     .long_name      = NULL_IF_CONFIG_SMALL("H.264 (VDA acceleration)"),
  273. };
  274.