opencl.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*
  2. * This file is part of FFmpeg.
  3. *
  4. * FFmpeg is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * FFmpeg is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with FFmpeg; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include "libavutil/mem.h"
  21. #include "libavutil/pixdesc.h"
  22. #include "formats.h"
  23. #include "opencl.h"
  24. int ff_opencl_filter_query_formats(AVFilterContext *avctx)
  25. {
  26. const static enum AVPixelFormat pix_fmts[] = {
  27. AV_PIX_FMT_OPENCL,
  28. AV_PIX_FMT_NONE,
  29. };
  30. AVFilterFormats *formats;
  31. formats = ff_make_format_list(pix_fmts);
  32. if (!formats)
  33. return AVERROR(ENOMEM);
  34. return ff_set_common_formats(avctx, formats);
  35. }
  36. static int opencl_filter_set_device(AVFilterContext *avctx,
  37. AVBufferRef *device)
  38. {
  39. OpenCLFilterContext *ctx = avctx->priv;
  40. av_buffer_unref(&ctx->device_ref);
  41. ctx->device_ref = av_buffer_ref(device);
  42. if (!ctx->device_ref)
  43. return AVERROR(ENOMEM);
  44. ctx->device = (AVHWDeviceContext*)ctx->device_ref->data;
  45. ctx->hwctx = ctx->device->hwctx;
  46. return 0;
  47. }
  48. int ff_opencl_filter_config_input(AVFilterLink *inlink)
  49. {
  50. AVFilterContext *avctx = inlink->dst;
  51. OpenCLFilterContext *ctx = avctx->priv;
  52. AVHWFramesContext *input_frames;
  53. int err;
  54. if (!inlink->hw_frames_ctx) {
  55. av_log(avctx, AV_LOG_ERROR, "OpenCL filtering requires a "
  56. "hardware frames context on the input.\n");
  57. return AVERROR(EINVAL);
  58. }
  59. // Extract the device and default output format from the first input.
  60. if (avctx->inputs[0] != inlink)
  61. return 0;
  62. input_frames = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
  63. if (input_frames->format != AV_PIX_FMT_OPENCL)
  64. return AVERROR(EINVAL);
  65. err = opencl_filter_set_device(avctx, input_frames->device_ref);
  66. if (err < 0)
  67. return err;
  68. // Default output parameters match input parameters.
  69. if (ctx->output_format == AV_PIX_FMT_NONE)
  70. ctx->output_format = input_frames->sw_format;
  71. if (!ctx->output_width)
  72. ctx->output_width = inlink->w;
  73. if (!ctx->output_height)
  74. ctx->output_height = inlink->h;
  75. return 0;
  76. }
  77. int ff_opencl_filter_config_output(AVFilterLink *outlink)
  78. {
  79. AVFilterContext *avctx = outlink->src;
  80. OpenCLFilterContext *ctx = avctx->priv;
  81. AVBufferRef *output_frames_ref = NULL;
  82. AVHWFramesContext *output_frames;
  83. int err;
  84. av_buffer_unref(&outlink->hw_frames_ctx);
  85. if (!ctx->device_ref) {
  86. if (!avctx->hw_device_ctx) {
  87. av_log(avctx, AV_LOG_ERROR, "OpenCL filtering requires an "
  88. "OpenCL device.\n");
  89. return AVERROR(EINVAL);
  90. }
  91. err = opencl_filter_set_device(avctx, avctx->hw_device_ctx);
  92. if (err < 0)
  93. return err;
  94. }
  95. output_frames_ref = av_hwframe_ctx_alloc(ctx->device_ref);
  96. if (!output_frames_ref) {
  97. err = AVERROR(ENOMEM);
  98. goto fail;
  99. }
  100. output_frames = (AVHWFramesContext*)output_frames_ref->data;
  101. output_frames->format = AV_PIX_FMT_OPENCL;
  102. output_frames->sw_format = ctx->output_format;
  103. output_frames->width = ctx->output_width;
  104. output_frames->height = ctx->output_height;
  105. err = av_hwframe_ctx_init(output_frames_ref);
  106. if (err < 0) {
  107. av_log(avctx, AV_LOG_ERROR, "Failed to initialise output "
  108. "frames: %d.\n", err);
  109. goto fail;
  110. }
  111. outlink->hw_frames_ctx = output_frames_ref;
  112. outlink->w = ctx->output_width;
  113. outlink->h = ctx->output_height;
  114. return 0;
  115. fail:
  116. av_buffer_unref(&output_frames_ref);
  117. return err;
  118. }
  119. int ff_opencl_filter_init(AVFilterContext *avctx)
  120. {
  121. OpenCLFilterContext *ctx = avctx->priv;
  122. ctx->output_format = AV_PIX_FMT_NONE;
  123. return 0;
  124. }
  125. void ff_opencl_filter_uninit(AVFilterContext *avctx)
  126. {
  127. OpenCLFilterContext *ctx = avctx->priv;
  128. cl_int cle;
  129. if (ctx->program) {
  130. cle = clReleaseProgram(ctx->program);
  131. if (cle != CL_SUCCESS)
  132. av_log(avctx, AV_LOG_ERROR, "Failed to release "
  133. "program: %d.\n", cle);
  134. }
  135. av_buffer_unref(&ctx->device_ref);
  136. }
  137. int ff_opencl_filter_load_program(AVFilterContext *avctx,
  138. const char **program_source_array,
  139. int nb_strings)
  140. {
  141. OpenCLFilterContext *ctx = avctx->priv;
  142. cl_int cle;
  143. ctx->program = clCreateProgramWithSource(ctx->hwctx->context, nb_strings,
  144. program_source_array,
  145. NULL, &cle);
  146. if (!ctx->program) {
  147. av_log(avctx, AV_LOG_ERROR, "Failed to create program: %d.\n", cle);
  148. return AVERROR(EIO);
  149. }
  150. cle = clBuildProgram(ctx->program, 1, &ctx->hwctx->device_id,
  151. NULL, NULL, NULL);
  152. if (cle != CL_SUCCESS) {
  153. av_log(avctx, AV_LOG_ERROR, "Failed to build program: %d.\n", cle);
  154. if (cle == CL_BUILD_PROGRAM_FAILURE) {
  155. char *log;
  156. size_t log_length;
  157. clGetProgramBuildInfo(ctx->program, ctx->hwctx->device_id,
  158. CL_PROGRAM_BUILD_LOG, 0, NULL, &log_length);
  159. log = av_malloc(log_length);
  160. if (log) {
  161. cle = clGetProgramBuildInfo(ctx->program,
  162. ctx->hwctx->device_id,
  163. CL_PROGRAM_BUILD_LOG,
  164. log_length, log, NULL);
  165. if (cle == CL_SUCCESS)
  166. av_log(avctx, AV_LOG_ERROR, "Build log:\n%s\n", log);
  167. }
  168. av_free(log);
  169. }
  170. clReleaseProgram(ctx->program);
  171. ctx->program = NULL;
  172. return AVERROR(EIO);
  173. }
  174. return 0;
  175. }
  176. int ff_opencl_filter_load_program_from_file(AVFilterContext *avctx,
  177. const char *filename)
  178. {
  179. FILE *file;
  180. char *src = NULL;
  181. size_t pos, len, rb;
  182. const char *src_const;
  183. int err;
  184. file = fopen(filename, "r");
  185. if (!file) {
  186. av_log(avctx, AV_LOG_ERROR, "Unable to open program "
  187. "source file \"%s\".\n", filename);
  188. return AVERROR(ENOENT);
  189. }
  190. len = 1 << 16;
  191. pos = 0;
  192. err = av_reallocp(&src, len);
  193. if (err < 0)
  194. goto fail;
  195. err = snprintf(src, len, "#line 1 \"%s\"\n", filename);
  196. if (err < 0) {
  197. err = AVERROR(errno);
  198. goto fail;
  199. }
  200. if (err > len / 2) {
  201. err = AVERROR(EINVAL);
  202. goto fail;
  203. }
  204. pos = err;
  205. while (1) {
  206. rb = fread(src + pos, 1, len - pos - 1, file);
  207. if (rb == 0 && ferror(file)) {
  208. err = AVERROR(EIO);
  209. goto fail;
  210. }
  211. pos += rb;
  212. if (pos < len)
  213. break;
  214. len <<= 1;
  215. err = av_reallocp(&src, len);
  216. if (err < 0)
  217. goto fail;
  218. }
  219. src[pos] = 0;
  220. src_const = src;
  221. err = ff_opencl_filter_load_program(avctx, &src_const, 1);
  222. fail:
  223. fclose(file);
  224. av_freep(&src);
  225. return err;
  226. }
  227. int ff_opencl_filter_work_size_from_image(AVFilterContext *avctx,
  228. size_t *work_size,
  229. AVFrame *frame, int plane,
  230. int block_alignment)
  231. {
  232. cl_mem image;
  233. cl_mem_object_type type;
  234. size_t width, height;
  235. cl_int cle;
  236. if (frame->format != AV_PIX_FMT_OPENCL) {
  237. av_log(avctx, AV_LOG_ERROR, "Invalid frame format %s, "
  238. "opencl required.\n", av_get_pix_fmt_name(frame->format));
  239. return AVERROR(EINVAL);
  240. }
  241. image = (cl_mem)frame->data[plane];
  242. if (!image) {
  243. av_log(avctx, AV_LOG_ERROR, "Plane %d required but not set.\n",
  244. plane);
  245. return AVERROR(EINVAL);
  246. }
  247. cle = clGetMemObjectInfo(image, CL_MEM_TYPE, sizeof(type),
  248. &type, NULL);
  249. if (cle != CL_SUCCESS) {
  250. av_log(avctx, AV_LOG_ERROR, "Failed to query object type of "
  251. "plane %d: %d.\n", plane, cle);
  252. return AVERROR_UNKNOWN;
  253. }
  254. if (type != CL_MEM_OBJECT_IMAGE2D) {
  255. av_log(avctx, AV_LOG_ERROR, "Plane %d is not a 2D image.\n",
  256. plane);
  257. return AVERROR(EINVAL);
  258. }
  259. cle = clGetImageInfo(image, CL_IMAGE_WIDTH, sizeof(size_t),
  260. &width, NULL);
  261. if (cle != CL_SUCCESS) {
  262. av_log(avctx, AV_LOG_ERROR, "Failed to query plane %d width: %d.\n",
  263. plane, cle);
  264. return AVERROR_UNKNOWN;
  265. }
  266. cle = clGetImageInfo(image, CL_IMAGE_HEIGHT, sizeof(size_t),
  267. &height, NULL);
  268. if (cle != CL_SUCCESS) {
  269. av_log(avctx, AV_LOG_ERROR, "Failed to query plane %d height: %d.\n",
  270. plane, cle);
  271. return AVERROR_UNKNOWN;
  272. }
  273. if (block_alignment) {
  274. width = FFALIGN(width, block_alignment);
  275. height = FFALIGN(height, block_alignment);
  276. }
  277. work_size[0] = width;
  278. work_size[1] = height;
  279. return 0;
  280. }
  281. void ff_opencl_print_const_matrix_3x3(AVBPrint *buf, const char *name_str,
  282. double mat[3][3])
  283. {
  284. int i, j;
  285. av_bprintf(buf, "__constant float %s[9] = {\n", name_str);
  286. for (i = 0; i < 3; i++) {
  287. for (j = 0; j < 3; j++)
  288. av_bprintf(buf, " %.5ff,", mat[i][j]);
  289. av_bprintf(buf, "\n");
  290. }
  291. av_bprintf(buf, "};\n");
  292. }