Libav 0.7.1
|
00001 /* 00002 * DPX (.dpx) image decoder 00003 * Copyright (c) 2009 Jimmy Christensen 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00022 #include "libavutil/intreadwrite.h" 00023 #include "libavutil/imgutils.h" 00024 #include "bytestream.h" 00025 #include "avcodec.h" 00026 00027 typedef struct DPXContext { 00028 AVFrame picture; 00029 } DPXContext; 00030 00031 00032 static unsigned int read32(const uint8_t **ptr, int is_big) 00033 { 00034 unsigned int temp; 00035 if (is_big) { 00036 temp = AV_RB32(*ptr); 00037 } else { 00038 temp = AV_RL32(*ptr); 00039 } 00040 *ptr += 4; 00041 return temp; 00042 } 00043 00044 static inline unsigned make_16bit(unsigned value) 00045 { 00046 // mask away invalid bits 00047 value &= 0xFFC0; 00048 // correctly expand to 16 bits 00049 return value + (value >> 10); 00050 } 00051 00052 static int decode_frame(AVCodecContext *avctx, 00053 void *data, 00054 int *data_size, 00055 AVPacket *avpkt) 00056 { 00057 const uint8_t *buf = avpkt->data; 00058 const uint8_t *buf_end = avpkt->data + avpkt->size; 00059 int buf_size = avpkt->size; 00060 DPXContext *const s = avctx->priv_data; 00061 AVFrame *picture = data; 00062 AVFrame *const p = &s->picture; 00063 uint8_t *ptr; 00064 00065 int magic_num, offset, endian; 00066 int x, y; 00067 int w, h, stride, bits_per_color, descriptor, elements, target_packet_size, source_packet_size; 00068 00069 unsigned int rgbBuffer; 00070 00071 if (avpkt->size <= 1634) { 00072 av_log(avctx, AV_LOG_ERROR, "Packet too small for DPX header\n"); 00073 return AVERROR_INVALIDDATA; 00074 } 00075 00076 magic_num = AV_RB32(buf); 00077 buf += 4; 00078 00079 /* Check if the files "magic number" is "SDPX" which means it uses 00080 * big-endian or XPDS which is for little-endian files */ 00081 if (magic_num == AV_RL32("SDPX")) { 00082 endian = 0; 00083 } else if (magic_num == AV_RB32("SDPX")) { 00084 endian = 1; 00085 } else { 00086 av_log(avctx, AV_LOG_ERROR, "DPX marker not found\n"); 00087 return -1; 00088 } 00089 00090 offset = read32(&buf, endian); 00091 if (avpkt->size <= offset) { 00092 av_log(avctx, AV_LOG_ERROR, "Invalid data start offset\n"); 00093 return AVERROR_INVALIDDATA; 00094 } 00095 // Need to end in 0x304 offset from start of file 00096 buf = avpkt->data + 0x304; 00097 w = read32(&buf, endian); 00098 h = read32(&buf, endian); 00099 00100 // Need to end in 0x320 to read the descriptor 00101 buf += 20; 00102 descriptor = buf[0]; 00103 00104 // Need to end in 0x323 to read the bits per color 00105 buf += 3; 00106 avctx->bits_per_raw_sample = 00107 bits_per_color = buf[0]; 00108 00109 buf += 825; 00110 avctx->sample_aspect_ratio.num = read32(&buf, endian); 00111 avctx->sample_aspect_ratio.den = read32(&buf, endian); 00112 00113 switch (descriptor) { 00114 case 51: // RGBA 00115 elements = 4; 00116 break; 00117 case 50: // RGB 00118 elements = 3; 00119 break; 00120 default: 00121 av_log(avctx, AV_LOG_ERROR, "Unsupported descriptor %d\n", descriptor); 00122 return -1; 00123 } 00124 00125 switch (bits_per_color) { 00126 case 8: 00127 if (elements == 4) { 00128 avctx->pix_fmt = PIX_FMT_RGBA; 00129 } else { 00130 avctx->pix_fmt = PIX_FMT_RGB24; 00131 } 00132 source_packet_size = elements; 00133 target_packet_size = elements; 00134 break; 00135 case 10: 00136 avctx->pix_fmt = PIX_FMT_RGB48; 00137 target_packet_size = 6; 00138 source_packet_size = 4; 00139 break; 00140 case 12: 00141 case 16: 00142 if (endian) { 00143 avctx->pix_fmt = PIX_FMT_RGB48BE; 00144 } else { 00145 avctx->pix_fmt = PIX_FMT_RGB48LE; 00146 } 00147 target_packet_size = 6; 00148 source_packet_size = elements * 2; 00149 break; 00150 default: 00151 av_log(avctx, AV_LOG_ERROR, "Unsupported color depth : %d\n", bits_per_color); 00152 return -1; 00153 } 00154 00155 if (s->picture.data[0]) 00156 avctx->release_buffer(avctx, &s->picture); 00157 if (av_image_check_size(w, h, 0, avctx)) 00158 return -1; 00159 if (w != avctx->width || h != avctx->height) 00160 avcodec_set_dimensions(avctx, w, h); 00161 if (avctx->get_buffer(avctx, p) < 0) { 00162 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00163 return -1; 00164 } 00165 00166 // Move pointer to offset from start of file 00167 buf = avpkt->data + offset; 00168 00169 ptr = p->data[0]; 00170 stride = p->linesize[0]; 00171 00172 if (source_packet_size*avctx->width*avctx->height > buf_end - buf) { 00173 av_log(avctx, AV_LOG_ERROR, "Overread buffer. Invalid header?\n"); 00174 return -1; 00175 } 00176 switch (bits_per_color) { 00177 case 10: 00178 for (x = 0; x < avctx->height; x++) { 00179 uint16_t *dst = (uint16_t*)ptr; 00180 for (y = 0; y < avctx->width; y++) { 00181 rgbBuffer = read32(&buf, endian); 00182 // Read out the 10-bit colors and convert to 16-bit 00183 *dst++ = make_16bit(rgbBuffer >> 16); 00184 *dst++ = make_16bit(rgbBuffer >> 6); 00185 *dst++ = make_16bit(rgbBuffer << 4); 00186 } 00187 ptr += stride; 00188 } 00189 break; 00190 case 8: 00191 case 12: // Treat 12-bit as 16-bit 00192 case 16: 00193 if (source_packet_size == target_packet_size) { 00194 for (x = 0; x < avctx->height; x++) { 00195 memcpy(ptr, buf, target_packet_size*avctx->width); 00196 ptr += stride; 00197 buf += source_packet_size*avctx->width; 00198 } 00199 } else { 00200 for (x = 0; x < avctx->height; x++) { 00201 uint8_t *dst = ptr; 00202 for (y = 0; y < avctx->width; y++) { 00203 memcpy(dst, buf, target_packet_size); 00204 dst += target_packet_size; 00205 buf += source_packet_size; 00206 } 00207 ptr += stride; 00208 } 00209 } 00210 break; 00211 } 00212 00213 *picture = s->picture; 00214 *data_size = sizeof(AVPicture); 00215 00216 return buf_size; 00217 } 00218 00219 static av_cold int decode_init(AVCodecContext *avctx) 00220 { 00221 DPXContext *s = avctx->priv_data; 00222 avcodec_get_frame_defaults(&s->picture); 00223 avctx->coded_frame = &s->picture; 00224 return 0; 00225 } 00226 00227 static av_cold int decode_end(AVCodecContext *avctx) 00228 { 00229 DPXContext *s = avctx->priv_data; 00230 if (s->picture.data[0]) 00231 avctx->release_buffer(avctx, &s->picture); 00232 00233 return 0; 00234 } 00235 00236 AVCodec ff_dpx_decoder = { 00237 "dpx", 00238 AVMEDIA_TYPE_VIDEO, 00239 CODEC_ID_DPX, 00240 sizeof(DPXContext), 00241 decode_init, 00242 NULL, 00243 decode_end, 00244 decode_frame, 00245 0, 00246 NULL, 00247 .long_name = NULL_IF_CONFIG_SMALL("DPX image"), 00248 };