graphics-ffmpeg.c 21 KB

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