graphics-ffmpeg.c 22 KB

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