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  int width, height;
617 
618  ff_texturedsp_init(&ctx->texdsp);
619  bytestream2_init(gbc, avpkt->data, avpkt->size);
620 
621  if (bytestream2_get_bytes_left(gbc) < 128) {
622  av_log(avctx, AV_LOG_ERROR, "Frame is too small (%d).\n",
624  return AVERROR_INVALIDDATA;
625  }
626 
627  if (bytestream2_get_le32(gbc) != MKTAG('D', 'D', 'S', ' ') ||
628  bytestream2_get_le32(gbc) != 124) { // header size
629  av_log(avctx, AV_LOG_ERROR, "Invalid DDS header.\n");
630  return AVERROR_INVALIDDATA;
631  }
632 
633  bytestream2_skip(gbc, 4); // flags
634 
635  height = bytestream2_get_le32(gbc);
636  width = bytestream2_get_le32(gbc);
637  ret = ff_set_dimensions(avctx, width, height);
638  if (ret < 0) {
639  av_log(avctx, AV_LOG_ERROR, "Invalid image size %dx%d.\n",
640  avctx->width, avctx->height);
641  return ret;
642  }
643 
644  /* Since codec is based on 4x4 blocks, size is aligned to 4. */
645  avctx->coded_width = FFALIGN(avctx->width, TEXTURE_BLOCK_W);
646  avctx->coded_height = FFALIGN(avctx->height, TEXTURE_BLOCK_H);
647 
648  bytestream2_skip(gbc, 4); // pitch
649  bytestream2_skip(gbc, 4); // depth
650  mipmap = bytestream2_get_le32(gbc);
651  if (mipmap != 0)
652  av_log(avctx, AV_LOG_VERBOSE, "Found %d mipmaps (ignored).\n", mipmap);
653 
654  /* Extract pixel format information, considering additional elements
655  * in reserved1 and reserved2. */
656  ret = parse_pixel_format(avctx);
657  if (ret < 0)
658  return ret;
659 
660  ret = ff_get_buffer(avctx, frame, 0);
661  if (ret < 0)
662  return ret;
663 
664  if (ctx->compressed) {
665  int size = (avctx->coded_height / TEXTURE_BLOCK_H) *
666  (avctx->coded_width / TEXTURE_BLOCK_W) * ctx->tex_ratio;
667  ctx->slice_count = av_clip(avctx->thread_count, 1,
668  avctx->coded_height / TEXTURE_BLOCK_H);
669 
670  if (bytestream2_get_bytes_left(gbc) < size) {
671  av_log(avctx, AV_LOG_ERROR,
672  "Compressed Buffer is too small (%d < %d).\n",
674  return AVERROR_INVALIDDATA;
675  }
676 
677  /* Use the decompress function on the texture, one block per thread. */
678  ctx->tex_data = gbc->buffer;
679  avctx->execute2(avctx, decompress_texture_thread, frame, NULL, ctx->slice_count);
680  } else if (!ctx->paletted && ctx->bpp == 4 && avctx->pix_fmt == AV_PIX_FMT_PAL8) {
681  uint8_t *dst = frame->data[0];
682  int x, y, i;
683 
684  /* Use the first 64 bytes as palette, then copy the rest. */
685  bytestream2_get_buffer(gbc, frame->data[1], 16 * 4);
686  for (i = 0; i < 16; i++) {
687  AV_WN32(frame->data[1] + i*4,
688  (frame->data[1][2+i*4]<<0)+
689  (frame->data[1][1+i*4]<<8)+
690  (frame->data[1][0+i*4]<<16)+
691  ((unsigned)frame->data[1][3+i*4]<<24)
692  );
693  }
694  frame->palette_has_changed = 1;
695 
696  if (bytestream2_get_bytes_left(gbc) < frame->height * frame->width / 2) {
697  av_log(avctx, AV_LOG_ERROR, "Buffer is too small (%d < %d).\n",
698  bytestream2_get_bytes_left(gbc), frame->height * frame->width / 2);
699  return AVERROR_INVALIDDATA;
700  }
701 
702  for (y = 0; y < frame->height; y++) {
703  for (x = 0; x < frame->width; x += 2) {
704  uint8_t val = bytestream2_get_byte(gbc);
705  dst[x ] = val & 0xF;
706  dst[x + 1] = val >> 4;
707  }
708  dst += frame->linesize[0];
709  }
710  } else {
711  int linesize = av_image_get_linesize(avctx->pix_fmt, frame->width, 0);
712 
713  if (ctx->paletted) {
714  int i;
715  /* Use the first 1024 bytes as palette, then copy the rest. */
716  bytestream2_get_buffer(gbc, frame->data[1], 256 * 4);
717  for (i = 0; i < 256; i++)
718  AV_WN32(frame->data[1] + i*4,
719  (frame->data[1][2+i*4]<<0)+
720  (frame->data[1][1+i*4]<<8)+
721  (frame->data[1][0+i*4]<<16)+
722  ((unsigned)frame->data[1][3+i*4]<<24)
723  );
724 
725  frame->palette_has_changed = 1;
726  }
727 
728  if (bytestream2_get_bytes_left(gbc) < frame->height * linesize) {
729  av_log(avctx, AV_LOG_ERROR, "Buffer is too small (%d < %d).\n",
730  bytestream2_get_bytes_left(gbc), frame->height * linesize);
731  return AVERROR_INVALIDDATA;
732  }
733 
734  av_image_copy_plane(frame->data[0], frame->linesize[0],
735  gbc->buffer, linesize,
736  linesize, frame->height);
737  }
738 
739  /* Run any post processing here if needed. */
740  if (ctx->postproc != DDS_NONE)
741  run_postproc(avctx, frame);
742 
743  /* Frame is ready to be output. */
744  frame->pict_type = AV_PICTURE_TYPE_I;
745  frame->key_frame = 1;
746  *got_frame = 1;
747 
748  return avpkt->size;
749 }
750 
752  .name = "dds",
753  .long_name = NULL_IF_CONFIG_SMALL("DirectDraw Surface image decoder"),
754  .type = AVMEDIA_TYPE_VIDEO,
755  .id = AV_CODEC_ID_DDS,
756  .decode = dds_decode,
757  .priv_data_size = sizeof(DDSContext),
759  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE
760 };
DXGI_FORMAT_BC4_SNORM
@ DXGI_FORMAT_BC4_SNORM
Definition: dds.c:86
AVCodec
AVCodec.
Definition: codec.h:202
stride
int stride
Definition: mace.c:144
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
FF_CODEC_CAP_INIT_THREADSAFE
#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:42
DDS_SWAP_ALPHA
@ DDS_SWAP_ALPHA
Definition: dds.c:49
DXGI_FORMAT_B8G8R8A8_TYPELESS
@ DXGI_FORMAT_B8G8R8A8_TYPELESS
Definition: dds.c:93
DXGI_FORMAT_BC2_UNORM_SRGB
@ DXGI_FORMAT_BC2_UNORM_SRGB
Definition: dds.c:80
DDS_RAW_YCOCG
@ DDS_RAW_YCOCG
Definition: dds.c:48
av_clip
#define av_clip
Definition: common.h:96
r
const char * r
Definition: vf_curves.c:116
AV_PIX_FMT_YA8
@ AV_PIX_FMT_YA8
8 bits gray, 8 bits alpha
Definition: pixfmt.h:133
AVCodecContext::colorspace
enum AVColorSpace colorspace
YUV colorspace type.
Definition: avcodec.h:960
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
@ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
Definition: dds.c:70
libm.h
DXGI_FORMAT_B8G8R8X8_UNORM
@ DXGI_FORMAT_B8G8R8X8_UNORM
Definition: dds.c:92
TEXTURE_BLOCK_H
#define TEXTURE_BLOCK_H
Definition: texturedsp.h:43
DXGI_FORMAT_B5G6R5_UNORM
@ DXGI_FORMAT_B5G6R5_UNORM
Definition: dds.c:90
GetByteContext
Definition: bytestream.h:33
DXGI_FORMAT_B8G8R8A8_UNORM
@ DXGI_FORMAT_B8G8R8A8_UNORM
Definition: dds.c:91
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:317
DDSContext::compressed
int compressed
Definition: dds.c:103
internal.h
AVPacket::data
uint8_t * data
Definition: packet.h:373
DXGI_FORMAT_BC4_TYPELESS
@ DXGI_FORMAT_BC4_TYPELESS
Definition: dds.c:84
b
#define b
Definition: input.c:40
DDS_NONE
@ DDS_NONE
Definition: dds.c:45
data
const char data[16]
Definition: mxf.c:143
DXGI_FORMAT_BC1_UNORM
@ DXGI_FORMAT_BC1_UNORM
Definition: dds.c:76
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:196
AVCOL_SPC_RGB
@ AVCOL_SPC_RGB
order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB), YZX and ST 428-1
Definition: pixfmt.h:524
DXGI_FORMAT_R16G16B16A16_TYPELESS
@ DXGI_FORMAT_R16G16B16A16_TYPELESS
Definition: dds.c:61
AV_PIX_FMT_BGR24
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
AV_PIX_FMT_BGRA
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
TextureDSPContext
Definition: texturedsp.h:45
DXGI_FORMAT_B8G8R8X8_UNORM_SRGB
@ DXGI_FORMAT_B8G8R8X8_UNORM_SRGB
Definition: dds.c:96
DDSContext::paletted
int paletted
Definition: dds.c:104
thread.h
av_image_copy_plane
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:374
ff_dds_decoder
const AVCodec ff_dds_decoder
Definition: dds.c:751
bytestream2_skip
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:168
DXGI_FORMAT_BC1_TYPELESS
@ DXGI_FORMAT_BC1_TYPELESS
Definition: dds.c:75
texturedsp.h
DDSContext::bpp
int bpp
Definition: dds.c:105
AVCodecContext::thread_count
int thread_count
thread count is used to decide how many independent tasks should be passed to execute()
Definition: avcodec.h:1440
DDPF_FOURCC
#define DDPF_FOURCC
Definition: dds.c:40
val
static double val(void *priv, double ch)
Definition: aeval.c:76
AVCodecContext::coded_height
int coded_height
Definition: avcodec.h:571
run_postproc
static void run_postproc(AVCodecContext *avctx, AVFrame *frame)
Definition: dds.c:482
DDSContext::tex_funct
int(* tex_funct)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Definition: dds.c:113
DXGI_FORMAT_B8G8R8X8_TYPELESS
@ DXGI_FORMAT_B8G8R8X8_TYPELESS
Definition: dds.c:95
lrint
#define lrint
Definition: tablegen.h:53
DDSPostProc
DDSPostProc
Definition: dds.c:44
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
DDSContext::tex_data
const uint8_t * tex_data
Definition: dds.c:108
width
#define width
DDS_SWIZZLE_XRBG
@ DDS_SWIZZLE_XRBG
Definition: dds.c:56
DDS_SWIZZLE_XGBR
@ DDS_SWIZZLE_XGBR
Definition: dds.c:55
DXGI_FORMAT_R16G16B16A16_SNORM
@ DXGI_FORMAT_R16G16B16A16_SNORM
Definition: dds.c:65
g
const char * g
Definition: vf_curves.c:117
GetByteContext::buffer
const uint8_t * buffer
Definition: bytestream.h:34
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
ctx
AVFormatContext * ctx
Definition: movenc.c:48
ff_texturedsp_init
av_cold void ff_texturedsp_init(TextureDSPContext *c)
Definition: texturedsp.c:637
DDS_SWIZZLE_RXBG
@ DDS_SWIZZLE_RXBG
Definition: dds.c:53
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
arg
const char * arg
Definition: jacosubdec.c:67
AV_PIX_FMT_RGB565LE
@ AV_PIX_FMT_RGB565LE
packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian
Definition: pixfmt.h:106
DXGI_FORMAT_R16G16B16A16_UNORM
@ DXGI_FORMAT_R16G16B16A16_UNORM
Definition: dds.c:63
NULL
#define NULL
Definition: coverity.c:32
AV_PIX_FMT_YUYV422
@ AV_PIX_FMT_YUYV422
packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
Definition: pixfmt.h:67
AV_PIX_FMT_MONOBLACK
@ AV_PIX_FMT_MONOBLACK
Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb.
Definition: pixfmt.h:76
DDS_SWIZZLE_RBXG
@ DDS_SWIZZLE_RBXG
Definition: dds.c:51
AV_PICTURE_TYPE_I
@ AV_PICTURE_TYPE_I
Intra.
Definition: avutil.h:274
src
#define src
Definition: vp8dsp.c:255
bytestream2_get_buffer
static av_always_inline unsigned int bytestream2_get_buffer(GetByteContext *g, uint8_t *dst, unsigned int size)
Definition: bytestream.h:267
AV_PIX_FMT_BGR0
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:230
AV_PIX_FMT_GRAY8
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition: pixfmt.h:74
DXGI_FORMAT_BC4_UNORM
@ DXGI_FORMAT_BC4_UNORM
Definition: dds.c:85
DDPF_NORMALMAP
#define DDPF_NORMALMAP
Definition: dds.c:42
DDS_SWIZZLE_XGXR
@ DDS_SWIZZLE_XGXR
Definition: dds.c:57
bytestream2_get_bytes_left
static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:158
ff_get_buffer
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1652
AV_CODEC_CAP_DR1
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition: codec.h:52
AVPacket::size
int size
Definition: packet.h:374
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
AV_WN32
#define AV_WN32(p, v)
Definition: intreadwrite.h:376
DDS_SWIZZLE_RXGB
@ DDS_SWIZZLE_RXGB
Definition: dds.c:54
DXGI_FORMAT_BC3_UNORM_SRGB
@ DXGI_FORMAT_BC3_UNORM_SRGB
Definition: dds.c:83
size
int size
Definition: twinvq_data.h:10344
DDSContext::texdsp
TextureDSPContext texdsp
Definition: dds.c:100
DXGI_FORMAT_R8G8B8A8_SNORM
@ DXGI_FORMAT_R8G8B8A8_SNORM
Definition: dds.c:72
DDSContext
Definition: dds.c:99
DXGI_FORMAT_BC5_SNORM
@ DXGI_FORMAT_BC5_SNORM
Definition: dds.c:89
DXGI_FORMAT_R8G8B8A8_TYPELESS
@ DXGI_FORMAT_R8G8B8A8_TYPELESS
Definition: dds.c:68
height
#define height
a
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:41
do_swizzle
static void do_swizzle(AVFrame *frame, int x, int y)
Definition: dds.c:473
AV_CODEC_CAP_SLICE_THREADS
#define AV_CODEC_CAP_SLICE_THREADS
Codec supports slice-based (or partition-based) multithreading.
Definition: codec.h:117
AV_PIX_FMT_RGB0
@ AV_PIX_FMT_RGB0
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:228
DDSContext::slice_count
int slice_count
Definition: dds.c:110
DXGI_FORMAT_R8G8B8A8_UINT
@ DXGI_FORMAT_R8G8B8A8_UINT
Definition: dds.c:71
DDSContext::postproc
enum DDSPostProc postproc
Definition: dds.c:106
av_image_get_linesize
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
DXGI_FORMAT_R16G16B16A16_FLOAT
@ DXGI_FORMAT_R16G16B16A16_FLOAT
Definition: dds.c:62
AV_PIX_FMT_BGRA64
#define AV_PIX_FMT_BGRA64
Definition: pixfmt.h:399
AV_PIX_FMT_RGB555LE
@ AV_PIX_FMT_RGB555LE
packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), little-endian, X=unused/undefined
Definition: pixfmt.h:108
DXGI_FORMAT_BC2_TYPELESS
@ DXGI_FORMAT_BC2_TYPELESS
Definition: dds.c:78
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:271
DXGI_FORMAT_R16G16B16A16_SINT
@ DXGI_FORMAT_R16G16B16A16_SINT
Definition: dds.c:66
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
DDSDXGIFormat
DDSDXGIFormat
Definition: dds.c:60
parse_pixel_format
static int parse_pixel_format(AVCodecContext *avctx)
Definition: dds.c:116
TEXTURE_BLOCK_W
#define TEXTURE_BLOCK_W
Definition: texturedsp.h:42
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:209
AVCodecContext::height
int height
Definition: avcodec.h:556
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:593
DXGI_FORMAT_BC1_UNORM_SRGB
@ DXGI_FORMAT_BC1_UNORM_SRGB
Definition: dds.c:77
avcodec.h
AV_PIX_FMT_PAL8
@ AV_PIX_FMT_PAL8
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:77
array
static int array[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:106
ret
ret
Definition: filter_design.txt:187
decompress_texture_thread
static int decompress_texture_thread(AVCodecContext *avctx, void *arg, int slice, int thread_nb)
Definition: dds.c:436
DDS_NORMAL_MAP
@ DDS_NORMAL_MAP
Definition: dds.c:47
DXGI_FORMAT_BC5_TYPELESS
@ DXGI_FORMAT_BC5_TYPELESS
Definition: dds.c:87
FFSWAP
#define FFSWAP(type, a, b)
Definition: macros.h:52
frame
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
Definition: filter_design.txt:264
DDPF_PALETTE
#define DDPF_PALETTE
Definition: dds.c:41
AV_PIX_FMT_UYVY422
@ AV_PIX_FMT_UYVY422
packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
Definition: pixfmt.h:81
DXGI_FORMAT_BC3_UNORM
@ DXGI_FORMAT_BC3_UNORM
Definition: dds.c:82
AVCodecContext
main external API structure.
Definition: avcodec.h:383
DDSContext::gbc
GetByteContext gbc
Definition: dds.c:101
DXGI_FORMAT_BC2_UNORM
@ DXGI_FORMAT_BC2_UNORM
Definition: dds.c:79
DDS_SWIZZLE_RGXB
@ DDS_SWIZZLE_RGXB
Definition: dds.c:52
av_clip_uint8
#define av_clip_uint8
Definition: common.h:102
DXGI_FORMAT_R16G16B16A16_UINT
@ DXGI_FORMAT_R16G16B16A16_UINT
Definition: dds.c:64
AVCodecContext::coded_width
int coded_width
Bitstream width / height, may be different from width/height e.g.
Definition: avcodec.h:571
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
AV_CODEC_ID_DDS
@ AV_CODEC_ID_DDS
Definition: codec_id.h:240
AV_PIX_FMT_GRAY16LE
@ AV_PIX_FMT_GRAY16LE
Y , 16bpp, little-endian.
Definition: pixfmt.h:98
ff_set_dimensions
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Check that the provided frame dimensions are valid and set them on the codec context.
Definition: utils.c:86
DXGI_FORMAT_BC3_TYPELESS
@ DXGI_FORMAT_BC3_TYPELESS
Definition: dds.c:81
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
AVPacket
This structure stores compressed data.
Definition: packet.h:350
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:410
DDS_SWIZZLE_A2XY
@ DDS_SWIZZLE_A2XY
Definition: dds.c:50
dds_decode
static int dds_decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: dds.c:608
d
d
Definition: ffmpeg_filter.c:153
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:556
bytestream.h
imgutils.h
DXGI_FORMAT_BC5_UNORM
@ DXGI_FORMAT_BC5_UNORM
Definition: dds.c:88
bytestream2_init
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:137
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
block
The exact code depends on how similar the blocks are and how related they are to the block
Definition: filter_design.txt:207
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
DDS_ALPHA_EXP
@ DDS_ALPHA_EXP
Definition: dds.c:46
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
DXGI_FORMAT_R8G8B8A8_UNORM
@ DXGI_FORMAT_R8G8B8A8_UNORM
Definition: dds.c:69
MKTAG
#define MKTAG(a, b, c, d)
Definition: macros.h:55
DDSContext::tex_ratio
int tex_ratio
Definition: dds.c:109
int
int
Definition: ffmpeg_filter.c:153
fourcc
uint32_t fourcc
Definition: vaapi_decode.c:239
DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
@ DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
Definition: dds.c:94
AVCodecContext::execute2
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:1511
DXGI_FORMAT_R8G8B8A8_SINT
@ DXGI_FORMAT_R8G8B8A8_SINT
Definition: dds.c:73
av_fourcc2str
#define av_fourcc2str(fourcc)
Definition: avutil.h:348