1/* 2 * DPX (.dpx) image decoder 3 * Copyright (c) 2009 Jimmy Christensen 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#include "libavutil/intreadwrite.h" 23#include "bytestream.h" 24#include "avcodec.h" 25 26typedef struct DPXContext { 27 AVFrame picture; 28} DPXContext; 29 30 31static unsigned int read32(const uint8_t **ptr, int is_big) 32{ 33 unsigned int temp; 34 if (is_big) { 35 temp = AV_RB32(*ptr); 36 } else { 37 temp = AV_RL32(*ptr); 38 } 39 *ptr += 4; 40 return temp; 41} 42 43static inline unsigned make_16bit(unsigned value) 44{ 45 // mask away invalid bits 46 value &= 0xFFC0; 47 // correctly expand to 16 bits 48 return value + (value >> 10); 49} 50 51static int decode_frame(AVCodecContext *avctx, 52 void *data, 53 int *data_size, 54 AVPacket *avpkt) 55{ 56 const uint8_t *buf = avpkt->data; 57 int buf_size = avpkt->size; 58 DPXContext *const s = avctx->priv_data; 59 AVFrame *picture = data; 60 AVFrame *const p = &s->picture; 61 uint8_t *ptr; 62 63 int magic_num, offset, endian; 64 int x, y; 65 int w, h, stride, bits_per_color, descriptor, elements, target_packet_size, source_packet_size; 66 67 unsigned int rgbBuffer; 68 69 magic_num = AV_RB32(buf); 70 buf += 4; 71 72 /* Check if the files "magic number" is "SDPX" which means it uses 73 * big-endian or XPDS which is for little-endian files */ 74 if (magic_num == AV_RL32("SDPX")) { 75 endian = 0; 76 } else if (magic_num == AV_RB32("SDPX")) { 77 endian = 1; 78 } else { 79 av_log(avctx, AV_LOG_ERROR, "DPX marker not found\n"); 80 return -1; 81 } 82 83 offset = read32(&buf, endian); 84 // Need to end in 0x304 offset from start of file 85 buf = avpkt->data + 0x304; 86 w = read32(&buf, endian); 87 h = read32(&buf, endian); 88 89 // Need to end in 0x320 to read the descriptor 90 buf += 20; 91 descriptor = buf[0]; 92 93 // Need to end in 0x323 to read the bits per color 94 buf += 3; 95 avctx->bits_per_raw_sample = 96 bits_per_color = buf[0]; 97 98 switch (descriptor) { 99 case 51: // RGBA 100 elements = 4; 101 break; 102 case 50: // RGB 103 elements = 3; 104 break; 105 default: 106 av_log(avctx, AV_LOG_ERROR, "Unsupported descriptor %d\n", descriptor); 107 return -1; 108 } 109 110 switch (bits_per_color) { 111 case 8: 112 if (elements == 4) { 113 avctx->pix_fmt = PIX_FMT_RGBA; 114 } else { 115 avctx->pix_fmt = PIX_FMT_RGB24; 116 } 117 source_packet_size = elements; 118 target_packet_size = elements; 119 break; 120 case 10: 121 avctx->pix_fmt = PIX_FMT_RGB48; 122 target_packet_size = 6; 123 source_packet_size = elements * 2; 124 break; 125 case 12: 126 case 16: 127 if (endian) { 128 avctx->pix_fmt = PIX_FMT_RGB48BE; 129 } else { 130 avctx->pix_fmt = PIX_FMT_RGB48LE; 131 } 132 target_packet_size = 6; 133 source_packet_size = elements * 2; 134 break; 135 default: 136 av_log(avctx, AV_LOG_ERROR, "Unsupported color depth : %d\n", bits_per_color); 137 return -1; 138 } 139 140 if (s->picture.data[0]) 141 avctx->release_buffer(avctx, &s->picture); 142 if (avcodec_check_dimensions(avctx, w, h)) 143 return -1; 144 if (w != avctx->width || h != avctx->height) 145 avcodec_set_dimensions(avctx, w, h); 146 if (avctx->get_buffer(avctx, p) < 0) { 147 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 148 return -1; 149 } 150 151 // Move pointer to offset from start of file 152 buf = avpkt->data + offset; 153 154 ptr = p->data[0]; 155 stride = p->linesize[0]; 156 157 switch (bits_per_color) { 158 case 10: 159 for (x = 0; x < avctx->height; x++) { 160 uint16_t *dst = (uint16_t*)ptr; 161 for (y = 0; y < avctx->width; y++) { 162 rgbBuffer = read32(&buf, endian); 163 // Read out the 10-bit colors and convert to 16-bit 164 *dst++ = make_16bit(rgbBuffer >> 16); 165 *dst++ = make_16bit(rgbBuffer >> 6); 166 *dst++ = make_16bit(rgbBuffer << 4); 167 } 168 ptr += stride; 169 } 170 break; 171 case 8: 172 case 12: // Treat 12-bit as 16-bit 173 case 16: 174 if (source_packet_size == target_packet_size) { 175 for (x = 0; x < avctx->height; x++) { 176 memcpy(ptr, buf, target_packet_size*avctx->width); 177 ptr += stride; 178 buf += source_packet_size*avctx->width; 179 } 180 } else { 181 for (x = 0; x < avctx->height; x++) { 182 uint8_t *dst = ptr; 183 for (y = 0; y < avctx->width; y++) { 184 memcpy(dst, buf, target_packet_size); 185 dst += target_packet_size; 186 buf += source_packet_size; 187 } 188 ptr += stride; 189 } 190 } 191 break; 192 } 193 194 *picture = s->picture; 195 *data_size = sizeof(AVPicture); 196 197 return buf_size; 198} 199 200static av_cold int decode_init(AVCodecContext *avctx) 201{ 202 DPXContext *s = avctx->priv_data; 203 avcodec_get_frame_defaults(&s->picture); 204 avctx->coded_frame = &s->picture; 205 return 0; 206} 207 208static av_cold int decode_end(AVCodecContext *avctx) 209{ 210 DPXContext *s = avctx->priv_data; 211 if (s->picture.data[0]) 212 avctx->release_buffer(avctx, &s->picture); 213 214 return 0; 215} 216 217AVCodec dpx_decoder = { 218 "dpx", 219 AVMEDIA_TYPE_VIDEO, 220 CODEC_ID_DPX, 221 sizeof(DPXContext), 222 decode_init, 223 NULL, 224 decode_end, 225 decode_frame, 226 0, 227 NULL, 228 .long_name = NULL_IF_CONFIG_SMALL("DPX image"), 229}; 230