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 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
00080
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
00096 buf = avpkt->data + 0x304;
00097 w = read32(&buf, endian);
00098 h = read32(&buf, endian);
00099
00100
00101 buf += 20;
00102 descriptor = buf[0];
00103
00104
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:
00115 elements = 4;
00116 break;
00117 case 50:
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
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
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:
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 .name = "dpx",
00238 .type = AVMEDIA_TYPE_VIDEO,
00239 .id = CODEC_ID_DPX,
00240 .priv_data_size = sizeof(DPXContext),
00241 .init = decode_init,
00242 .close = decode_end,
00243 .decode = decode_frame,
00244 .long_name = NULL_IF_CONFIG_SMALL("DPX image"),
00245 };