00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00047 value &= 0xFFC0;
00048
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 magic_num = AV_RB32(buf);
00072 buf += 4;
00073
00074
00075
00076 if (magic_num == AV_RL32("SDPX")) {
00077 endian = 0;
00078 } else if (magic_num == AV_RB32("SDPX")) {
00079 endian = 1;
00080 } else {
00081 av_log(avctx, AV_LOG_ERROR, "DPX marker not found\n");
00082 return -1;
00083 }
00084
00085 offset = read32(&buf, endian);
00086
00087 buf = avpkt->data + 0x304;
00088 w = read32(&buf, endian);
00089 h = read32(&buf, endian);
00090
00091
00092 buf += 20;
00093 descriptor = buf[0];
00094
00095
00096 buf += 3;
00097 avctx->bits_per_raw_sample =
00098 bits_per_color = buf[0];
00099
00100 switch (descriptor) {
00101 case 51:
00102 elements = 4;
00103 break;
00104 case 50:
00105 elements = 3;
00106 break;
00107 default:
00108 av_log(avctx, AV_LOG_ERROR, "Unsupported descriptor %d\n", descriptor);
00109 return -1;
00110 }
00111
00112 switch (bits_per_color) {
00113 case 8:
00114 if (elements == 4) {
00115 avctx->pix_fmt = PIX_FMT_RGBA;
00116 } else {
00117 avctx->pix_fmt = PIX_FMT_RGB24;
00118 }
00119 source_packet_size = elements;
00120 target_packet_size = elements;
00121 break;
00122 case 10:
00123 avctx->pix_fmt = PIX_FMT_RGB48;
00124 target_packet_size = 6;
00125 source_packet_size = elements * 2;
00126 break;
00127 case 12:
00128 case 16:
00129 if (endian) {
00130 avctx->pix_fmt = PIX_FMT_RGB48BE;
00131 } else {
00132 avctx->pix_fmt = PIX_FMT_RGB48LE;
00133 }
00134 target_packet_size = 6;
00135 source_packet_size = elements * 2;
00136 break;
00137 default:
00138 av_log(avctx, AV_LOG_ERROR, "Unsupported color depth : %d\n", bits_per_color);
00139 return -1;
00140 }
00141
00142 if (s->picture.data[0])
00143 avctx->release_buffer(avctx, &s->picture);
00144 if (av_image_check_size(w, h, 0, avctx))
00145 return -1;
00146 if (w != avctx->width || h != avctx->height)
00147 avcodec_set_dimensions(avctx, w, h);
00148 if (avctx->get_buffer(avctx, p) < 0) {
00149 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00150 return -1;
00151 }
00152
00153
00154 buf = avpkt->data + offset;
00155
00156 ptr = p->data[0];
00157 stride = p->linesize[0];
00158
00159 switch (bits_per_color) {
00160 case 10:
00161 for (x = 0; x < avctx->height; x++) {
00162 uint16_t *dst = (uint16_t*)ptr;
00163 for (y = 0; y < avctx->width; y++) {
00164 rgbBuffer = read32(&buf, endian);
00165
00166 *dst++ = make_16bit(rgbBuffer >> 16);
00167 *dst++ = make_16bit(rgbBuffer >> 6);
00168 *dst++ = make_16bit(rgbBuffer << 4);
00169 }
00170 ptr += stride;
00171 }
00172 break;
00173 case 8:
00174 case 12:
00175 case 16:
00176 if (source_packet_size*avctx->width*avctx->height > buf_end - buf) {
00177 av_log(avctx, AV_LOG_ERROR, "Overread buffer. Invalid header?\n");
00178 return -1;
00179 }
00180 if (source_packet_size == target_packet_size) {
00181 for (x = 0; x < avctx->height; x++) {
00182 memcpy(ptr, buf, target_packet_size*avctx->width);
00183 ptr += stride;
00184 buf += source_packet_size*avctx->width;
00185 }
00186 } else {
00187 for (x = 0; x < avctx->height; x++) {
00188 uint8_t *dst = ptr;
00189 for (y = 0; y < avctx->width; y++) {
00190 memcpy(dst, buf, target_packet_size);
00191 dst += target_packet_size;
00192 buf += source_packet_size;
00193 }
00194 ptr += stride;
00195 }
00196 }
00197 break;
00198 }
00199
00200 *picture = s->picture;
00201 *data_size = sizeof(AVPicture);
00202
00203 return buf_size;
00204 }
00205
00206 static av_cold int decode_init(AVCodecContext *avctx)
00207 {
00208 DPXContext *s = avctx->priv_data;
00209 avcodec_get_frame_defaults(&s->picture);
00210 avctx->coded_frame = &s->picture;
00211 return 0;
00212 }
00213
00214 static av_cold int decode_end(AVCodecContext *avctx)
00215 {
00216 DPXContext *s = avctx->priv_data;
00217 if (s->picture.data[0])
00218 avctx->release_buffer(avctx, &s->picture);
00219
00220 return 0;
00221 }
00222
00223 AVCodec ff_dpx_decoder = {
00224 "dpx",
00225 AVMEDIA_TYPE_VIDEO,
00226 CODEC_ID_DPX,
00227 sizeof(DPXContext),
00228 decode_init,
00229 NULL,
00230 decode_end,
00231 decode_frame,
00232 0,
00233 NULL,
00234 .long_name = NULL_IF_CONFIG_SMALL("DPX image"),
00235 };