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
8.1KB

  1. /*
  2. * VDA 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. #include "vda_internal.h"
  23. /**
  24. * \addtogroup VDA_Decoding
  25. *
  26. * @{
  27. */
  28. /* Mutex manager callback. */
  29. static int vda_lock_operation(void **mtx, enum AVLockOp op)
  30. {
  31. switch(op)
  32. {
  33. case AV_LOCK_CREATE:
  34. *mtx = av_malloc(sizeof(pthread_mutex_t));
  35. if(!*mtx)
  36. return 1;
  37. return !!pthread_mutex_init(*mtx, NULL);
  38. case AV_LOCK_OBTAIN:
  39. return !!pthread_mutex_lock(*mtx);
  40. case AV_LOCK_RELEASE:
  41. return !!pthread_mutex_unlock(*mtx);
  42. case AV_LOCK_DESTROY:
  43. pthread_mutex_destroy(*mtx);
  44. av_freep(mtx);
  45. return 0;
  46. }
  47. return 1;
  48. }
  49. /* Helper to create a dictionary according to the given pts. */
  50. static CFDictionaryRef vda_dictionary_with_pts(int64_t i_pts)
  51. {
  52. CFStringRef key = CFSTR("FF_VDA_DECODER_PTS_KEY");
  53. CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &i_pts);
  54. CFDictionaryRef user_info = CFDictionaryCreate( kCFAllocatorDefault,
  55. (const void **)&key,
  56. (const void **)&value,
  57. 1,
  58. &kCFTypeDictionaryKeyCallBacks,
  59. &kCFTypeDictionaryValueCallBacks);
  60. CFRelease(value);
  61. return user_info;
  62. }
  63. /* Helper to retrieve the pts from the given dictionary. */
  64. static int64_t vda_pts_from_dictionary(CFDictionaryRef user_info)
  65. {
  66. CFNumberRef pts;
  67. int64_t outValue = 0;
  68. if (NULL == user_info)
  69. return 0;
  70. pts = CFDictionaryGetValue(user_info, CFSTR("FF_VDA_DECODER_PTS_KEY"));
  71. if (pts)
  72. CFNumberGetValue(pts, kCFNumberSInt64Type, &outValue);
  73. return outValue;
  74. }
  75. /* Removes and releases all frames from the queue. */
  76. static void vda_clear_queue(struct vda_context *vda_ctx)
  77. {
  78. vda_frame *top_frame;
  79. vda_lock_operation(&vda_ctx->queue_mutex, AV_LOCK_OBTAIN);
  80. while (vda_ctx->queue != NULL)
  81. {
  82. top_frame = vda_ctx->queue;
  83. vda_ctx->queue = top_frame->next_frame;
  84. ff_vda_release_vda_frame(top_frame);
  85. }
  86. vda_lock_operation(&vda_ctx->queue_mutex, AV_LOCK_RELEASE);
  87. }
  88. /* Decoder callback that adds the vda frame to the queue in display order. */
  89. static void vda_decoder_callback (void *vda_hw_ctx,
  90. CFDictionaryRef user_info,
  91. OSStatus status,
  92. uint32_t infoFlags,
  93. CVImageBufferRef image_buffer)
  94. {
  95. struct vda_context *vda_ctx = (struct vda_context*)vda_hw_ctx;
  96. vda_frame *new_frame;
  97. vda_frame *queue_walker;
  98. if (NULL == image_buffer)
  99. return;
  100. if (kCVPixelFormatType_422YpCbCr8 != CVPixelBufferGetPixelFormatType(image_buffer))
  101. return;
  102. new_frame = (vda_frame *)av_mallocz(sizeof(vda_frame));
  103. new_frame->next_frame = NULL;
  104. new_frame->cv_buffer = CVPixelBufferRetain(image_buffer);
  105. new_frame->pts = vda_pts_from_dictionary(user_info);
  106. vda_lock_operation(&vda_ctx->queue_mutex, AV_LOCK_OBTAIN);
  107. queue_walker = vda_ctx->queue;
  108. if (!queue_walker || (new_frame->pts < queue_walker->pts))
  109. {
  110. /* we have an empty queue, or this frame earlier than the current queue head */
  111. new_frame->next_frame = queue_walker;
  112. vda_ctx->queue = new_frame;
  113. }
  114. else
  115. {
  116. /* walk the queue and insert this frame where it belongs in display order */
  117. vda_frame *next_frame;
  118. while (1)
  119. {
  120. next_frame = queue_walker->next_frame;
  121. if (!next_frame || (new_frame->pts < next_frame->pts))
  122. {
  123. new_frame->next_frame = next_frame;
  124. queue_walker->next_frame = new_frame;
  125. break;
  126. }
  127. queue_walker = next_frame;
  128. }
  129. }
  130. vda_lock_operation(&vda_ctx->queue_mutex, AV_LOCK_RELEASE);
  131. }
  132. int ff_vda_create_decoder(struct vda_context *vda_ctx,
  133. uint8_t *extradata,
  134. int extradata_size)
  135. {
  136. OSStatus status = kVDADecoderNoErr;
  137. CFNumberRef height;
  138. CFNumberRef width;
  139. CFNumberRef format;
  140. CFDataRef avc_data;
  141. CFMutableDictionaryRef config_info;
  142. if (av_lockmgr_register(vda_lock_operation))
  143. return -1;
  144. vda_lock_operation(&vda_ctx->queue_mutex, AV_LOCK_CREATE);
  145. config_info = (CFDictionaryCreateMutable(kCFAllocatorDefault,
  146. 4,
  147. &kCFTypeDictionaryKeyCallBacks,
  148. &kCFTypeDictionaryValueCallBacks));
  149. height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->height);
  150. width = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->width);
  151. format = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->format);
  152. avc_data = CFDataCreate(kCFAllocatorDefault, extradata, extradata_size);
  153. CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, height);
  154. CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width);
  155. CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, format);
  156. CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, avc_data);
  157. status = VDADecoderCreate( config_info,
  158. NULL,
  159. (VDADecoderOutputCallback *)vda_decoder_callback,
  160. (void *)vda_ctx,
  161. &vda_ctx->decoder );
  162. CFRelease(height);
  163. CFRelease(width);
  164. CFRelease(format);
  165. CFRelease(avc_data);
  166. CFRelease(config_info);
  167. if (kVDADecoderNoErr != status)
  168. return status;
  169. return 0;
  170. }
  171. int ff_vda_destroy_decoder(struct vda_context *vda_ctx)
  172. {
  173. OSStatus status = kVDADecoderNoErr;
  174. if (vda_ctx->decoder)
  175. status = VDADecoderDestroy(vda_ctx->decoder);
  176. vda_clear_queue(vda_ctx);
  177. if (vda_ctx->queue_mutex != NULL)
  178. vda_lock_operation(&vda_ctx->queue_mutex, AV_LOCK_DESTROY);
  179. if (kVDADecoderNoErr != status)
  180. return status;
  181. return 0;
  182. }
  183. vda_frame *ff_vda_queue_pop(struct vda_context *vda_ctx)
  184. {
  185. vda_frame *top_frame;
  186. if (!vda_ctx->queue)
  187. return NULL;
  188. vda_lock_operation(&vda_ctx->queue_mutex, AV_LOCK_OBTAIN);
  189. top_frame = vda_ctx->queue;
  190. vda_ctx->queue = top_frame->next_frame;
  191. vda_lock_operation(&vda_ctx->queue_mutex, AV_LOCK_RELEASE);
  192. return top_frame;
  193. }
  194. void ff_vda_release_vda_frame(vda_frame *frame)
  195. {
  196. if (frame != NULL)
  197. {
  198. CVPixelBufferRelease(frame->cv_buffer);
  199. av_freep(&frame);
  200. }
  201. }
  202. int ff_vda_decoder_decode(struct vda_context *vda_ctx,
  203. uint8_t *bitstream,
  204. int bitstream_size,
  205. int64_t frame_pts)
  206. {
  207. OSStatus status = kVDADecoderNoErr;
  208. CFDictionaryRef user_info;
  209. CFDataRef coded_frame;
  210. coded_frame = CFDataCreate(kCFAllocatorDefault, bitstream, bitstream_size);
  211. user_info = vda_dictionary_with_pts(frame_pts);
  212. status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, user_info);
  213. CFRelease(user_info);
  214. CFRelease(coded_frame);
  215. if (kVDADecoderNoErr != status)
  216. return status;
  217. return 0;
  218. }
  219. /* @} */