Libav
|
00001 /* 00002 * DPX (.dpx) image decoder 00003 * Copyright (c) 2009 Jimmy Christensen 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg 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 * FFmpeg 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 FFmpeg; 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 "bytestream.h" 00024 #include "avcodec.h" 00025 00026 typedef struct DPXContext { 00027 AVFrame picture; 00028 } DPXContext; 00029 00030 00031 static unsigned int read32(const uint8_t **ptr, int is_big) 00032 { 00033 unsigned int temp; 00034 if (is_big) { 00035 temp = AV_RB32(*ptr); 00036 } else { 00037 temp = AV_RL32(*ptr); 00038 } 00039 *ptr += 4; 00040 return temp; 00041 } 00042 00043 static inline unsigned make_16bit(unsigned value) 00044 { 00045 // mask away invalid bits 00046 value &= 0xFFC0; 00047 // correctly expand to 16 bits 00048 return value + (value >> 10); 00049 } 00050 00051 static int decode_frame(AVCodecContext *avctx, 00052 void *data, 00053 int *data_size, 00054 AVPacket *avpkt) 00055 { 00056 const uint8_t *buf = avpkt->data; 00057 int buf_size = avpkt->size; 00058 DPXContext *const s = avctx->priv_data; 00059 AVFrame *picture = data; 00060 AVFrame *const p = &s->picture; 00061 uint8_t *ptr; 00062 00063 int magic_num, offset, endian; 00064 int x, y; 00065 int w, h, stride, bits_per_color, descriptor, elements, target_packet_size, source_packet_size; 00066 00067 unsigned int rgbBuffer; 00068 00069 magic_num = AV_RB32(buf); 00070 buf += 4; 00071 00072 /* Check if the files "magic number" is "SDPX" which means it uses 00073 * big-endian or XPDS which is for little-endian files */ 00074 if (magic_num == AV_RL32("SDPX")) { 00075 endian = 0; 00076 } else if (magic_num == AV_RB32("SDPX")) { 00077 endian = 1; 00078 } else { 00079 av_log(avctx, AV_LOG_ERROR, "DPX marker not found\n"); 00080 return -1; 00081 } 00082 00083 offset = read32(&buf, endian); 00084 // Need to end in 0x304 offset from start of file 00085 buf = avpkt->data + 0x304; 00086 w = read32(&buf, endian); 00087 h = read32(&buf, endian); 00088 00089 // Need to end in 0x320 to read the descriptor 00090 buf += 20; 00091 descriptor = buf[0]; 00092 00093 // Need to end in 0x323 to read the bits per color 00094 buf += 3; 00095 avctx->bits_per_raw_sample = 00096 bits_per_color = buf[0]; 00097 00098 switch (descriptor) { 00099 case 51: // RGBA 00100 elements = 4; 00101 break; 00102 case 50: // RGB 00103 elements = 3; 00104 break; 00105 default: 00106 av_log(avctx, AV_LOG_ERROR, "Unsupported descriptor %d\n", descriptor); 00107 return -1; 00108 } 00109 00110 switch (bits_per_color) { 00111 case 8: 00112 if (elements == 4) { 00113 avctx->pix_fmt = PIX_FMT_RGBA; 00114 } else { 00115 avctx->pix_fmt = PIX_FMT_RGB24; 00116 } 00117 source_packet_size = elements; 00118 target_packet_size = elements; 00119 break; 00120 case 10: 00121 avctx->pix_fmt = PIX_FMT_RGB48; 00122 target_packet_size = 6; 00123 source_packet_size = elements * 2; 00124 break; 00125 case 12: 00126 case 16: 00127 if (endian) { 00128 avctx->pix_fmt = PIX_FMT_RGB48BE; 00129 } else { 00130 avctx->pix_fmt = PIX_FMT_RGB48LE; 00131 } 00132 target_packet_size = 6; 00133 source_packet_size = elements * 2; 00134 break; 00135 default: 00136 av_log(avctx, AV_LOG_ERROR, "Unsupported color depth : %d\n", bits_per_color); 00137 return -1; 00138 } 00139 00140 if (s->picture.data[0]) 00141 avctx->release_buffer(avctx, &s->picture); 00142 if (avcodec_check_dimensions(avctx, w, h)) 00143 return -1; 00144 if (w != avctx->width || h != avctx->height) 00145 avcodec_set_dimensions(avctx, w, h); 00146 if (avctx->get_buffer(avctx, p) < 0) { 00147 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00148 return -1; 00149 } 00150 00151 // Move pointer to offset from start of file 00152 buf = avpkt->data + offset; 00153 00154 ptr = p->data[0]; 00155 stride = p->linesize[0]; 00156 00157 switch (bits_per_color) { 00158 case 10: 00159 for (x = 0; x < avctx->height; x++) { 00160 uint16_t *dst = (uint16_t*)ptr; 00161 for (y = 0; y < avctx->width; y++) { 00162 rgbBuffer = read32(&buf, endian); 00163 // Read out the 10-bit colors and convert to 16-bit 00164 *dst++ = make_16bit(rgbBuffer >> 16); 00165 *dst++ = make_16bit(rgbBuffer >> 6); 00166 *dst++ = make_16bit(rgbBuffer << 4); 00167 } 00168 ptr += stride; 00169 } 00170 break; 00171 case 8: 00172 case 12: // Treat 12-bit as 16-bit 00173 case 16: 00174 if (source_packet_size == target_packet_size) { 00175 for (x = 0; x < avctx->height; x++) { 00176 memcpy(ptr, buf, target_packet_size*avctx->width); 00177 ptr += stride; 00178 buf += source_packet_size*avctx->width; 00179 } 00180 } else { 00181 for (x = 0; x < avctx->height; x++) { 00182 uint8_t *dst = ptr; 00183 for (y = 0; y < avctx->width; y++) { 00184 memcpy(dst, buf, target_packet_size); 00185 dst += target_packet_size; 00186 buf += source_packet_size; 00187 } 00188 ptr += stride; 00189 } 00190 } 00191 break; 00192 } 00193 00194 *picture = s->picture; 00195 *data_size = sizeof(AVPicture); 00196 00197 return buf_size; 00198 } 00199 00200 static av_cold int decode_init(AVCodecContext *avctx) 00201 { 00202 DPXContext *s = avctx->priv_data; 00203 avcodec_get_frame_defaults(&s->picture); 00204 avctx->coded_frame = &s->picture; 00205 return 0; 00206 } 00207 00208 static av_cold int decode_end(AVCodecContext *avctx) 00209 { 00210 DPXContext *s = avctx->priv_data; 00211 if (s->picture.data[0]) 00212 avctx->release_buffer(avctx, &s->picture); 00213 00214 return 0; 00215 } 00216 00217 AVCodec dpx_decoder = { 00218 "dpx", 00219 AVMEDIA_TYPE_VIDEO, 00220 CODEC_ID_DPX, 00221 sizeof(DPXContext), 00222 decode_init, 00223 NULL, 00224 decode_end, 00225 decode_frame, 00226 0, 00227 NULL, 00228 .long_name = NULL_IF_CONFIG_SMALL("DPX image"), 00229 };