graphics-ffmpeg.c 21 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. AVCodec *const decoder = avcodec_find_decoder(codecpar->codec_id);
  36. #else
  37. AVCodecContext *const decoder_ctx = stream->codec;
  38. AVCodec *const decoder = avcodec_find_decoder(decoder_ctx->codec_id);
  39. #endif
  40. if (!decoder) {
  41. blog(LOG_WARNING, "Failed to find decoder for file '%s'",
  42. info->file);
  43. return false;
  44. }
  45. #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
  46. AVCodecContext *const decoder_ctx = avcodec_alloc_context3(decoder);
  47. avcodec_parameters_to_context(decoder_ctx, codecpar);
  48. #endif
  49. info->decoder_ctx = decoder_ctx;
  50. #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
  51. info->cx = codecpar->width;
  52. info->cy = codecpar->height;
  53. info->format = codecpar->format;
  54. #else
  55. info->cx = decoder_ctx->width;
  56. info->cy = decoder_ctx->height;
  57. info->format = decoder_ctx->pix_fmt;
  58. #endif
  59. ret = avcodec_open2(decoder_ctx, decoder, NULL);
  60. if (ret < 0) {
  61. blog(LOG_WARNING,
  62. "Failed to open video codec for file '%s': "
  63. "%s",
  64. info->file, av_err2str(ret));
  65. return false;
  66. }
  67. return true;
  68. }
  69. static void ffmpeg_image_free(struct ffmpeg_image *info)
  70. {
  71. avcodec_free_context(&info->decoder_ctx);
  72. avformat_close_input(&info->fmt_ctx);
  73. }
  74. static bool ffmpeg_image_init(struct ffmpeg_image *info, const char *file)
  75. {
  76. int ret;
  77. if (!file || !*file)
  78. return false;
  79. memset(info, 0, sizeof(struct ffmpeg_image));
  80. info->file = file;
  81. ret = avformat_open_input(&info->fmt_ctx, file, NULL, NULL);
  82. if (ret < 0) {
  83. blog(LOG_WARNING, "Failed to open file '%s': %s", info->file,
  84. av_err2str(ret));
  85. return false;
  86. }
  87. ret = avformat_find_stream_info(info->fmt_ctx, NULL);
  88. if (ret < 0) {
  89. blog(LOG_WARNING,
  90. "Could not find stream info for file '%s':"
  91. " %s",
  92. info->file, av_err2str(ret));
  93. goto fail;
  94. }
  95. if (!ffmpeg_image_open_decoder_context(info))
  96. goto fail;
  97. return true;
  98. fail:
  99. ffmpeg_image_free(info);
  100. return false;
  101. }
  102. #ifdef _MSC_VER
  103. #define obs_bswap16(v) _byteswap_ushort(v)
  104. #else
  105. #define obs_bswap16(v) __builtin_bswap16(v)
  106. #endif
  107. static void *ffmpeg_image_copy_data_straight(struct ffmpeg_image *info,
  108. AVFrame *frame)
  109. {
  110. const size_t linesize = (size_t)info->cx * 4;
  111. const size_t totalsize = info->cy * linesize;
  112. void *data = bmalloc(totalsize);
  113. const size_t src_linesize = frame->linesize[0];
  114. if (linesize != src_linesize) {
  115. const size_t min_line = linesize < src_linesize ? linesize
  116. : src_linesize;
  117. uint8_t *dst = data;
  118. const uint8_t *src = frame->data[0];
  119. for (int y = 0; y < info->cy; y++) {
  120. memcpy(dst, src, min_line);
  121. dst += linesize;
  122. src += src_linesize;
  123. }
  124. } else {
  125. memcpy(data, frame->data[0], totalsize);
  126. }
  127. return data;
  128. }
  129. static inline size_t get_dst_position(size_t src, const size_t w,
  130. const size_t h, const size_t x,
  131. const size_t y, int orient)
  132. {
  133. size_t res_x = 0;
  134. size_t res_y = 0;
  135. if (orient == 2) {
  136. /*
  137. * Orientation 2: Flip X
  138. *
  139. * 888888 888888
  140. * 88 -> 88
  141. * 8888 -> 8888
  142. * 88 -> 88
  143. * 88 88
  144. *
  145. * (0, 0) -> (w, 0)
  146. * (0, h) -> (w, h)
  147. * (w, 0) -> (0, 0)
  148. * (w, h) -> (0, h)
  149. *
  150. * (w - x, y)
  151. */
  152. res_x = w - 1 - x;
  153. res_y = y;
  154. } else if (orient == 3) {
  155. /*
  156. * Orientation 3: 180°
  157. *
  158. * 88 888888
  159. * 88 -> 88
  160. * 8888 -> 8888
  161. * 88 -> 88
  162. * 888888 88
  163. *
  164. * (0, 0) -> (w, h)
  165. * (0, h) -> (w, 0)
  166. * (w, 0) -> (0, h)
  167. * (w, h) -> (0, 0)
  168. *
  169. * (w - x, h - y)
  170. */
  171. res_x = w - 1 - x;
  172. res_y = h - 1 - y;
  173. } else if (orient == 4) {
  174. /*
  175. * Orientation 4: Flip Y
  176. *
  177. * 88 888888
  178. * 88 -> 88
  179. * 8888 -> 8888
  180. * 88 -> 88
  181. * 888888 88
  182. *
  183. * (0, 0) -> (0, h)
  184. * (0, h) -> (0, 0)
  185. * (w, 0) -> (w, h)
  186. * (w, h) -> (w, 0)
  187. *
  188. * (x, h - y)
  189. */
  190. res_x = x;
  191. res_y = h - 1 - y;
  192. } else if (orient == 5) {
  193. /*
  194. * Orientation 5: Flip Y + 90° CW
  195. *
  196. * 8888888888 888888
  197. * 88 88 -> 88
  198. * 88 -> 8888
  199. * -> 88
  200. * 88
  201. *
  202. * (0, 0) -> (0, 0)
  203. * (0, h) -> (w, 0)
  204. * (w, 0) -> (0, h)
  205. * (w, h) -> (w, h)
  206. *
  207. * (y, x)
  208. */
  209. res_x = y;
  210. res_y = x;
  211. } else if (orient == 6) {
  212. /*
  213. * Orientation 6: 90° CW
  214. *
  215. * 88 888888
  216. * 88 88 -> 88
  217. * 8888888888 -> 8888
  218. * -> 88
  219. * 88
  220. *
  221. * (0, 0) -> (w, 0)
  222. * (0, h) -> (0, 0)
  223. * (w, 0) -> (w, h)
  224. * (w, h) -> (0, h)
  225. *
  226. * (w - y, x)
  227. */
  228. res_x = w - 1 - y;
  229. res_y = x;
  230. } else if (orient == 7) {
  231. /*
  232. * Orientation 7: Flip Y + 90° CCW
  233. *
  234. * 88 888888
  235. * 88 88 -> 88
  236. * 8888888888 -> 8888
  237. * -> 88
  238. * 88
  239. *
  240. * (0, 0) -> (w, h)
  241. * (0, h) -> (0, h)
  242. * (w, 0) -> (w, 0)
  243. * (w, h) -> (0, 0)
  244. *
  245. * (w - y, h - x)
  246. */
  247. res_x = w - 1 - y;
  248. res_y = h - 1 - x;
  249. } else if (orient == 8) {
  250. /*
  251. * Orientation 8: 90° CCW
  252. *
  253. * 8888888888 888888
  254. * 88 88 -> 88
  255. * 88 -> 8888
  256. * -> 88
  257. * 88
  258. *
  259. * (0, 0) -> (0, h)
  260. * (0, h) -> (w, h)
  261. * (w, 0) -> (0, 0)
  262. * (w, h) -> (w, 0)
  263. *
  264. * (y, h - x)
  265. */
  266. res_x = y;
  267. res_y = h - 1 - x;
  268. }
  269. return (res_x + res_y * w) * 4;
  270. }
  271. #define TILE_SIZE 16
  272. #define MIN(a, b) (((a) < (b)) ? (a) : (b))
  273. static void *ffmpeg_image_orient(struct ffmpeg_image *info, void *in_data,
  274. int orient)
  275. {
  276. const size_t sx = (size_t)info->cx;
  277. const size_t sy = (size_t)info->cy;
  278. uint8_t *data = NULL;
  279. if (orient == 0 || orient == 1)
  280. return in_data;
  281. data = bmalloc(sx * 4 * sy);
  282. if (orient >= 5 && orient < 9) {
  283. info->cx = (int)sy;
  284. info->cy = (int)sx;
  285. }
  286. uint8_t *src = in_data;
  287. size_t off_dst;
  288. size_t off_src = 0;
  289. for (size_t y0 = 0; y0 < sy; y0 += TILE_SIZE) {
  290. for (size_t x0 = 0; x0 < sx; x0 += TILE_SIZE) {
  291. size_t lim_x = MIN((size_t)sx, x0 + TILE_SIZE);
  292. size_t lim_y = MIN((size_t)sy, y0 + TILE_SIZE);
  293. for (size_t y = y0; y < lim_y; y++) {
  294. for (size_t x = x0; x < lim_x; x++) {
  295. off_src = (x + y * sx) * 4;
  296. off_dst = get_dst_position(off_src,
  297. 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 ((int)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.6604910f * red2020 -
  593. 0.5876411f * green2020 -
  594. 0.0728499f * blue2020;
  595. const float green709 = -0.1245505f * red2020 +
  596. 1.1328999f * green2020 -
  597. 0.0083494f * blue2020;
  598. const float blue709 = -0.0181508f * red2020 -
  599. 0.1005789f * green2020 +
  600. 1.1187297f * 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. }