FFmpeg
dds.c
Go to the documentation of this file.
1 /*
2  * DirectDraw Surface image decoder
3  * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com>
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /**
23  * @file
24  * DDS decoder
25  *
26  * https://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx
27  */
28 
29 #include <stdint.h>
30 
31 #include "libavutil/libm.h"
32 #include "libavutil/imgutils.h"
33 
34 #include "avcodec.h"
35 #include "bytestream.h"
36 #include "internal.h"
37 #include "texturedsp.h"
38 #include "thread.h"
39 
40 #define DDPF_FOURCC (1 << 2)
41 #define DDPF_PALETTE (1 << 5)
42 #define DDPF_NORMALMAP (1U << 31)
43 
45  DDS_NONE = 0,
58 };
59 
67 
74 
97 };
98 
99 typedef struct DDSContext {
102 
104  int paletted;
105  int bpp;
107 
108  const uint8_t *tex_data; // Compressed texture
109  int tex_ratio; // Compression ratio
110  int slice_count; // Number of slices for threaded operations
111 
112  /* Pointer to the selected compress or decompress function. */
113  int (*tex_funct)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block);
114 } DDSContext;
115 
117 {
118  DDSContext *ctx = avctx->priv_data;
119  GetByteContext *gbc = &ctx->gbc;
120  uint32_t flags, fourcc, gimp_tag;
121  enum DDSDXGIFormat dxgi;
122  int size, bpp, r, g, b, a;
123  int alpha_exponent, ycocg_classic, ycocg_scaled, normal_map, array;
124 
125  /* Alternative DDS implementations use reserved1 as custom header. */
126  bytestream2_skip(gbc, 4 * 3);
127  gimp_tag = bytestream2_get_le32(gbc);
128  alpha_exponent = gimp_tag == MKTAG('A', 'E', 'X', 'P');
129  ycocg_classic = gimp_tag == MKTAG('Y', 'C', 'G', '1');
130  ycocg_scaled = gimp_tag == MKTAG('Y', 'C', 'G', '2');
131  bytestream2_skip(gbc, 4 * 7);
132 
133  /* Now the real DDPF starts. */
134  size = bytestream2_get_le32(gbc);
135  if (size != 32) {
136  av_log(avctx, AV_LOG_ERROR, "Invalid pixel format header %d.\n", size);
137  return AVERROR_INVALIDDATA;
138  }
139  flags = bytestream2_get_le32(gbc);
140  ctx->compressed = flags & DDPF_FOURCC;
141  ctx->paletted = flags & DDPF_PALETTE;
142  normal_map = flags & DDPF_NORMALMAP;
143  fourcc = bytestream2_get_le32(gbc);
144 
145  if (ctx->compressed && ctx->paletted) {
146  av_log(avctx, AV_LOG_WARNING,
147  "Disabling invalid palette flag for compressed dds.\n");
148  ctx->paletted = 0;
149  }
150 
151  bpp = ctx->bpp = bytestream2_get_le32(gbc); // rgbbitcount
152  r = bytestream2_get_le32(gbc); // rbitmask
153  g = bytestream2_get_le32(gbc); // gbitmask
154  b = bytestream2_get_le32(gbc); // bbitmask
155  a = bytestream2_get_le32(gbc); // abitmask
156 
157  bytestream2_skip(gbc, 4); // caps
158  bytestream2_skip(gbc, 4); // caps2
159  bytestream2_skip(gbc, 4); // caps3
160  bytestream2_skip(gbc, 4); // caps4
161  bytestream2_skip(gbc, 4); // reserved2
162 
163  av_log(avctx, AV_LOG_VERBOSE, "fourcc %s bpp %d "
164  "r 0x%x g 0x%x b 0x%x a 0x%x\n", av_fourcc2str(fourcc), bpp, r, g, b, a);
165  if (gimp_tag)
166  av_log(avctx, AV_LOG_VERBOSE, "and GIMP-DDS tag %s\n", av_fourcc2str(gimp_tag));
167 
168  if (ctx->compressed)
169  avctx->pix_fmt = AV_PIX_FMT_RGBA;
170 
171  if (ctx->compressed) {
172  switch (fourcc) {
173  case MKTAG('D', 'X', 'T', '1'):
174  ctx->tex_ratio = 8;
175  ctx->tex_funct = ctx->texdsp.dxt1a_block;
176  break;
177  case MKTAG('D', 'X', 'T', '2'):
178  ctx->tex_ratio = 16;
179  ctx->tex_funct = ctx->texdsp.dxt2_block;
180  break;
181  case MKTAG('D', 'X', 'T', '3'):
182  ctx->tex_ratio = 16;
183  ctx->tex_funct = ctx->texdsp.dxt3_block;
184  break;
185  case MKTAG('D', 'X', 'T', '4'):
186  ctx->tex_ratio = 16;
187  ctx->tex_funct = ctx->texdsp.dxt4_block;
188  break;
189  case MKTAG('D', 'X', 'T', '5'):
190  ctx->tex_ratio = 16;
191  if (ycocg_scaled)
192  ctx->tex_funct = ctx->texdsp.dxt5ys_block;
193  else if (ycocg_classic)
194  ctx->tex_funct = ctx->texdsp.dxt5y_block;
195  else
196  ctx->tex_funct = ctx->texdsp.dxt5_block;
197  break;
198  case MKTAG('R', 'X', 'G', 'B'):
199  ctx->tex_ratio = 16;
200  ctx->tex_funct = ctx->texdsp.dxt5_block;
201  /* This format may be considered as a normal map,
202  * but it is handled differently in a separate postproc. */
203  ctx->postproc = DDS_SWIZZLE_RXGB;
204  normal_map = 0;
205  break;
206  case MKTAG('A', 'T', 'I', '1'):
207  case MKTAG('B', 'C', '4', 'U'):
208  ctx->tex_ratio = 8;
209  ctx->tex_funct = ctx->texdsp.rgtc1u_block;
210  break;
211  case MKTAG('B', 'C', '4', 'S'):
212  ctx->tex_ratio = 8;
213  ctx->tex_funct = ctx->texdsp.rgtc1s_block;
214  break;
215  case MKTAG('A', 'T', 'I', '2'):
216  /* RGT2 variant with swapped R and G (3Dc)*/
217  ctx->tex_ratio = 16;
218  ctx->tex_funct = ctx->texdsp.dxn3dc_block;
219  break;
220  case MKTAG('B', 'C', '5', 'U'):
221  ctx->tex_ratio = 16;
222  ctx->tex_funct = ctx->texdsp.rgtc2u_block;
223  break;
224  case MKTAG('B', 'C', '5', 'S'):
225  ctx->tex_ratio = 16;
226  ctx->tex_funct = ctx->texdsp.rgtc2s_block;
227  break;
228  case MKTAG('U', 'Y', 'V', 'Y'):
229  ctx->compressed = 0;
230  avctx->pix_fmt = AV_PIX_FMT_UYVY422;
231  break;
232  case MKTAG('Y', 'U', 'Y', '2'):
233  ctx->compressed = 0;
234  avctx->pix_fmt = AV_PIX_FMT_YUYV422;
235  break;
236  case MKTAG('P', '8', ' ', ' '):
237  /* ATI Palette8, same as normal palette */
238  ctx->compressed = 0;
239  ctx->paletted = 1;
240  avctx->pix_fmt = AV_PIX_FMT_PAL8;
241  break;
242  case MKTAG('G', '1', ' ', ' '):
243  ctx->compressed = 0;
244  avctx->pix_fmt = AV_PIX_FMT_MONOBLACK;
245  break;
246  case MKTAG('D', 'X', '1', '0'):
247  /* DirectX 10 extra header */
248  dxgi = bytestream2_get_le32(gbc);
249  bytestream2_skip(gbc, 4); // resourceDimension
250  bytestream2_skip(gbc, 4); // miscFlag
251  array = bytestream2_get_le32(gbc);
252  bytestream2_skip(gbc, 4); // miscFlag2
253 
254  if (array != 0)
255  av_log(avctx, AV_LOG_VERBOSE,
256  "Found array of size %d (ignored).\n", array);
257 
258  /* Only BC[1-5] are actually compressed. */
259  ctx->compressed = (dxgi >= 70) && (dxgi <= 84);
260 
261  av_log(avctx, AV_LOG_VERBOSE, "DXGI format %d.\n", dxgi);
262  switch (dxgi) {
263  /* RGB types. */
270  avctx->pix_fmt = AV_PIX_FMT_BGRA64;
271  break;
273  avctx->colorspace = AVCOL_SPC_RGB;
279  avctx->pix_fmt = AV_PIX_FMT_BGRA;
280  break;
282  avctx->colorspace = AVCOL_SPC_RGB;
285  avctx->pix_fmt = AV_PIX_FMT_RGBA;
286  break;
288  avctx->colorspace = AVCOL_SPC_RGB;
291  avctx->pix_fmt = AV_PIX_FMT_RGBA; // opaque
292  break;
294  avctx->pix_fmt = AV_PIX_FMT_RGB565LE;
295  break;
296  /* Texture types. */
298  avctx->colorspace = AVCOL_SPC_RGB;
301  ctx->tex_ratio = 8;
302  ctx->tex_funct = ctx->texdsp.dxt1a_block;
303  break;
305  avctx->colorspace = AVCOL_SPC_RGB;
308  ctx->tex_ratio = 16;
309  ctx->tex_funct = ctx->texdsp.dxt3_block;
310  break;
312  avctx->colorspace = AVCOL_SPC_RGB;
315  ctx->tex_ratio = 16;
316  ctx->tex_funct = ctx->texdsp.dxt5_block;
317  break;
320  ctx->tex_ratio = 8;
321  ctx->tex_funct = ctx->texdsp.rgtc1u_block;
322  break;
324  ctx->tex_ratio = 8;
325  ctx->tex_funct = ctx->texdsp.rgtc1s_block;
326  break;
329  ctx->tex_ratio = 16;
330  ctx->tex_funct = ctx->texdsp.rgtc2u_block;
331  break;
333  ctx->tex_ratio = 16;
334  ctx->tex_funct = ctx->texdsp.rgtc2s_block;
335  break;
336  default:
337  av_log(avctx, AV_LOG_ERROR,
338  "Unsupported DXGI format %d.\n", dxgi);
339  return AVERROR_INVALIDDATA;
340  }
341  break;
342  default:
343  av_log(avctx, AV_LOG_ERROR, "Unsupported %s fourcc.\n", av_fourcc2str(fourcc));
344  return AVERROR_INVALIDDATA;
345  }
346  } else if (ctx->paletted) {
347  if (bpp == 8) {
348  avctx->pix_fmt = AV_PIX_FMT_PAL8;
349  } else {
350  av_log(avctx, AV_LOG_ERROR, "Unsupported palette bpp %d.\n", bpp);
351  return AVERROR_INVALIDDATA;
352  }
353  } else {
354  /* 4 bpp */
355  if (bpp == 4 && r == 0 && g == 0 && b == 0 && a == 0)
356  avctx->pix_fmt = AV_PIX_FMT_PAL8;
357  /* 8 bpp */
358  else if (bpp == 8 && r == 0xff && g == 0 && b == 0 && a == 0)
359  avctx->pix_fmt = AV_PIX_FMT_GRAY8;
360  else if (bpp == 8 && r == 0 && g == 0 && b == 0 && a == 0xff)
361  avctx->pix_fmt = AV_PIX_FMT_GRAY8;
362  /* 16 bpp */
363  else if (bpp == 16 && r == 0xff && g == 0 && b == 0 && a == 0xff00)
364  avctx->pix_fmt = AV_PIX_FMT_YA8;
365  else if (bpp == 16 && r == 0xff00 && g == 0 && b == 0 && a == 0xff) {
366  avctx->pix_fmt = AV_PIX_FMT_YA8;
367  ctx->postproc = DDS_SWAP_ALPHA;
368  }
369  else if (bpp == 16 && r == 0xffff && g == 0 && b == 0 && a == 0)
370  avctx->pix_fmt = AV_PIX_FMT_GRAY16LE;
371  else if (bpp == 16 && r == 0x7c00 && g == 0x3e0 && b == 0x1f && a == 0)
372  avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
373  else if (bpp == 16 && r == 0x7c00 && g == 0x3e0 && b == 0x1f && a == 0x8000)
374  avctx->pix_fmt = AV_PIX_FMT_RGB555LE; // alpha ignored
375  else if (bpp == 16 && r == 0xf800 && g == 0x7e0 && b == 0x1f && a == 0)
376  avctx->pix_fmt = AV_PIX_FMT_RGB565LE;
377  /* 24 bpp */
378  else if (bpp == 24 && r == 0xff0000 && g == 0xff00 && b == 0xff && a == 0)
379  avctx->pix_fmt = AV_PIX_FMT_BGR24;
380  /* 32 bpp */
381  else if (bpp == 32 && r == 0xff0000 && g == 0xff00 && b == 0xff && a == 0)
382  avctx->pix_fmt = AV_PIX_FMT_BGR0; // opaque
383  else if (bpp == 32 && r == 0xff && g == 0xff00 && b == 0xff0000 && a == 0)
384  avctx->pix_fmt = AV_PIX_FMT_RGB0; // opaque
385  else if (bpp == 32 && r == 0xff0000 && g == 0xff00 && b == 0xff && a == 0xff000000)
386  avctx->pix_fmt = AV_PIX_FMT_BGRA;
387  else if (bpp == 32 && r == 0xff && g == 0xff00 && b == 0xff0000 && a == 0xff000000)
388  avctx->pix_fmt = AV_PIX_FMT_RGBA;
389  /* give up */
390  else {
391  av_log(avctx, AV_LOG_ERROR, "Unknown pixel format "
392  "[bpp %d r 0x%x g 0x%x b 0x%x a 0x%x].\n", bpp, r, g, b, a);
393  return AVERROR_INVALIDDATA;
394  }
395  }
396 
397  /* Set any remaining post-proc that should happen before frame is ready. */
398  if (alpha_exponent)
399  ctx->postproc = DDS_ALPHA_EXP;
400  else if (normal_map)
401  ctx->postproc = DDS_NORMAL_MAP;
402  else if (ycocg_classic && !ctx->compressed)
403  ctx->postproc = DDS_RAW_YCOCG;
404 
405  /* ATI/NVidia variants sometimes add swizzling in bpp. */
406  switch (bpp) {
407  case MKTAG('A', '2', 'X', 'Y'):
408  ctx->postproc = DDS_SWIZZLE_A2XY;
409  break;
410  case MKTAG('x', 'G', 'B', 'R'):
411  ctx->postproc = DDS_SWIZZLE_XGBR;
412  break;
413  case MKTAG('x', 'R', 'B', 'G'):
414  ctx->postproc = DDS_SWIZZLE_XRBG;
415  break;
416  case MKTAG('R', 'B', 'x', 'G'):
417  ctx->postproc = DDS_SWIZZLE_RBXG;
418  break;
419  case MKTAG('R', 'G', 'x', 'B'):
420  ctx->postproc = DDS_SWIZZLE_RGXB;
421  break;
422  case MKTAG('R', 'x', 'B', 'G'):
423  ctx->postproc = DDS_SWIZZLE_RXBG;
424  break;
425  case MKTAG('x', 'G', 'x', 'R'):
426  ctx->postproc = DDS_SWIZZLE_XGXR;
427  break;
428  case MKTAG('A', '2', 'D', '5'):
429  ctx->postproc = DDS_NORMAL_MAP;
430  break;
431  }
432 
433  return 0;
434 }
435 
437  int slice, int thread_nb)
438 {
439  DDSContext *ctx = avctx->priv_data;
440  AVFrame *frame = arg;
441  const uint8_t *d = ctx->tex_data;
442  int w_block = avctx->coded_width / TEXTURE_BLOCK_W;
443  int h_block = avctx->coded_height / TEXTURE_BLOCK_H;
444  int x, y;
445  int start_slice, end_slice;
446  int base_blocks_per_slice = h_block / ctx->slice_count;
447  int remainder_blocks = h_block % ctx->slice_count;
448 
449  /* When the frame height (in blocks) doesn't divide evenly between the
450  * number of slices, spread the remaining blocks evenly between the first
451  * operations */
452  start_slice = slice * base_blocks_per_slice;
453  /* Add any extra blocks (one per slice) that have been added before this slice */
454  start_slice += FFMIN(slice, remainder_blocks);
455 
456  end_slice = start_slice + base_blocks_per_slice;
457  /* Add an extra block if there are still remainder blocks to be accounted for */
458  if (slice < remainder_blocks)
459  end_slice++;
460 
461  for (y = start_slice; y < end_slice; y++) {
462  uint8_t *p = frame->data[0] + y * frame->linesize[0] * TEXTURE_BLOCK_H;
463  int off = y * w_block;
464  for (x = 0; x < w_block; x++) {
465  ctx->tex_funct(p + x * 16, frame->linesize[0],
466  d + (off + x) * ctx->tex_ratio);
467  }
468  }
469 
470  return 0;
471 }
472 
473 static void do_swizzle(AVFrame *frame, int x, int y)
474 {
475  int i;
476  for (i = 0; i < frame->linesize[0] * frame->height; i += 4) {
477  uint8_t *src = frame->data[0] + i;
478  FFSWAP(uint8_t, src[x], src[y]);
479  }
480 }
481 
483 {
484  DDSContext *ctx = avctx->priv_data;
485  int i, x_off;
486 
487  switch (ctx->postproc) {
488  case DDS_ALPHA_EXP:
489  /* Alpha-exponential mode divides each channel by the maximum
490  * R, G or B value, and stores the multiplying factor in the
491  * alpha channel. */
492  av_log(avctx, AV_LOG_DEBUG, "Post-processing alpha exponent.\n");
493 
494  for (i = 0; i < frame->linesize[0] * frame->height; i += 4) {
495  uint8_t *src = frame->data[0] + i;
496  int r = src[0];
497  int g = src[1];
498  int b = src[2];
499  int a = src[3];
500 
501  src[0] = r * a / 255;
502  src[1] = g * a / 255;
503  src[2] = b * a / 255;
504  src[3] = 255;
505  }
506  break;
507  case DDS_NORMAL_MAP:
508  /* Normal maps work in the XYZ color space and they encode
509  * X in R or in A, depending on the texture type, Y in G and
510  * derive Z with a square root of the distance.
511  *
512  * http://www.realtimecollisiondetection.net/blog/?p=28 */
513  av_log(avctx, AV_LOG_DEBUG, "Post-processing normal map.\n");
514 
515  x_off = ctx->tex_ratio == 8 ? 0 : 3;
516  for (i = 0; i < frame->linesize[0] * frame->height; i += 4) {
517  uint8_t *src = frame->data[0] + i;
518  int x = src[x_off];
519  int y = src[1];
520  int z = 127;
521 
522  int d = (255 * 255 - x * x - y * y) / 2;
523  if (d > 0)
524  z = lrint(sqrtf(d));
525 
526  src[0] = x;
527  src[1] = y;
528  src[2] = z;
529  src[3] = 255;
530  }
531  break;
532  case DDS_RAW_YCOCG:
533  /* Data is Y-Co-Cg-A and not RGBA, but they are represented
534  * with the same masks in the DDPF header. */
535  av_log(avctx, AV_LOG_DEBUG, "Post-processing raw YCoCg.\n");
536 
537  for (i = 0; i < frame->linesize[0] * frame->height; i += 4) {
538  uint8_t *src = frame->data[0] + i;
539  int a = src[0];
540  int cg = src[1] - 128;
541  int co = src[2] - 128;
542  int y = src[3];
543 
544  src[0] = av_clip_uint8(y + co - cg);
545  src[1] = av_clip_uint8(y + cg);
546  src[2] = av_clip_uint8(y - co - cg);
547  src[3] = a;
548  }
549  break;
550  case DDS_SWAP_ALPHA:
551  /* Alpha and Luma are stored swapped. */
552  av_log(avctx, AV_LOG_DEBUG, "Post-processing swapped Luma/Alpha.\n");
553 
554  for (i = 0; i < frame->linesize[0] * frame->height; i += 2) {
555  uint8_t *src = frame->data[0] + i;
556  FFSWAP(uint8_t, src[0], src[1]);
557  }
558  break;
559  case DDS_SWIZZLE_A2XY:
560  /* Swap R and G, often used to restore a standard RGTC2. */
561  av_log(avctx, AV_LOG_DEBUG, "Post-processing A2XY swizzle.\n");
562  do_swizzle(frame, 0, 1);
563  break;
564  case DDS_SWIZZLE_RBXG:
565  /* Swap G and A, then B and new A (G). */
566  av_log(avctx, AV_LOG_DEBUG, "Post-processing RBXG swizzle.\n");
567  do_swizzle(frame, 1, 3);
568  do_swizzle(frame, 2, 3);
569  break;
570  case DDS_SWIZZLE_RGXB:
571  /* Swap B and A. */
572  av_log(avctx, AV_LOG_DEBUG, "Post-processing RGXB swizzle.\n");
573  do_swizzle(frame, 2, 3);
574  break;
575  case DDS_SWIZZLE_RXBG:
576  /* Swap G and A. */
577  av_log(avctx, AV_LOG_DEBUG, "Post-processing RXBG swizzle.\n");
578  do_swizzle(frame, 1, 3);
579  break;
580  case DDS_SWIZZLE_RXGB:
581  /* Swap R and A (misleading name). */
582  av_log(avctx, AV_LOG_DEBUG, "Post-processing RXGB swizzle.\n");
583  do_swizzle(frame, 0, 3);
584  break;
585  case DDS_SWIZZLE_XGBR:
586  /* Swap B and A, then R and new A (B). */
587  av_log(avctx, AV_LOG_DEBUG, "Post-processing XGBR swizzle.\n");
588  do_swizzle(frame, 2, 3);
589  do_swizzle(frame, 0, 3);
590  break;
591  case DDS_SWIZZLE_XGXR:
592  /* Swap G and A, then R and new A (G), then new R (G) and new G (A).
593  * This variant does not store any B component. */
594  av_log(avctx, AV_LOG_DEBUG, "Post-processing XGXR swizzle.\n");
595  do_swizzle(frame, 1, 3);
596  do_swizzle(frame, 0, 3);
597  do_swizzle(frame, 0, 1);
598  break;
599  case DDS_SWIZZLE_XRBG:
600  /* Swap G and A, then R and new A (G). */
601  av_log(avctx, AV_LOG_DEBUG, "Post-processing XRBG swizzle.\n");
602  do_swizzle(frame, 1, 3);
603  do_swizzle(frame, 0, 3);
604  break;
605  }
606 }
607 
608 static int dds_decode(AVCodecContext *avctx, void *data,
609  int *got_frame, AVPacket *avpkt)
610 {
611  DDSContext *ctx = avctx->priv_data;
612  GetByteContext *gbc = &ctx->gbc;
613  AVFrame *frame = data;
614  int mipmap;
615  int ret;
616 
617  ff_texturedsp_init(&ctx->texdsp);
618  bytestream2_init(gbc, avpkt->data, avpkt->size);
619 
620  if (bytestream2_get_bytes_left(gbc) < 128) {
621  av_log(avctx, AV_LOG_ERROR, "Frame is too small (%d).\n",
623  return AVERROR_INVALIDDATA;
624  }
625 
626  if (bytestream2_get_le32(gbc) != MKTAG('D', 'D', 'S', ' ') ||
627  bytestream2_get_le32(gbc) != 124) { // header size
628  av_log(avctx, AV_LOG_ERROR, "Invalid DDS header.\n");
629  return AVERROR_INVALIDDATA;
630  }
631 
632  bytestream2_skip(gbc, 4); // flags
633 
634  avctx->height = bytestream2_get_le32(gbc);
635  avctx->width = bytestream2_get_le32(gbc);
636  ret = av_image_check_size(avctx->width, avctx->height, 0, avctx);
637  if (ret < 0) {
638  av_log(avctx, AV_LOG_ERROR, "Invalid image size %dx%d.\n",
639  avctx->width, avctx->height);
640  return ret;
641  }
642 
643  /* Since codec is based on 4x4 blocks, size is aligned to 4. */
644  avctx->coded_width = FFALIGN(avctx->width, TEXTURE_BLOCK_W);
645  avctx->coded_height = FFALIGN(avctx->height, TEXTURE_BLOCK_H);
646 
647  bytestream2_skip(gbc, 4); // pitch
648  bytestream2_skip(gbc, 4); // depth
649  mipmap = bytestream2_get_le32(gbc);
650  if (mipmap != 0)
651  av_log(avctx, AV_LOG_VERBOSE, "Found %d mipmaps (ignored).\n", mipmap);
652 
653  /* Extract pixel format information, considering additional elements
654  * in reserved1 and reserved2. */
655  ret = parse_pixel_format(avctx);
656  if (ret < 0)
657  return ret;
658 
659  ret = ff_get_buffer(avctx, frame, 0);
660  if (ret < 0)
661  return ret;
662 
663  if (ctx->compressed) {
664  int size = (avctx->coded_height / TEXTURE_BLOCK_H) *
665  (avctx->coded_width / TEXTURE_BLOCK_W) * ctx->tex_ratio;
666  ctx->slice_count = av_clip(avctx->thread_count, 1,
667  avctx->coded_height / TEXTURE_BLOCK_H);
668 
669  if (bytestream2_get_bytes_left(gbc) < size) {
670  av_log(avctx, AV_LOG_ERROR,
671  "Compressed Buffer is too small (%d < %d).\n",
672  bytestream2_get_bytes_left(gbc), size);
673  return AVERROR_INVALIDDATA;
674  }
675 
676  /* Use the decompress function on the texture, one block per thread. */
677  ctx->tex_data = gbc->buffer;
678  avctx->execute2(avctx, decompress_texture_thread, frame, NULL, ctx->slice_count);
679  } else if (!ctx->paletted && ctx->bpp == 4 && avctx->pix_fmt == AV_PIX_FMT_PAL8) {
680  uint8_t *dst = frame->data[0];
681  int x, y, i;
682 
683  /* Use the first 64 bytes as palette, then copy the rest. */
684  bytestream2_get_buffer(gbc, frame->data[1], 16 * 4);
685  for (i = 0; i < 16; i++) {
686  AV_WN32(frame->data[1] + i*4,
687  (frame->data[1][2+i*4]<<0)+
688  (frame->data[1][1+i*4]<<8)+
689  (frame->data[1][0+i*4]<<16)+
690  ((unsigned)frame->data[1][3+i*4]<<24)
691  );
692  }
693  frame->palette_has_changed = 1;
694 
695  if (bytestream2_get_bytes_left(gbc) < frame->height * frame->width / 2) {
696  av_log(avctx, AV_LOG_ERROR, "Buffer is too small (%d < %d).\n",
697  bytestream2_get_bytes_left(gbc), frame->height * frame->width / 2);
698  return AVERROR_INVALIDDATA;
699  }
700 
701  for (y = 0; y < frame->height; y++) {
702  for (x = 0; x < frame->width; x += 2) {
703  uint8_t val = bytestream2_get_byte(gbc);
704  dst[x ] = val & 0xF;
705  dst[x + 1] = val >> 4;
706  }
707  dst += frame->linesize[0];
708  }
709  } else {
710  int linesize = av_image_get_linesize(avctx->pix_fmt, frame->width, 0);
711 
712  if (ctx->paletted) {
713  int i;
714  /* Use the first 1024 bytes as palette, then copy the rest. */
715  bytestream2_get_buffer(gbc, frame->data[1], 256 * 4);
716  for (i = 0; i < 256; i++)
717  AV_WN32(frame->data[1] + i*4,
718  (frame->data[1][2+i*4]<<0)+
719  (frame->data[1][1+i*4]<<8)+
720  (frame->data[1][0+i*4]<<16)+
721  ((unsigned)frame->data[1][3+i*4]<<24)
722  );
723 
724  frame->palette_has_changed = 1;
725  }
726 
727  if (bytestream2_get_bytes_left(gbc) < frame->height * linesize) {
728  av_log(avctx, AV_LOG_ERROR, "Buffer is too small (%d < %d).\n",
729  bytestream2_get_bytes_left(gbc), frame->height * linesize);
730  return AVERROR_INVALIDDATA;
731  }
732 
733  av_image_copy_plane(frame->data[0], frame->linesize[0],
734  gbc->buffer, linesize,
735  linesize, frame->height);
736  }
737 
738  /* Run any post processing here if needed. */
739  if (ctx->postproc != DDS_NONE)
740  run_postproc(avctx, frame);
741 
742  /* Frame is ready to be output. */
743  frame->pict_type = AV_PICTURE_TYPE_I;
744  frame->key_frame = 1;
745  *got_frame = 1;
746 
747  return avpkt->size;
748 }
749 
751  .name = "dds",
752  .long_name = NULL_IF_CONFIG_SMALL("DirectDraw Surface image decoder"),
753  .type = AVMEDIA_TYPE_VIDEO,
754  .id = AV_CODEC_ID_DDS,
755  .decode = dds_decode,
756  .priv_data_size = sizeof(DDSContext),
758  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE
759 };
packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
Definition: pixfmt.h:81
#define NULL
Definition: coverity.c:32
const char const char void * val
Definition: avisynth_c.h:863
int av_image_get_linesize(enum AVPixelFormat pix_fmt, int width, int plane)
Compute the size of an image line with format pix_fmt and width width for the plane plane...
Definition: imgutils.c:76
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
int compressed
Definition: dds.c:103
int(* dxt5_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Definition: texturedsp.h:51
This structure describes decoded (raw) audio or video data.
Definition: frame.h:268
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
8 bits gray, 8 bits alpha
Definition: pixfmt.h:143
int coded_width
Bitstream width / height, may be different from width/height e.g.
Definition: avcodec.h:1753
misc image utilities
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
const char * g
Definition: vf_curves.c:115
uint32_t fourcc
Definition: vaapi_decode.c:238
Texture block (4x4) module.
packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), little-endian, X=unused/undefined ...
Definition: pixfmt.h:108
int size
Definition: avcodec.h:1478
#define AV_PIX_FMT_BGRA64
Definition: pixfmt.h:382
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:36
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1775
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
int slice_count
Definition: dds.c:110
enum DDSPostProc postproc
Definition: dds.c:106
int tex_ratio
Definition: dds.c:109
static int parse_pixel_format(AVCodecContext *avctx)
Definition: dds.c:116
#define src
Definition: vp8dsp.c:254
AVCodec.
Definition: avcodec.h:3477
order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB)
Definition: pixfmt.h:497
TextureDSPContext texdsp
Definition: dds.c:100
packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian
Definition: pixfmt.h:106
#define FF_CODEC_CAP_INIT_THREADSAFE
The codec does not modify any global variables in the init function, allowing to call the init functi...
Definition: internal.h:40
The exact code depends on how similar the blocks are and how related they are to the block
uint8_t
#define DDPF_NORMALMAP
Definition: dds.c:42
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:238
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:77
Definition: dds.c:45
Multithreading support functions.
int(* dxt5y_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Definition: texturedsp.h:52
#define TEXTURE_BLOCK_H
Definition: texturedsp.h:43
uint8_t * data
Definition: avcodec.h:1477
int(* dxt3_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Definition: texturedsp.h:49
const uint8_t * buffer
Definition: bytestream.h:34
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
ptrdiff_t size
Definition: opengl_enc.c:100
#define DDPF_FOURCC
Definition: dds.c:40
int(* rgtc2s_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Definition: texturedsp.h:58
#define FFALIGN(x, a)
Definition: macros.h:48
#define av_log(a,...)
DDSPostProc
Definition: dds.c:44
int(* dxt5ys_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Definition: texturedsp.h:53
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:260
int width
Definition: frame.h:326
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
AVCodec ff_dds_decoder
Definition: dds.c:750
int(* rgtc1u_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Definition: texturedsp.h:55
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:164
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
const char * r
Definition: vf_curves.c:114
static av_always_inline unsigned int bytestream2_get_buffer(GetByteContext *g, uint8_t *dst, unsigned int size)
Definition: bytestream.h:263
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
GetByteContext gbc
Definition: dds.c:101
Definition: dds.c:99
#define av_fourcc2str(fourcc)
Definition: avutil.h:348
static av_always_inline unsigned int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:154
const char * arg
Definition: jacosubdec.c:66
const char * name
Name of the codec implementation.
Definition: avcodec.h:3484
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx)
Check if the given dimension of an image is valid, meaning that all bytes of the image can be address...
Definition: imgutils.c:282
av_cold void ff_texturedsp_init(TextureDSPContext *c)
Definition: texturedsp.c:637
#define b
Definition: input.c:41
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:351
int(* dxt1a_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Definition: texturedsp.h:47
#define FFMIN(a, b)
Definition: common.h:96
int paletted
Definition: dds.c:104
int width
picture width / height.
Definition: avcodec.h:1738
AVFormatContext * ctx
Definition: movenc.c:48
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
int(* dxt2_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Definition: texturedsp.h:48
int thread_count
thread count is used to decide how many independent tasks should be passed to execute() ...
Definition: avcodec.h:2820
int bpp
Definition: dds.c:105
#define AV_CODEC_CAP_SLICE_THREADS
Codec supports slice-based (or partition-based) multithreading.
Definition: avcodec.h:1041
int(* execute2)(struct AVCodecContext *c, int(*func)(struct AVCodecContext *c2, void *arg, int jobnr, int threadnr), void *arg2, int *ret, int count)
The codec may call this to execute several independent things.
Definition: avcodec.h:2880
Libavcodec external API header.
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:299
main external API structure.
Definition: avcodec.h:1565
packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
Definition: pixfmt.h:67
static void do_swizzle(AVFrame *frame, int x, int y)
Definition: dds.c:473
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1964
Replacements for frequently missing libm functions.
int coded_height
Definition: avcodec.h:1753
enum AVColorSpace colorspace
YUV colorspace type.
Definition: avcodec.h:2189
int palette_has_changed
Tell user application that palette has changed from previous frame.
Definition: frame.h:425
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:240
int(* tex_funct)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Definition: dds.c:113
int(* dxt4_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Definition: texturedsp.h:50
int(* rgtc1s_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Definition: texturedsp.h:54
#define flags(name, subs,...)
Definition: cbs_av1.c:561
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:282
Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb...
Definition: pixfmt.h:76
int
Y , 8bpp.
Definition: pixfmt.h:74
common internal api header.
#define AV_WN32(p, v)
Definition: intreadwrite.h:376
int(* rgtc2u_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Definition: texturedsp.h:59
void * priv_data
Definition: avcodec.h:1592
Y , 16bpp, little-endian.
Definition: pixfmt.h:98
int key_frame
1 -> keyframe, 0-> not
Definition: frame.h:346
static int decompress_texture_thread(AVCodecContext *avctx, void *arg, int slice, int thread_nb)
Definition: dds.c:436
#define lrint
Definition: tablegen.h:53
#define DDPF_PALETTE
Definition: dds.c:41
int height
Definition: frame.h:326
static int array[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:106
#define FFSWAP(type, a, b)
Definition: common.h:99
void av_image_copy_plane(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize, int bytewidth, int height)
Copy image plane from src to dst.
Definition: imgutils.c:338
#define stride
#define MKTAG(a, b, c, d)
Definition: common.h:366
DDSDXGIFormat
Definition: dds.c:60
static void run_postproc(AVCodecContext *avctx, AVFrame *frame)
Definition: dds.c:482
#define TEXTURE_BLOCK_W
Definition: texturedsp.h:42
const uint8_t * tex_data
Definition: dds.c:108
int(* dxn3dc_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Definition: texturedsp.h:60
This structure stores compressed data.
Definition: avcodec.h:1454
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:981
static int dds_decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: dds.c:608