FFmpeg
hdrdec.c
Go to the documentation of this file.
1 /*
2  * Radiance HDR image format
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include "avcodec.h"
22 #include "bytestream.h"
23 #include "codec_internal.h"
24 #include "decode.h"
25 #include "thread.h"
26 
27 #define MINELEN 8
28 #define MAXELEN 0x7fff
29 
30 static int hdr_get_line(GetByteContext *gb, uint8_t *buffer, int size)
31 {
32  int n = 0, c;
33 
34  memset(buffer, 0, size);
35 
36  do {
37  c = bytestream2_get_byte(gb);
38  if (n < size - 1)
39  buffer[n++] = c;
40  } while (bytestream2_get_bytes_left(gb) > 0 && c != '\n');
41 
42  return 0;
43 }
44 
45 static float convert(int expo, int val)
46 {
47  if (expo == -128) {
48  return 0.f;
49  } else {
50  const float v = val / 256.f;
51 
52  return ldexpf(v, expo);
53  }
54 }
55 
56 static int decompress(uint8_t *scanline, int w, GetByteContext *gb, const uint8_t *start)
57 {
58  int rshift = 0;
59 
60  while (w > 0) {
61  if (bytestream2_get_bytes_left(gb) < 4)
62  return AVERROR_INVALIDDATA;
63  scanline[0] = bytestream2_get_byte(gb);
64  scanline[1] = bytestream2_get_byte(gb);
65  scanline[2] = bytestream2_get_byte(gb);
66  scanline[3] = bytestream2_get_byte(gb);
67 
68  if (scanline[0] == 1 &&
69  scanline[1] == 1 &&
70  scanline[2] == 1) {
71  int run = scanline[3];
72  for (int i = run << rshift; i > 0 && w > 0 && scanline >= start + 4; i--) {
73  memcpy(scanline, scanline - 4, 4);
74  scanline += 4;
75  w -= 4;
76  }
77  rshift += 8;
78  if (rshift > 16)
79  break;
80  } else {
81  scanline += 4;
82  w--;
83  rshift = 0;
84  }
85  }
86 
87  return 1;
88 }
89 
91  int *got_frame, AVPacket *avpkt)
92 {
93  int width = 0, height = 0;
94  GetByteContext gb;
95  uint8_t line[512];
96  float sar;
97  int ret;
98 
99  bytestream2_init(&gb, avpkt->data, avpkt->size);
100  hdr_get_line(&gb, line, sizeof(line));
101  if (memcmp("#?RADIANCE\n", line, 11))
102  return AVERROR_INVALIDDATA;
103 
104  do {
105  hdr_get_line(&gb, line, sizeof(line));
106  if (sscanf(line, "PIXASPECT=%f\n", &sar) == 1)
107  avctx->sample_aspect_ratio = p->sample_aspect_ratio = av_inv_q(av_d2q(sar, 4096));
108  } while (line[0] != '\n' && line[0]);
109 
110  hdr_get_line(&gb, line, sizeof(line));
111  if (sscanf(line, "-Y %d +X %d\n", &height, &width) == 2) {
112  ;
113  } else if (sscanf(line, "+Y %d +X %d\n", &height, &width) == 2) {
114  ;
115  } else if (sscanf(line, "-Y %d -X %d\n", &height, &width) == 2) {
116  ;
117  } else if (sscanf(line, "+Y %d -X %d\n", &height, &width) == 2) {
118  ;
119  } else if (sscanf(line, "-X %d +Y %d\n", &width, &height) == 2) {
120  ;
121  } else if (sscanf(line, "+X %d +Y %d\n", &width, &height) == 2) {
122  ;
123  } else if (sscanf(line, "-X %d -Y %d\n", &width, &height) == 2) {
124  ;
125  } else if (sscanf(line, "+X %d -Y %d\n", &width, &height) == 2) {
126  ;
127  }
128 
129  if (bytestream2_get_bytes_left(&gb) < height * 4)
130  return AVERROR_INVALIDDATA;
131 
132  if ((ret = ff_set_dimensions(avctx, width, height)) < 0)
133  return ret;
134 
135  avctx->pix_fmt = AV_PIX_FMT_GBRPF32;
136 
137  if (avctx->skip_frame >= AVDISCARD_ALL)
138  return avpkt->size;
139 
140  if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0)
141  return ret;
142 
143  for (int y = 0; y < height; y++) {
144  float *dst_r = (float *)(p->data[2] + y * p->linesize[2]);
145  float *dst_g = (float *)(p->data[0] + y * p->linesize[0]);
146  float *dst_b = (float *)(p->data[1] + y * p->linesize[1]);
147  uint8_t *scanline = p->data[0] + y * p->linesize[0];
148  int i;
149 
150  if (width < MINELEN || width > MAXELEN) {
151  ret = decompress(scanline, width, &gb, scanline);
152  if (ret < 0)
153  return ret;
154  goto convert;
155  }
156 
157  i = bytestream2_peek_byte(&gb);
158  if (i != 2) {
159  ret = decompress(scanline, width, &gb, scanline);
160  if (ret < 0)
161  return ret;
162  goto convert;
163  }
164  bytestream2_skip(&gb, 1);
165 
166  scanline[1] = bytestream2_get_byte(&gb);
167  scanline[2] = bytestream2_get_byte(&gb);
168  i = bytestream2_get_byte(&gb);
169 
170  if (scanline[1] != 2 || scanline[2] & 128) {
171  scanline[0] = 2;
172  scanline[3] = i;
173  ret = decompress(scanline + 4, width - 1, &gb, scanline);
174  if (ret < 0)
175  return ret;
176  goto convert;
177  }
178 
179  for (int i = 0; i < 4; i++) {
180  uint8_t *scanline = p->data[0] + y * p->linesize[0] + i;
181 
182  for (int j = 0; j < width * 4 && bytestream2_get_bytes_left(&gb) > 0;) {
183  int run = bytestream2_get_byte(&gb);
184  if (run > 128) {
185  uint8_t val = bytestream2_get_byte(&gb);
186  run &= 127;
187  while (run--) {
188  if (j >= width * 4)
189  break;
190  scanline[j] = val;
191  j += 4;
192  }
193  } else if (run > 0) {
194  while (run--) {
195  if (j >= width * 4)
196  break;
197  scanline[j] = bytestream2_get_byte(&gb);
198  j += 4;
199  }
200  }
201  }
202  }
203 
204 convert:
205  for (int x = 0; x < width; x++) {
206  uint8_t rgbe[4];
207  int expo;
208 
209  memcpy(rgbe, p->data[0] + y * p->linesize[0] + x * 4, 4);
210  expo = rgbe[3] - 128;
211 
212  dst_r[x] = convert(expo, rgbe[0]);
213  dst_b[x] = convert(expo, rgbe[2]);
214  dst_g[x] = convert(expo, rgbe[1]);
215  }
216  }
217 
218  *got_frame = 1;
219 
220  return avpkt->size;
221 }
222 
224  .p.name = "hdr",
225  CODEC_LONG_NAME("HDR (Radiance RGBE format) image"),
226  .p.type = AVMEDIA_TYPE_VIDEO,
227  .p.id = AV_CODEC_ID_RADIANCE_HDR,
228  .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
229  .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
231 };
bytestream2_get_bytes_left
static av_always_inline int bytestream2_get_bytes_left(const GetByteContext *g)
Definition: bytestream.h:158
GetByteContext
Definition: bytestream.h:33
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:427
AVPacket::data
uint8_t * data
Definition: packet.h:588
decompress
static int decompress(uint8_t *scanline, int w, GetByteContext *gb, const uint8_t *start)
Definition: hdrdec.c:56
FFCodec
Definition: codec_internal.h:127
convert
static float convert(int expo, int val)
Definition: hdrdec.c:45
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:91
ff_hdr_decoder
const FFCodec ff_hdr_decoder
Definition: hdrdec.c:223
thread.h
bytestream2_skip
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:168
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:131
AVCodecContext::skip_frame
enum AVDiscard skip_frame
Skip decoding for selected frames.
Definition: avcodec.h:1670
val
static double val(void *priv, double ch)
Definition: aeval.c:77
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:347
ff_thread_get_buffer
int ff_thread_get_buffer(AVCodecContext *avctx, AVFrame *f, int flags)
Wrapper around get_buffer() for frame-multithreaded codecs.
Definition: pthread_frame.c:1043
hdr_get_line
static int hdr_get_line(GetByteContext *gb, uint8_t *buffer, int size)
Definition: hdrdec.c:30
decode.h
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:332
AV_CODEC_CAP_FRAME_THREADS
#define AV_CODEC_CAP_FRAME_THREADS
Codec supports frame-level multithreading.
Definition: codec.h:95
AVDISCARD_ALL
@ AVDISCARD_ALL
discard all
Definition: defs.h:232
ldexpf
#define ldexpf(x, exp)
Definition: libm.h:391
run
uint8_t run
Definition: svq3.c:207
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
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:589
height
#define height
Definition: dsp.h:89
codec_internal.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
AV_PIX_FMT_GBRPF32
#define AV_PIX_FMT_GBRPF32
Definition: pixfmt.h:578
size
int size
Definition: twinvq_data.h:10344
FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM
#define FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM
The decoder extracts and fills its parameters even if the frame is skipped due to the skip_frame sett...
Definition: codec_internal.h:54
line
Definition: graph2dot.c:48
av_d2q
AVRational av_d2q(double d, int max)
Convert a double precision floating point number to a rational.
Definition: rational.c:106
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:179
av_inv_q
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
Definition: rational.h:159
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:639
avcodec.h
ret
ret
Definition: filter_design.txt:187
AVCodecContext
main external API structure.
Definition: avcodec.h:439
hdr_decode_frame
static int hdr_decode_frame(AVCodecContext *avctx, AVFrame *p, int *got_frame, AVPacket *avpkt)
Definition: hdrdec.c:90
buffer
the frame and frame reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFrame structures Several references can point to the same frame buffer
Definition: filter_design.txt:49
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:200
w
uint8_t w
Definition: llvidencdsp.c:39
AVPacket
This structure stores compressed data.
Definition: packet.h:565
bytestream.h
bytestream2_init
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:137
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
AV_CODEC_ID_RADIANCE_HDR
@ AV_CODEC_ID_RADIANCE_HDR
Definition: codec_id.h:320
width
#define width
Definition: dsp.h:89
AVCodecContext::sample_aspect_ratio
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown) That is the width of a pixel divided by the height of the pixel.
Definition: avcodec.h:624
MAXELEN
#define MAXELEN
Definition: hdrdec.c:28