Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * VDA H264 HW acceleration.
  3.  *
  4.  * copyright (c) 2011 Sebastien Zwickert
  5.  *
  6.  * This file is part of FFmpeg.
  7.  *
  8.  * FFmpeg is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Lesser General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2.1 of the License, or (at your option) any later version.
  12.  *
  13.  * FFmpeg is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Lesser General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Lesser General Public
  19.  * License along with FFmpeg; if not, write to the Free Software
  20.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21.  */
  22.  
  23. #include <CoreFoundation/CFDictionary.h>
  24. #include <CoreFoundation/CFNumber.h>
  25. #include <CoreFoundation/CFData.h>
  26.  
  27. #include "vda.h"
  28. #include "libavutil/avutil.h"
  29. #include "h264.h"
  30.  
  31. struct vda_buffer {
  32.     CVPixelBufferRef cv_buffer;
  33. };
  34.  
  35. /* Decoder callback that adds the vda frame to the queue in display order. */
  36. static void vda_decoder_callback (void *vda_hw_ctx,
  37.                                   CFDictionaryRef user_info,
  38.                                   OSStatus status,
  39.                                   uint32_t infoFlags,
  40.                                   CVImageBufferRef image_buffer)
  41. {
  42.     struct vda_context *vda_ctx = vda_hw_ctx;
  43.  
  44.     if (!image_buffer)
  45.         return;
  46.  
  47.     if (vda_ctx->cv_pix_fmt_type != CVPixelBufferGetPixelFormatType(image_buffer))
  48.         return;
  49.  
  50.     vda_ctx->cv_buffer = CVPixelBufferRetain(image_buffer);
  51. }
  52.  
  53. static int vda_sync_decode(struct vda_context *vda_ctx)
  54. {
  55.     OSStatus status;
  56.     CFDataRef coded_frame;
  57.     uint32_t flush_flags = 1 << 0; ///< kVDADecoderFlush_emitFrames
  58.  
  59.     coded_frame = CFDataCreate(kCFAllocatorDefault,
  60.                                vda_ctx->priv_bitstream,
  61.                                vda_ctx->priv_bitstream_size);
  62.  
  63.     status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, NULL);
  64.  
  65.     if (kVDADecoderNoErr == status)
  66.         status = VDADecoderFlush(vda_ctx->decoder, flush_flags);
  67.  
  68.     CFRelease(coded_frame);
  69.  
  70.     return status;
  71. }
  72.  
  73.  
  74. static int vda_h264_start_frame(AVCodecContext *avctx,
  75.                                 av_unused const uint8_t *buffer,
  76.                                 av_unused uint32_t size)
  77. {
  78.     struct vda_context *vda_ctx = avctx->hwaccel_context;
  79.  
  80.     if (!vda_ctx->decoder)
  81.         return -1;
  82.  
  83.     vda_ctx->priv_bitstream_size = 0;
  84.  
  85.     return 0;
  86. }
  87.  
  88. static int vda_h264_decode_slice(AVCodecContext *avctx,
  89.                                  const uint8_t *buffer,
  90.                                  uint32_t size)
  91. {
  92.     struct vda_context *vda_ctx = avctx->hwaccel_context;
  93.     void *tmp;
  94.  
  95.     if (!vda_ctx->decoder)
  96.         return -1;
  97.  
  98.     tmp = av_fast_realloc(vda_ctx->priv_bitstream,
  99.                           &vda_ctx->priv_allocated_size,
  100.                           vda_ctx->priv_bitstream_size + size + 4);
  101.     if (!tmp)
  102.         return AVERROR(ENOMEM);
  103.  
  104.     vda_ctx->priv_bitstream = tmp;
  105.  
  106.     AV_WB32(vda_ctx->priv_bitstream + vda_ctx->priv_bitstream_size, size);
  107.     memcpy(vda_ctx->priv_bitstream + vda_ctx->priv_bitstream_size + 4, buffer, size);
  108.  
  109.     vda_ctx->priv_bitstream_size += size + 4;
  110.  
  111.     return 0;
  112. }
  113.  
  114. static void vda_h264_release_buffer(void *opaque, uint8_t *data)
  115. {
  116.     struct vda_buffer *context = opaque;
  117.     CVPixelBufferRelease(context->cv_buffer);
  118.     av_free(context);
  119. }
  120.  
  121. static int vda_h264_end_frame(AVCodecContext *avctx)
  122. {
  123.     H264Context *h                      = avctx->priv_data;
  124.     struct vda_context *vda_ctx         = avctx->hwaccel_context;
  125.     AVFrame *frame                      = &h->cur_pic_ptr->f;
  126.     struct vda_buffer *context;
  127.     AVBufferRef *buffer;
  128.     int status;
  129.  
  130.     if (!vda_ctx->decoder || !vda_ctx->priv_bitstream)
  131.         return -1;
  132.  
  133.     status = vda_sync_decode(vda_ctx);
  134.     frame->data[3] = (void*)vda_ctx->cv_buffer;
  135.  
  136.     if (status)
  137.         av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status);
  138.  
  139.     if (!vda_ctx->use_ref_buffer || status)
  140.         return status;
  141.  
  142.     context = av_mallocz(sizeof(*context));
  143.     buffer = av_buffer_create(NULL, 0, vda_h264_release_buffer, context, 0);
  144.     if (!context || !buffer) {
  145.         CVPixelBufferRelease(vda_ctx->cv_buffer);
  146.         av_free(context);
  147.         return -1;
  148.     }
  149.  
  150.     context->cv_buffer = vda_ctx->cv_buffer;
  151.     frame->buf[3] = buffer;
  152.  
  153.     return status;
  154. }
  155.  
  156. int ff_vda_create_decoder(struct vda_context *vda_ctx,
  157.                           uint8_t *extradata,
  158.                           int extradata_size)
  159. {
  160.     OSStatus status;
  161.     CFNumberRef height;
  162.     CFNumberRef width;
  163.     CFNumberRef format;
  164.     CFDataRef avc_data;
  165.     CFMutableDictionaryRef config_info;
  166.     CFMutableDictionaryRef buffer_attributes;
  167.     CFMutableDictionaryRef io_surface_properties;
  168.     CFNumberRef cv_pix_fmt;
  169.  
  170.     vda_ctx->priv_bitstream = NULL;
  171.     vda_ctx->priv_allocated_size = 0;
  172.  
  173.     /* Each VCL NAL in the bitstream sent to the decoder
  174.      * is preceded by a 4 bytes length header.
  175.      * Change the avcC atom header if needed, to signal headers of 4 bytes. */
  176.     if (extradata_size >= 4 && (extradata[4] & 0x03) != 0x03) {
  177.         uint8_t *rw_extradata;
  178.  
  179.         if (!(rw_extradata = av_malloc(extradata_size)))
  180.             return AVERROR(ENOMEM);
  181.  
  182.         memcpy(rw_extradata, extradata, extradata_size);
  183.  
  184.         rw_extradata[4] |= 0x03;
  185.  
  186.         avc_data = CFDataCreate(kCFAllocatorDefault, rw_extradata, extradata_size);
  187.  
  188.         av_freep(&rw_extradata);
  189.     } else {
  190.         avc_data = CFDataCreate(kCFAllocatorDefault, extradata, extradata_size);
  191.     }
  192.  
  193.     config_info = CFDictionaryCreateMutable(kCFAllocatorDefault,
  194.                                             4,
  195.                                             &kCFTypeDictionaryKeyCallBacks,
  196.                                             &kCFTypeDictionaryValueCallBacks);
  197.  
  198.     height   = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->height);
  199.     width    = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->width);
  200.     format   = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->format);
  201.  
  202.     CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, height);
  203.     CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width);
  204.     CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, format);
  205.     CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, avc_data);
  206.  
  207.     buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault,
  208.                                                   2,
  209.                                                   &kCFTypeDictionaryKeyCallBacks,
  210.                                                   &kCFTypeDictionaryValueCallBacks);
  211.     io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault,
  212.                                                       0,
  213.                                                       &kCFTypeDictionaryKeyCallBacks,
  214.                                                       &kCFTypeDictionaryValueCallBacks);
  215.     cv_pix_fmt  = CFNumberCreate(kCFAllocatorDefault,
  216.                                  kCFNumberSInt32Type,
  217.                                  &vda_ctx->cv_pix_fmt_type);
  218.     CFDictionarySetValue(buffer_attributes,
  219.                          kCVPixelBufferPixelFormatTypeKey,
  220.                          cv_pix_fmt);
  221.     CFDictionarySetValue(buffer_attributes,
  222.                          kCVPixelBufferIOSurfacePropertiesKey,
  223.                          io_surface_properties);
  224.  
  225.     status = VDADecoderCreate(config_info,
  226.                               buffer_attributes,
  227.                               vda_decoder_callback,
  228.                               vda_ctx,
  229.                               &vda_ctx->decoder);
  230.  
  231.     CFRelease(height);
  232.     CFRelease(width);
  233.     CFRelease(format);
  234.     CFRelease(avc_data);
  235.     CFRelease(config_info);
  236.     CFRelease(io_surface_properties);
  237.     CFRelease(cv_pix_fmt);
  238.     CFRelease(buffer_attributes);
  239.  
  240.     return status;
  241. }
  242.  
  243. int ff_vda_destroy_decoder(struct vda_context *vda_ctx)
  244. {
  245.     OSStatus status = kVDADecoderNoErr;
  246.  
  247.     if (vda_ctx->decoder)
  248.         status = VDADecoderDestroy(vda_ctx->decoder);
  249.  
  250.     av_freep(&vda_ctx->priv_bitstream);
  251.  
  252.     return status;
  253. }
  254.  
  255. AVHWAccel ff_h264_vda_hwaccel = {
  256.     .name           = "h264_vda",
  257.     .type           = AVMEDIA_TYPE_VIDEO,
  258.     .id             = AV_CODEC_ID_H264,
  259.     .pix_fmt        = AV_PIX_FMT_VDA_VLD,
  260.     .start_frame    = vda_h264_start_frame,
  261.     .decode_slice   = vda_h264_decode_slice,
  262.     .end_frame      = vda_h264_end_frame,
  263. };
  264.