2 * DPX (.dpx) image decoder
3 * Copyright (c) 2009 Jimmy Christensen
5 * This file is part of Libav.
7 * Libav 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.
12 * Libav 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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "libavutil/intreadwrite.h"
23 #include "libavutil/imgutils.h"
24 #include "bytestream.h"
28 typedef struct DPXContext
{
33 static unsigned int read32(const uint8_t **ptr
, int is_big
)
45 static inline unsigned make_16bit(unsigned value
)
47 // mask away invalid bits
49 // correctly expand to 16 bits
50 return value
+ (value
>> 10);
53 static int decode_frame(AVCodecContext
*avctx
,
58 const uint8_t *buf
= avpkt
->data
;
59 const uint8_t *buf_end
= avpkt
->data
+ avpkt
->size
;
60 int buf_size
= avpkt
->size
;
61 DPXContext
*const s
= avctx
->priv_data
;
62 AVFrame
*picture
= data
;
63 AVFrame
*const p
= &s
->picture
;
67 int magic_num
, endian
;
69 int w
, h
, stride
, bits_per_color
, descriptor
, elements
, target_packet_size
, source_packet_size
;
71 unsigned int rgbBuffer
;
73 if (avpkt
->size
<= 1634) {
74 av_log(avctx
, AV_LOG_ERROR
, "Packet too small for DPX header\n");
75 return AVERROR_INVALIDDATA
;
78 magic_num
= AV_RB32(buf
);
81 /* Check if the files "magic number" is "SDPX" which means it uses
82 * big-endian or XPDS which is for little-endian files */
83 if (magic_num
== AV_RL32("SDPX")) {
85 } else if (magic_num
== AV_RB32("SDPX")) {
88 av_log(avctx
, AV_LOG_ERROR
, "DPX marker not found\n");
89 return AVERROR_INVALIDDATA
;
92 offset
= read32(&buf
, endian
);
93 if (avpkt
->size
<= offset
) {
94 av_log(avctx
, AV_LOG_ERROR
, "Invalid data start offset\n");
95 return AVERROR_INVALIDDATA
;
97 // Need to end in 0x304 offset from start of file
98 buf
= avpkt
->data
+ 0x304;
99 w
= read32(&buf
, endian
);
100 h
= read32(&buf
, endian
);
102 // Need to end in 0x320 to read the descriptor
106 // Need to end in 0x323 to read the bits per color
108 avctx
->bits_per_raw_sample
=
109 bits_per_color
= buf
[0];
112 avctx
->sample_aspect_ratio
.num
= read32(&buf
, endian
);
113 avctx
->sample_aspect_ratio
.den
= read32(&buf
, endian
);
115 switch (descriptor
) {
123 av_log(avctx
, AV_LOG_ERROR
, "Unsupported descriptor %d\n", descriptor
);
124 return AVERROR_INVALIDDATA
;
127 switch (bits_per_color
) {
130 avctx
->pix_fmt
= AV_PIX_FMT_RGBA
;
132 avctx
->pix_fmt
= AV_PIX_FMT_RGB24
;
134 source_packet_size
= elements
;
135 target_packet_size
= elements
;
138 avctx
->pix_fmt
= AV_PIX_FMT_RGB48
;
139 target_packet_size
= 6;
140 source_packet_size
= 4;
145 avctx
->pix_fmt
= AV_PIX_FMT_RGB48BE
;
147 avctx
->pix_fmt
= AV_PIX_FMT_RGB48LE
;
149 target_packet_size
= 6;
150 source_packet_size
= elements
* 2;
153 av_log(avctx
, AV_LOG_ERROR
, "Unsupported color depth : %d\n", bits_per_color
);
154 return AVERROR_INVALIDDATA
;
157 if (s
->picture
.data
[0])
158 avctx
->release_buffer(avctx
, &s
->picture
);
159 if ((ret
= av_image_check_size(w
, h
, 0, avctx
)) < 0)
161 if (w
!= avctx
->width
|| h
!= avctx
->height
)
162 avcodec_set_dimensions(avctx
, w
, h
);
163 if ((ret
= ff_get_buffer(avctx
, p
)) < 0) {
164 av_log(avctx
, AV_LOG_ERROR
, "get_buffer() failed\n");
168 // Move pointer to offset from start of file
169 buf
= avpkt
->data
+ offset
;
172 stride
= p
->linesize
[0];
174 if (source_packet_size
*avctx
->width
*avctx
->height
> buf_end
- buf
) {
175 av_log(avctx
, AV_LOG_ERROR
, "Overread buffer. Invalid header?\n");
176 return AVERROR_INVALIDDATA
;
178 switch (bits_per_color
) {
180 for (x
= 0; x
< avctx
->height
; x
++) {
181 uint16_t *dst
= (uint16_t*)ptr
;
182 for (y
= 0; y
< avctx
->width
; y
++) {
183 rgbBuffer
= read32(&buf
, endian
);
184 // Read out the 10-bit colors and convert to 16-bit
185 *dst
++ = make_16bit(rgbBuffer
>> 16);
186 *dst
++ = make_16bit(rgbBuffer
>> 6);
187 *dst
++ = make_16bit(rgbBuffer
<< 4);
193 case 12: // Treat 12-bit as 16-bit
195 if (source_packet_size
== target_packet_size
) {
196 for (x
= 0; x
< avctx
->height
; x
++) {
197 memcpy(ptr
, buf
, target_packet_size
*avctx
->width
);
199 buf
+= source_packet_size
*avctx
->width
;
202 for (x
= 0; x
< avctx
->height
; x
++) {
204 for (y
= 0; y
< avctx
->width
; y
++) {
205 memcpy(dst
, buf
, target_packet_size
);
206 dst
+= target_packet_size
;
207 buf
+= source_packet_size
;
215 *picture
= s
->picture
;
221 static av_cold
int decode_init(AVCodecContext
*avctx
)
223 DPXContext
*s
= avctx
->priv_data
;
224 avcodec_get_frame_defaults(&s
->picture
);
225 avctx
->coded_frame
= &s
->picture
;
229 static av_cold
int decode_end(AVCodecContext
*avctx
)
231 DPXContext
*s
= avctx
->priv_data
;
232 if (s
->picture
.data
[0])
233 avctx
->release_buffer(avctx
, &s
->picture
);
238 AVCodec ff_dpx_decoder
= {
240 .type
= AVMEDIA_TYPE_VIDEO
,
241 .id
= AV_CODEC_ID_DPX
,
242 .priv_data_size
= sizeof(DPXContext
),
245 .decode
= decode_frame
,
246 .long_name
= NULL_IF_CONFIG_SMALL("DPX image"),
247 .capabilities
= CODEC_CAP_DR1
,