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 
90 static int hdr_decode_frame(AVCodecContext *avctx, AVFrame *p,
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 ((ret = ff_set_dimensions(avctx, width, height)) < 0)
130  return ret;
131 
132  avctx->pix_fmt = AV_PIX_FMT_GBRPF32;
133 
134  if (avctx->skip_frame >= AVDISCARD_ALL)
135  return avpkt->size;
136 
137  if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0)
138  return ret;
139 
140  for (int y = 0; y < height; y++) {
141  float *dst_r = (float *)(p->data[2] + y * p->linesize[2]);
142  float *dst_g = (float *)(p->data[0] + y * p->linesize[0]);
143  float *dst_b = (float *)(p->data[1] + y * p->linesize[1]);
144  uint8_t *scanline = p->data[0] + y * p->linesize[0];
145  int i;
146 
147  if (width < MINELEN || width > MAXELEN) {
148  ret = decompress(scanline, width, &gb, scanline);
149  if (ret < 0)
150  return ret;
151  goto convert;
152  }
153 
154  i = bytestream2_peek_byte(&gb);
155  if (i != 2) {
156  ret = decompress(scanline, width, &gb, scanline);
157  if (ret < 0)
158  return ret;
159  goto convert;
160  }
161  bytestream2_skip(&gb, 1);
162 
163  scanline[1] = bytestream2_get_byte(&gb);
164  scanline[2] = bytestream2_get_byte(&gb);
165  i = bytestream2_get_byte(&gb);
166 
167  if (scanline[1] != 2 || scanline[2] & 128) {
168  scanline[0] = 2;
169  scanline[3] = i;
170  ret = decompress(scanline + 4, width - 1, &gb, scanline);
171  if (ret < 0)
172  return ret;
173  goto convert;
174  }
175 
176  for (int i = 0; i < 4; i++) {
177  uint8_t *scanline = p->data[0] + y * p->linesize[0] + i;
178 
179  for (int j = 0; j < width * 4 && bytestream2_get_bytes_left(&gb) > 0;) {
180  int run = bytestream2_get_byte(&gb);
181  if (run > 128) {
182  uint8_t val = bytestream2_get_byte(&gb);
183  run &= 127;
184  while (run--) {
185  if (j >= width * 4)
186  break;
187  scanline[j] = val;
188  j += 4;
189  }
190  } else if (run > 0) {
191  while (run--) {
192  if (j >= width * 4)
193  break;
194  scanline[j] = bytestream2_get_byte(&gb);
195  j += 4;
196  }
197  }
198  }
199  }
200 
201 convert:
202  for (int x = 0; x < width; x++) {
203  uint8_t rgbe[4];
204  int expo;
205 
206  memcpy(rgbe, p->data[0] + y * p->linesize[0] + x * 4, 4);
207  expo = rgbe[3] - 128;
208 
209  dst_r[x] = convert(expo, rgbe[0]);
210  dst_b[x] = convert(expo, rgbe[2]);
211  dst_g[x] = convert(expo, rgbe[1]);
212  }
213  }
214 
215  p->flags |= AV_FRAME_FLAG_KEY;
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 };
GetByteContext
Definition: bytestream.h:33
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:375
w
uint8_t w
Definition: llviddspenc.c:38
AVPacket::data
uint8_t * data
Definition: packet.h:522
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
AVFrame::flags
int flags
Frame flags, a combination of AV_FRAME_FLAGS.
Definition: frame.h:647
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:94
ff_hdr_decoder
const FFCodec ff_hdr_decoder
Definition: hdrdec.c:223
thread.h
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:396
ff_thread_get_buffer
the pkt_dts and pkt_pts fields in AVFrame will work as usual Restrictions on codec whose streams don t reset across will not work because their bitstreams cannot be decoded in parallel *The contents of buffers must not be read before as well as code calling up to before the decode process starts Call have so the codec calls ff_thread_report set FF_CODEC_CAP_ALLOCATE_PROGRESS in FFCodec caps_internal and use ff_thread_get_buffer() to allocate frames. Otherwise decode directly into the user-supplied frames. Call ff_thread_report_progress() after some part of the current picture has decoded. A good place to put this is where draw_horiz_band() is called - add this if it isn 't called anywhere
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:1819
val
static double val(void *priv, double ch)
Definition: aeval.c:78
AV_FRAME_FLAG_KEY
#define AV_FRAME_FLAG_KEY
A flag to mark frames that are keyframes.
Definition: frame.h:626
width
#define width
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:287
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:272
AV_CODEC_CAP_FRAME_THREADS
#define AV_CODEC_CAP_FRAME_THREADS
Codec supports frame-level multithreading.
Definition: codec.h:110
AVDISCARD_ALL
@ AVDISCARD_ALL
discard all
Definition: defs.h:219
ldexpf
#define ldexpf(x, exp)
Definition: libm.h:389
run
uint8_t run
Definition: svq3.c:203
AV_PICTURE_TYPE_I
@ AV_PICTURE_TYPE_I
Intra.
Definition: avutil.h:279
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
bytestream2_get_bytes_left
static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:158
AVFrame::pict_type
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:477
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:523
codec_internal.h
AV_PIX_FMT_GBRPF32
#define AV_PIX_FMT_GBRPF32
Definition: pixfmt.h:508
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
height
#define height
line
Definition: graph2dot.c:48
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:255
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:194
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:657
avcodec.h
ret
ret
Definition: filter_design.txt:187
AVFrame::sample_aspect_ratio
AVRational sample_aspect_ratio
Sample aspect ratio for the video frame, 0/1 if unknown/unspecified.
Definition: frame.h:482
AVCodecContext
main external API structure.
Definition: avcodec.h:445
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
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
AVPacket
This structure stores compressed data.
Definition: packet.h:499
bytestream.h
bytestream2_init
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:137
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition: frame.h:420
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:316
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:642
MAXELEN
#define MAXELEN
Definition: hdrdec.c:28