graphics-ffmpeg.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  1. #include "graphics.h"
  2. #include "half.h"
  3. #include "srgb.h"
  4. #include <obs-ffmpeg-compat.h>
  5. #include <util/dstr.h>
  6. #include <util/platform.h>
  7. #include <libavcodec/avcodec.h>
  8. #include <libavformat/avformat.h>
  9. #include <libavutil/imgutils.h>
  10. #include <libswscale/swscale.h>
  11. #ifdef _WIN32
  12. #include <wincodec.h>
  13. #pragma comment(lib, "windowscodecs.lib")
  14. #endif
  15. struct ffmpeg_image {
  16. const char *file;
  17. AVFormatContext *fmt_ctx;
  18. AVCodecContext *decoder_ctx;
  19. int cx, cy;
  20. enum AVPixelFormat format;
  21. };
  22. static bool ffmpeg_image_open_decoder_context(struct ffmpeg_image *info)
  23. {
  24. AVFormatContext *const fmt_ctx = info->fmt_ctx;
  25. int ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, 1, NULL, 0);
  26. if (ret < 0) {
  27. blog(LOG_WARNING, "Couldn't find video stream in file '%s': %s", info->file, av_err2str(ret));
  28. return false;
  29. }
  30. AVStream *const stream = fmt_ctx->streams[ret];
  31. AVCodecParameters *const codecpar = stream->codecpar;
  32. const AVCodec *const decoder = avcodec_find_decoder(codecpar->codec_id); // fix discarded-qualifiers
  33. if (!decoder) {
  34. blog(LOG_WARNING, "Failed to find decoder for file '%s'", info->file);
  35. return false;
  36. }
  37. AVCodecContext *const decoder_ctx = avcodec_alloc_context3(decoder);
  38. avcodec_parameters_to_context(decoder_ctx, codecpar);
  39. info->decoder_ctx = decoder_ctx;
  40. info->cx = codecpar->width;
  41. info->cy = codecpar->height;
  42. info->format = codecpar->format;
  43. ret = avcodec_open2(decoder_ctx, decoder, NULL);
  44. if (ret < 0) {
  45. blog(LOG_WARNING,
  46. "Failed to open video codec for file '%s': "
  47. "%s",
  48. info->file, av_err2str(ret));
  49. return false;
  50. }
  51. return true;
  52. }
  53. static void ffmpeg_image_free(struct ffmpeg_image *info)
  54. {
  55. avcodec_free_context(&info->decoder_ctx);
  56. avformat_close_input(&info->fmt_ctx);
  57. }
  58. static bool ffmpeg_image_init(struct ffmpeg_image *info, const char *file)
  59. {
  60. int ret;
  61. if (!file || !*file)
  62. return false;
  63. memset(info, 0, sizeof(struct ffmpeg_image));
  64. info->file = file;
  65. ret = avformat_open_input(&info->fmt_ctx, file, NULL, NULL);
  66. if (ret < 0) {
  67. blog(LOG_WARNING, "Failed to open file '%s': %s", info->file, av_err2str(ret));
  68. return false;
  69. }
  70. ret = avformat_find_stream_info(info->fmt_ctx, NULL);
  71. if (ret < 0) {
  72. blog(LOG_WARNING,
  73. "Could not find stream info for file '%s':"
  74. " %s",
  75. info->file, av_err2str(ret));
  76. goto fail;
  77. }
  78. if (!ffmpeg_image_open_decoder_context(info))
  79. goto fail;
  80. return true;
  81. fail:
  82. ffmpeg_image_free(info);
  83. return false;
  84. }
  85. #ifdef _MSC_VER
  86. #define obs_bswap16(v) _byteswap_ushort(v)
  87. #else
  88. #define obs_bswap16(v) __builtin_bswap16(v)
  89. #endif
  90. static void *ffmpeg_image_copy_data_straight(struct ffmpeg_image *info, AVFrame *frame)
  91. {
  92. const size_t linesize = (size_t)info->cx * 4;
  93. const size_t totalsize = info->cy * linesize;
  94. void *data = bmalloc(totalsize);
  95. const size_t src_linesize = frame->linesize[0];
  96. if (linesize != src_linesize) {
  97. const size_t min_line = linesize < src_linesize ? linesize : src_linesize;
  98. uint8_t *dst = data;
  99. const uint8_t *src = frame->data[0];
  100. for (int y = 0; y < info->cy; y++) {
  101. memcpy(dst, src, min_line);
  102. dst += linesize;
  103. src += src_linesize;
  104. }
  105. } else {
  106. memcpy(data, frame->data[0], totalsize);
  107. }
  108. return data;
  109. }
  110. static inline size_t get_dst_position(const size_t w, const size_t h, const size_t x, const size_t y, int orient)
  111. {
  112. size_t res_x = 0;
  113. size_t res_y = 0;
  114. if (orient == 2) {
  115. /*
  116. * Orientation 2: Flip X
  117. *
  118. * 888888 888888
  119. * 88 -> 88
  120. * 8888 -> 8888
  121. * 88 -> 88
  122. * 88 88
  123. *
  124. * (0, 0) -> (w, 0)
  125. * (0, h) -> (w, h)
  126. * (w, 0) -> (0, 0)
  127. * (w, h) -> (0, h)
  128. *
  129. * (w - x, y)
  130. */
  131. res_x = w - 1 - x;
  132. res_y = y;
  133. } else if (orient == 3) {
  134. /*
  135. * Orientation 3: 180 degree
  136. *
  137. * 88 888888
  138. * 88 -> 88
  139. * 8888 -> 8888
  140. * 88 -> 88
  141. * 888888 88
  142. *
  143. * (0, 0) -> (w, h)
  144. * (0, h) -> (w, 0)
  145. * (w, 0) -> (0, h)
  146. * (w, h) -> (0, 0)
  147. *
  148. * (w - x, h - y)
  149. */
  150. res_x = w - 1 - x;
  151. res_y = h - 1 - y;
  152. } else if (orient == 4) {
  153. /*
  154. * Orientation 4: Flip Y
  155. *
  156. * 88 888888
  157. * 88 -> 88
  158. * 8888 -> 8888
  159. * 88 -> 88
  160. * 888888 88
  161. *
  162. * (0, 0) -> (0, h)
  163. * (0, h) -> (0, 0)
  164. * (w, 0) -> (w, h)
  165. * (w, h) -> (w, 0)
  166. *
  167. * (x, h - y)
  168. */
  169. res_x = x;
  170. res_y = h - 1 - y;
  171. } else if (orient == 5) {
  172. /*
  173. * Orientation 5: Flip Y + 90 degree CW
  174. *
  175. * 8888888888 888888
  176. * 88 88 -> 88
  177. * 88 -> 8888
  178. * -> 88
  179. * 88
  180. *
  181. * (0, 0) -> (0, 0)
  182. * (0, h) -> (w, 0)
  183. * (w, 0) -> (0, h)
  184. * (w, h) -> (w, h)
  185. *
  186. * (y, x)
  187. */
  188. res_x = y;
  189. res_y = x;
  190. } else if (orient == 6) {
  191. /*
  192. * Orientation 6: 90 degree CW
  193. *
  194. * 88 888888
  195. * 88 88 -> 88
  196. * 8888888888 -> 8888
  197. * -> 88
  198. * 88
  199. *
  200. * (0, 0) -> (w, 0)
  201. * (0, h) -> (0, 0)
  202. * (w, 0) -> (w, h)
  203. * (w, h) -> (0, h)
  204. *
  205. * (w - y, x)
  206. */
  207. res_x = w - 1 - y;
  208. res_y = x;
  209. } else if (orient == 7) {
  210. /*
  211. * Orientation 7: Flip Y + 90 degree CCW
  212. *
  213. * 88 888888
  214. * 88 88 -> 88
  215. * 8888888888 -> 8888
  216. * -> 88
  217. * 88
  218. *
  219. * (0, 0) -> (w, h)
  220. * (0, h) -> (0, h)
  221. * (w, 0) -> (w, 0)
  222. * (w, h) -> (0, 0)
  223. *
  224. * (w - y, h - x)
  225. */
  226. res_x = w - 1 - y;
  227. res_y = h - 1 - x;
  228. } else if (orient == 8) {
  229. /*
  230. * Orientation 8: 90 degree CCW
  231. *
  232. * 8888888888 888888
  233. * 88 88 -> 88
  234. * 88 -> 8888
  235. * -> 88
  236. * 88
  237. *
  238. * (0, 0) -> (0, h)
  239. * (0, h) -> (w, h)
  240. * (w, 0) -> (0, 0)
  241. * (w, h) -> (w, 0)
  242. *
  243. * (y, h - x)
  244. */
  245. res_x = y;
  246. res_y = h - 1 - x;
  247. }
  248. return (res_x + res_y * w) * 4;
  249. }
  250. #define TILE_SIZE 16
  251. #define MIN(a, b) (((a) < (b)) ? (a) : (b))
  252. static void *ffmpeg_image_orient(struct ffmpeg_image *info, void *in_data, int orient)
  253. {
  254. const size_t sx = (size_t)info->cx;
  255. const size_t sy = (size_t)info->cy;
  256. uint8_t *data = NULL;
  257. if (orient == 0 || orient == 1)
  258. return in_data;
  259. data = bmalloc(sx * 4 * sy);
  260. if (orient >= 5 && orient < 9) {
  261. info->cx = (int)sy;
  262. info->cy = (int)sx;
  263. }
  264. uint8_t *src = in_data;
  265. size_t off_dst;
  266. size_t off_src = 0;
  267. for (size_t y0 = 0; y0 < sy; y0 += TILE_SIZE) {
  268. for (size_t x0 = 0; x0 < sx; x0 += TILE_SIZE) {
  269. size_t lim_x = MIN((size_t)sx, x0 + TILE_SIZE);
  270. size_t lim_y = MIN((size_t)sy, y0 + TILE_SIZE);
  271. for (size_t y = y0; y < lim_y; y++) {
  272. for (size_t x = x0; x < lim_x; x++) {
  273. off_src = (x + y * sx) * 4;
  274. off_dst = get_dst_position(info->cx, info->cy, x, y, orient);
  275. memcpy(data + off_dst, src + off_src, 4);
  276. }
  277. }
  278. }
  279. }
  280. bfree(in_data);
  281. return data;
  282. }
  283. static void *ffmpeg_image_reformat_frame(struct ffmpeg_image *info, AVFrame *frame, enum gs_image_alpha_mode alpha_mode)
  284. {
  285. struct SwsContext *sws_ctx = NULL;
  286. void *data = NULL;
  287. int ret = 0;
  288. AVDictionary *dict = frame->metadata;
  289. AVDictionaryEntry *entry = NULL;
  290. int orient = 0;
  291. if (dict) {
  292. entry = av_dict_get(dict, "Orientation", NULL, AV_DICT_MATCH_CASE);
  293. if (entry && entry->value) {
  294. orient = atoi(entry->value);
  295. }
  296. }
  297. if (info->format == AV_PIX_FMT_BGR0) {
  298. data = ffmpeg_image_copy_data_straight(info, frame);
  299. } else if (info->format == AV_PIX_FMT_RGBA || info->format == AV_PIX_FMT_BGRA) {
  300. if (alpha_mode == GS_IMAGE_ALPHA_STRAIGHT) {
  301. data = ffmpeg_image_copy_data_straight(info, frame);
  302. } else {
  303. const size_t linesize = (size_t)info->cx * 4;
  304. const size_t totalsize = info->cy * linesize;
  305. data = bmalloc(totalsize);
  306. const size_t src_linesize = frame->linesize[0];
  307. const size_t min_line = linesize < src_linesize ? linesize : src_linesize;
  308. uint8_t *dst = data;
  309. const uint8_t *src = frame->data[0];
  310. const size_t row_elements = min_line >> 2;
  311. if (alpha_mode == GS_IMAGE_ALPHA_PREMULTIPLY_SRGB) {
  312. for (int y = 0; y < info->cy; y++) {
  313. gs_premultiply_xyza_srgb_loop_restrict(dst, src, row_elements);
  314. dst += linesize;
  315. src += src_linesize;
  316. }
  317. } else if (alpha_mode == GS_IMAGE_ALPHA_PREMULTIPLY) {
  318. for (int y = 0; y < info->cy; y++) {
  319. gs_premultiply_xyza_loop_restrict(dst, src, row_elements);
  320. dst += linesize;
  321. src += src_linesize;
  322. }
  323. }
  324. }
  325. } else if (info->format == AV_PIX_FMT_RGBA64BE) {
  326. const size_t dst_linesize = (size_t)info->cx * 4;
  327. data = bmalloc(info->cy * dst_linesize);
  328. const size_t src_linesize = frame->linesize[0];
  329. const size_t src_min_line = (dst_linesize * 2) < src_linesize ? (dst_linesize * 2) : src_linesize;
  330. const size_t row_elements = src_min_line >> 3;
  331. uint8_t *dst = data;
  332. const uint8_t *src = frame->data[0];
  333. uint16_t value[4];
  334. float f[4];
  335. if (alpha_mode == GS_IMAGE_ALPHA_STRAIGHT) {
  336. for (int y = 0; y < info->cy; y++) {
  337. for (size_t x = 0; x < row_elements; ++x) {
  338. memcpy(value, src, sizeof(value));
  339. f[0] = (float)obs_bswap16(value[0]) / 65535.0f;
  340. f[1] = (float)obs_bswap16(value[1]) / 65535.0f;
  341. f[2] = (float)obs_bswap16(value[2]) / 65535.0f;
  342. f[3] = (float)obs_bswap16(value[3]) / 65535.0f;
  343. gs_float4_to_u8x4(dst, f);
  344. dst += sizeof(*dst) * 4;
  345. src += sizeof(value);
  346. }
  347. src += src_linesize - src_min_line;
  348. }
  349. } else if (alpha_mode == GS_IMAGE_ALPHA_PREMULTIPLY_SRGB) {
  350. for (int y = 0; y < info->cy; y++) {
  351. for (size_t x = 0; x < row_elements; ++x) {
  352. memcpy(value, src, sizeof(value));
  353. f[0] = (float)obs_bswap16(value[0]) / 65535.0f;
  354. f[1] = (float)obs_bswap16(value[1]) / 65535.0f;
  355. f[2] = (float)obs_bswap16(value[2]) / 65535.0f;
  356. f[3] = (float)obs_bswap16(value[3]) / 65535.0f;
  357. gs_float3_srgb_nonlinear_to_linear(f);
  358. gs_premultiply_float4(f);
  359. gs_float3_srgb_linear_to_nonlinear(f);
  360. gs_float4_to_u8x4(dst, f);
  361. dst += sizeof(*dst) * 4;
  362. src += sizeof(value);
  363. }
  364. src += src_linesize - src_min_line;
  365. }
  366. } else if (alpha_mode == GS_IMAGE_ALPHA_PREMULTIPLY) {
  367. for (int y = 0; y < info->cy; y++) {
  368. for (size_t x = 0; x < row_elements; ++x) {
  369. memcpy(value, src, sizeof(value));
  370. f[0] = (float)obs_bswap16(value[0]) / 65535.0f;
  371. f[1] = (float)obs_bswap16(value[1]) / 65535.0f;
  372. f[2] = (float)obs_bswap16(value[2]) / 65535.0f;
  373. f[3] = (float)obs_bswap16(value[3]) / 65535.0f;
  374. gs_premultiply_float4(f);
  375. gs_float4_to_u8x4(dst, f);
  376. dst += sizeof(*dst) * 4;
  377. src += sizeof(value);
  378. }
  379. src += src_linesize - src_min_line;
  380. }
  381. }
  382. info->format = AV_PIX_FMT_RGBA;
  383. } else {
  384. static const enum AVPixelFormat format = AV_PIX_FMT_BGRA;
  385. sws_ctx = sws_getContext(info->cx, info->cy, info->format, info->cx, info->cy, format, SWS_POINT, NULL,
  386. NULL, NULL);
  387. if (!sws_ctx) {
  388. blog(LOG_WARNING,
  389. "Failed to create scale context "
  390. "for '%s'",
  391. info->file);
  392. goto fail;
  393. }
  394. uint8_t *pointers[4];
  395. int linesizes[4];
  396. ret = av_image_alloc(pointers, linesizes, info->cx, info->cy, format, 32);
  397. if (ret < 0) {
  398. blog(LOG_WARNING, "av_image_alloc failed for '%s': %s", info->file, av_err2str(ret));
  399. sws_freeContext(sws_ctx);
  400. goto fail;
  401. }
  402. ret = sws_scale(sws_ctx, (const uint8_t *const *)frame->data, frame->linesize, 0, info->cy, pointers,
  403. linesizes);
  404. sws_freeContext(sws_ctx);
  405. if (ret < 0) {
  406. blog(LOG_WARNING, "sws_scale failed for '%s': %s", info->file, av_err2str(ret));
  407. av_freep(pointers);
  408. goto fail;
  409. }
  410. const size_t linesize = (size_t)info->cx * 4;
  411. data = bmalloc(info->cy * linesize);
  412. const uint8_t *src = pointers[0];
  413. uint8_t *dst = data;
  414. for (size_t y = 0; y < (size_t)info->cy; y++) {
  415. memcpy(dst, src, linesize);
  416. dst += linesize;
  417. src += linesizes[0];
  418. }
  419. av_freep(pointers);
  420. if (alpha_mode == GS_IMAGE_ALPHA_PREMULTIPLY_SRGB) {
  421. gs_premultiply_xyza_srgb_loop(data, (size_t)info->cx * info->cy);
  422. } else if (alpha_mode == GS_IMAGE_ALPHA_PREMULTIPLY) {
  423. gs_premultiply_xyza_loop(data, (size_t)info->cx * info->cy);
  424. }
  425. info->format = format;
  426. }
  427. data = ffmpeg_image_orient(info, data, orient);
  428. fail:
  429. return data;
  430. }
  431. static void *ffmpeg_image_decode(struct ffmpeg_image *info, enum gs_image_alpha_mode alpha_mode)
  432. {
  433. AVPacket packet = {0};
  434. void *data = NULL;
  435. AVFrame *frame = av_frame_alloc();
  436. int got_frame = 0;
  437. int ret;
  438. if (!frame) {
  439. blog(LOG_WARNING, "Failed to create frame data for '%s'", info->file);
  440. return NULL;
  441. }
  442. ret = av_read_frame(info->fmt_ctx, &packet);
  443. if (ret < 0) {
  444. blog(LOG_WARNING, "Failed to read image frame from '%s': %s", info->file, av_err2str(ret));
  445. goto fail;
  446. }
  447. while (!got_frame) {
  448. ret = avcodec_send_packet(info->decoder_ctx, &packet);
  449. if (ret == 0)
  450. ret = avcodec_receive_frame(info->decoder_ctx, frame);
  451. got_frame = (ret == 0);
  452. if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
  453. ret = 0;
  454. if (ret < 0) {
  455. blog(LOG_WARNING, "Failed to decode frame for '%s': %s", info->file, av_err2str(ret));
  456. goto fail;
  457. }
  458. }
  459. data = ffmpeg_image_reformat_frame(info, frame, alpha_mode);
  460. fail:
  461. av_packet_unref(&packet);
  462. av_frame_free(&frame);
  463. return data;
  464. }
  465. void gs_init_image_deps(void) {}
  466. void gs_free_image_deps(void) {}
  467. static inline enum gs_color_format convert_format(enum AVPixelFormat format)
  468. {
  469. switch (format) {
  470. case AV_PIX_FMT_RGBA:
  471. return GS_RGBA;
  472. case AV_PIX_FMT_BGRA:
  473. return GS_BGRA;
  474. case AV_PIX_FMT_BGR0:
  475. return GS_BGRX;
  476. case AV_PIX_FMT_RGBA64BE:
  477. return GS_RGBA16;
  478. default:
  479. return GS_BGRX;
  480. }
  481. }
  482. uint8_t *gs_create_texture_file_data(const char *file, enum gs_color_format *format, uint32_t *cx_out, uint32_t *cy_out)
  483. {
  484. struct ffmpeg_image image;
  485. uint8_t *data = NULL;
  486. if (ffmpeg_image_init(&image, file)) {
  487. data = ffmpeg_image_decode(&image, GS_IMAGE_ALPHA_STRAIGHT);
  488. if (data) {
  489. *format = convert_format(image.format);
  490. *cx_out = (uint32_t)image.cx;
  491. *cy_out = (uint32_t)image.cy;
  492. }
  493. ffmpeg_image_free(&image);
  494. }
  495. return data;
  496. }
  497. #ifdef _WIN32
  498. static float pq_to_linear(float u)
  499. {
  500. const float common = powf(u, 1.f / 78.84375f);
  501. return powf(fabsf(max(common - 0.8359375f, 0.f) / (18.8515625f - 18.6875f * common)), 1.f / 0.1593017578f);
  502. }
  503. static void convert_pq_to_cccs(const BYTE *intermediate, const UINT intermediate_size, BYTE *bytes)
  504. {
  505. const BYTE *src_cursor = intermediate;
  506. const BYTE *src_cursor_end = src_cursor + intermediate_size;
  507. BYTE *dst_cursor = bytes;
  508. uint32_t rgb10;
  509. struct half rgba16[4];
  510. rgba16[3].u = 0x3c00;
  511. while (src_cursor < src_cursor_end) {
  512. memcpy(&rgb10, src_cursor, sizeof(rgb10));
  513. const float blue = (float)(rgb10 & 0x3ff) / 1023.f;
  514. const float green = (float)((rgb10 >> 10) & 0x3ff) / 1023.f;
  515. const float red = (float)((rgb10 >> 20) & 0x3ff) / 1023.f;
  516. const float red2020 = pq_to_linear(red);
  517. const float green2020 = pq_to_linear(green);
  518. const float blue2020 = pq_to_linear(blue);
  519. const float red709 = 1.6604910021084345f * red2020 - 0.58764113878854951f * green2020 -
  520. 0.072849863319884883f * blue2020;
  521. const float green709 = -0.12455047452159074f * red2020 + 1.1328998971259603f * green2020 -
  522. 0.0083494226043694768f * blue2020;
  523. const float blue709 = -0.018150763354905303f * red2020 - 0.10057889800800739f * green2020 +
  524. 1.1187296613629127f * blue2020;
  525. rgba16[0] = half_from_float(red709 * 125.f);
  526. rgba16[1] = half_from_float(green709 * 125.f);
  527. rgba16[2] = half_from_float(blue709 * 125.f);
  528. memcpy(dst_cursor, &rgba16, sizeof(rgba16));
  529. src_cursor += 4;
  530. dst_cursor += 8;
  531. }
  532. }
  533. static void *wic_image_init_internal(const char *file, IWICBitmapFrameDecode *pFrame, enum gs_color_format *format,
  534. uint32_t *cx_out, uint32_t *cy_out, enum gs_color_space *space)
  535. {
  536. BYTE *bytes = NULL;
  537. WICPixelFormatGUID pixelFormat;
  538. HRESULT hr = pFrame->lpVtbl->GetPixelFormat(pFrame, &pixelFormat);
  539. if (SUCCEEDED(hr)) {
  540. const bool scrgb = memcmp(&pixelFormat, &GUID_WICPixelFormat64bppRGBAHalf, sizeof(pixelFormat)) == 0;
  541. const bool pq10 = memcmp(&pixelFormat, &GUID_WICPixelFormat32bppBGR101010, sizeof(pixelFormat)) == 0;
  542. if (scrgb || pq10) {
  543. UINT width, height;
  544. hr = pFrame->lpVtbl->GetSize(pFrame, &width, &height);
  545. if (SUCCEEDED(hr)) {
  546. const UINT pitch = 8 * width;
  547. const UINT size = pitch * height;
  548. bytes = bmalloc(size);
  549. if (bytes) {
  550. bool success = false;
  551. if (pq10) {
  552. const UINT intermediate_pitch = 4 * width;
  553. const UINT intermediate_size = intermediate_pitch * height;
  554. BYTE *intermediate = bmalloc(intermediate_size);
  555. if (intermediate) {
  556. hr = pFrame->lpVtbl->CopyPixels(pFrame, NULL,
  557. intermediate_pitch,
  558. intermediate_size,
  559. intermediate);
  560. success = SUCCEEDED(hr);
  561. if (success) {
  562. convert_pq_to_cccs(intermediate, intermediate_size,
  563. bytes);
  564. } else {
  565. blog(LOG_WARNING,
  566. "WIC: Failed to CopyPixels intermediate for file: %s",
  567. file);
  568. }
  569. bfree(intermediate);
  570. } else {
  571. blog(LOG_WARNING,
  572. "WIC: Failed to allocate intermediate for file: %s", file);
  573. }
  574. } else {
  575. hr = pFrame->lpVtbl->CopyPixels(pFrame, NULL, pitch, size, bytes);
  576. success = SUCCEEDED(hr);
  577. if (!success) {
  578. blog(LOG_WARNING, "WIC: Failed to CopyPixels for file: %s",
  579. file);
  580. }
  581. }
  582. if (success) {
  583. *format = GS_RGBA16F;
  584. *cx_out = width;
  585. *cy_out = height;
  586. *space = GS_CS_709_SCRGB;
  587. } else {
  588. bfree(bytes);
  589. bytes = NULL;
  590. }
  591. } else {
  592. blog(LOG_WARNING, "WIC: Failed to allocate for file: %s", file);
  593. }
  594. } else {
  595. blog(LOG_WARNING, "WIC: Failed to GetSize of frame for file: %s", file);
  596. }
  597. } else {
  598. blog(LOG_WARNING,
  599. "WIC: Only handle GUID_WICPixelFormat32bppBGR101010 and GUID_WICPixelFormat64bppRGBAHalf for now");
  600. }
  601. } else {
  602. blog(LOG_WARNING, "WIC: Failed to GetPixelFormat for file: %s", file);
  603. }
  604. return bytes;
  605. }
  606. static void *wic_image_init(const struct ffmpeg_image *info, const char *file, enum gs_color_format *format,
  607. uint32_t *cx_out, uint32_t *cy_out, enum gs_color_space *space)
  608. {
  609. const size_t len = strlen(file);
  610. if (len <= 4 && astrcmpi(file + len - 4, ".jxr") != 0) {
  611. blog(LOG_WARNING, "WIC: Only handle JXR for WIC images for now");
  612. return NULL;
  613. }
  614. BYTE *bytes = NULL;
  615. wchar_t *file_w = NULL;
  616. os_utf8_to_wcs_ptr(file, 0, &file_w);
  617. if (file_w) {
  618. IWICImagingFactory *pFactory = NULL;
  619. HRESULT hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
  620. &IID_IWICImagingFactory, &pFactory);
  621. if (SUCCEEDED(hr)) {
  622. IWICBitmapDecoder *pDecoder = NULL;
  623. hr = pFactory->lpVtbl->CreateDecoderFromFilename(pFactory, file_w, NULL, GENERIC_READ,
  624. WICDecodeMetadataCacheOnDemand, &pDecoder);
  625. if (SUCCEEDED(hr)) {
  626. IWICBitmapFrameDecode *pFrame = NULL;
  627. hr = pDecoder->lpVtbl->GetFrame(pDecoder, 0, &pFrame);
  628. if (SUCCEEDED(hr)) {
  629. bytes = wic_image_init_internal(file, pFrame, format, cx_out, cy_out, space);
  630. pFrame->lpVtbl->Release(pFrame);
  631. } else {
  632. blog(LOG_WARNING, "WIC: Failed to create IWICBitmapFrameDecode from file: %s",
  633. file);
  634. }
  635. pDecoder->lpVtbl->Release(pDecoder);
  636. } else {
  637. blog(LOG_WARNING, "WIC: Failed to create IWICBitmapDecoder from file: %s", file);
  638. }
  639. pFactory->lpVtbl->Release(pFactory);
  640. } else {
  641. blog(LOG_WARNING, "WIC: Failed to create IWICImagingFactory");
  642. }
  643. bfree(file_w);
  644. } else {
  645. blog(LOG_WARNING, "WIC: Failed to widen file name: %s", file);
  646. }
  647. return bytes;
  648. }
  649. #endif
  650. uint8_t *gs_create_texture_file_data2(const char *file, enum gs_image_alpha_mode alpha_mode,
  651. enum gs_color_format *format, uint32_t *cx_out, uint32_t *cy_out)
  652. {
  653. enum gs_color_space unused;
  654. return gs_create_texture_file_data3(file, alpha_mode, format, cx_out, cy_out, &unused);
  655. }
  656. uint8_t *gs_create_texture_file_data3(const char *file, enum gs_image_alpha_mode alpha_mode,
  657. enum gs_color_format *format, uint32_t *cx_out, uint32_t *cy_out,
  658. enum gs_color_space *space)
  659. {
  660. struct ffmpeg_image image;
  661. uint8_t *data = NULL;
  662. if (ffmpeg_image_init(&image, file)) {
  663. data = ffmpeg_image_decode(&image, alpha_mode);
  664. if (data) {
  665. *format = convert_format(image.format);
  666. *cx_out = (uint32_t)image.cx;
  667. *cy_out = (uint32_t)image.cy;
  668. *space = GS_CS_SRGB;
  669. }
  670. ffmpeg_image_free(&image);
  671. }
  672. #ifdef _WIN32
  673. if (data == NULL) {
  674. data = wic_image_init(&image, file, format, cx_out, cy_out, space);
  675. }
  676. #endif
  677. return data;
  678. }