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  scanline[0] = bytestream2_get_byte(gb);
62  scanline[1] = bytestream2_get_byte(gb);
63  scanline[2] = bytestream2_get_byte(gb);
64  scanline[3] = bytestream2_get_byte(gb);
65 
66  if (scanline[0] == 1 &&
67  scanline[1] == 1 &&
68  scanline[2] == 1) {
69  int run = scanline[3];
70  for (int i = run << rshift; i > 0 && w > 0 && scanline >= start + 4; i--) {
71  memcpy(scanline, scanline - 4, 4);
72  scanline += 4;
73  w -= 4;
74  }
75  rshift += 8;
76  if (rshift > 16)
77  break;
78  } else {
79  scanline += 4;
80  w--;
81  rshift = 0;
82  }
83  }
84 
85  return 1;
86 }
87 
88 static int hdr_decode_frame(AVCodecContext *avctx, AVFrame *p,
89  int *got_frame, AVPacket *avpkt)
90 {
91  int width = 0, height = 0;
92  GetByteContext gb;
93  uint8_t line[512];
94  float sar;
95  int ret;
96 
97  bytestream2_init(&gb, avpkt->data, avpkt->size);
98  hdr_get_line(&gb, line, sizeof(line));
99  if (memcmp("#?RADIANCE\n", line, 11))
100  return AVERROR_INVALIDDATA;
101 
102  do {
103  hdr_get_line(&gb, line, sizeof(line));
104  if (sscanf(line, "PIXASPECT=%f\n", &sar) == 1)
105  avctx->sample_aspect_ratio = p->sample_aspect_ratio = av_inv_q(av_d2q(sar, 4096));
106  } while (line[0] != '\n' && line[0]);
107 
108  hdr_get_line(&gb, line, sizeof(line));
109  if (sscanf(line, "-Y %d +X %d\n", &height, &width) == 2) {
110  ;
111  } else 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, "-X %d +Y %d\n", &width, &height) == 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  }
126 
127  if ((ret = ff_set_dimensions(avctx, width, height)) < 0)
128  return ret;
129 
130  avctx->pix_fmt = AV_PIX_FMT_GBRPF32;
131 
132  if (avctx->skip_frame >= AVDISCARD_ALL)
133  return avpkt->size;
134 
135  if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0)
136  return ret;
137 
138  for (int y = 0; y < height; y++) {
139  float *dst_r = (float *)(p->data[2] + y * p->linesize[2]);
140  float *dst_g = (float *)(p->data[0] + y * p->linesize[0]);
141  float *dst_b = (float *)(p->data[1] + y * p->linesize[1]);
142  uint8_t *scanline = p->data[0] + y * p->linesize[0];
143  int i;
144 
145  if (width < MINELEN || width > MAXELEN) {
146  decompress(scanline, width, &gb, scanline);
147  goto convert;
148  }
149 
150  i = bytestream2_peek_byte(&gb);
151  if (i != 2) {
152  decompress(scanline, width, &gb, scanline);
153  goto convert;
154  }
155  bytestream2_skip(&gb, 1);
156 
157  scanline[1] = bytestream2_get_byte(&gb);
158  scanline[2] = bytestream2_get_byte(&gb);
159  i = bytestream2_get_byte(&gb);
160 
161  if (scanline[1] != 2 || scanline[2] & 128) {
162  scanline[0] = 2;
163  scanline[3] = i;
164  decompress(scanline + 4, width - 1, &gb, scanline);
165  goto convert;
166  }
167 
168  for (int i = 0; i < 4; i++) {
169  uint8_t *scanline = p->data[0] + y * p->linesize[0] + i;
170 
171  for (int j = 0; j < width * 4 && bytestream2_get_bytes_left(&gb) > 0;) {
172  int run = bytestream2_get_byte(&gb);
173  if (run > 128) {
174  uint8_t val = bytestream2_get_byte(&gb);
175  run &= 127;
176  while (run--) {
177  if (j >= width * 4)
178  break;
179  scanline[j] = val;
180  j += 4;
181  }
182  } else if (run > 0) {
183  while (run--) {
184  if (j >= width * 4)
185  break;
186  scanline[j] = bytestream2_get_byte(&gb);
187  j += 4;
188  }
189  }
190  }
191  }
192 
193 convert:
194  for (int x = 0; x < width; x++) {
195  uint8_t rgbe[4];
196  int expo;
197 
198  memcpy(rgbe, p->data[0] + y * p->linesize[0] + x * 4, 4);
199  expo = rgbe[3] - 128;
200 
201  dst_r[x] = convert(expo, rgbe[0]);
202  dst_b[x] = convert(expo, rgbe[2]);
203  dst_g[x] = convert(expo, rgbe[1]);
204  }
205  }
206 
207  p->key_frame = 1;
209 
210  *got_frame = 1;
211 
212  return avpkt->size;
213 }
214 
216  .p.name = "hdr",
217  CODEC_LONG_NAME("HDR (Radiance RGBE format) image"),
218  .p.type = AVMEDIA_TYPE_VIDEO,
219  .p.id = AV_CODEC_ID_RADIANCE_HDR,
220  .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
221  .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
223 };
GetByteContext
Definition: bytestream.h:33
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:325
w
uint8_t w
Definition: llviddspenc.c:38
AVPacket::data
uint8_t * data
Definition: packet.h:374
decompress
static int decompress(uint8_t *scanline, int w, GetByteContext *gb, const uint8_t *start)
Definition: hdrdec.c:56
FFCodec
Definition: codec_internal.h:119
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:215
thread.h
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:346
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:123
AVCodecContext::skip_frame
enum AVDiscard skip_frame
Skip decoding for selected frames.
Definition: avcodec.h:1698
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 AVCodec caps_internal and use ff_thread_get_buffer() to allocate frames. The frames must then be freed with ff_thread_release_buffer(). 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
AVFrame::key_frame
int key_frame
1 -> keyframe, 0-> not
Definition: frame.h:417
val
static double val(void *priv, double ch)
Definition: aeval.c:77
width
#define width
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:298
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:264
AV_CODEC_CAP_FRAME_THREADS
#define AV_CODEC_CAP_FRAME_THREADS
Codec supports frame-level multithreading.
Definition: codec.h:113
AVDISCARD_ALL
@ AVDISCARD_ALL
discard all
Definition: defs.h:76
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:274
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:422
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:375
codec_internal.h
AV_PIX_FMT_GBRPF32
#define AV_PIX_FMT_GBRPF32
Definition: pixfmt.h:488
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:269
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:211
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:608
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:427
AVCodecContext
main external API structure.
Definition: avcodec.h:398
hdr_decode_frame
static int hdr_decode_frame(AVCodecContext *avctx, AVFrame *p, int *got_frame, AVPacket *avpkt)
Definition: hdrdec.c:88
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:351
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:370
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:319
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:768
MAXELEN
#define MAXELEN
Definition: hdrdec.c:28