dpx.c 8.37 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * DPX (.dpx) image decoder
 * Copyright (c) 2009 Jimmy Christensen
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "libavutil/intreadwrite.h"
23
#include "libavutil/imgutils.h"
24 25
#include "bytestream.h"
#include "avcodec.h"
26
#include "internal.h"
27 28 29 30 31 32 33 34 35 36 37 38 39

static unsigned int read32(const uint8_t **ptr, int is_big)
{
    unsigned int temp;
    if (is_big) {
        temp = AV_RB32(*ptr);
    } else {
        temp = AV_RL32(*ptr);
    }
    *ptr += 4;
    return temp;
}

Georg Lippitsch's avatar
Georg Lippitsch committed
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
static uint16_t read10in32(const uint8_t **ptr, uint32_t * lbuf,
                                  int * n_datum, int is_big)
{
    if (*n_datum)
        (*n_datum)--;
    else {
        *lbuf = read32(ptr, is_big);
        *n_datum = 2;
    }

    *lbuf = (*lbuf << 10) | (*lbuf >> 22);

    return *lbuf & 0x3FF;
}

55 56
static int decode_frame(AVCodecContext *avctx,
                        void *data,
57
                        int *got_frame,
58 59 60 61
                        AVPacket *avpkt)
{
    const uint8_t *buf = avpkt->data;
    int buf_size       = avpkt->size;
62
    AVFrame *const p = data;
63
    uint8_t *ptr[AV_NUM_DATA_POINTERS];
64

65 66
    unsigned int offset;
    int magic_num, endian;
67
    int x, y, i, ret;
Georg Lippitsch's avatar
Georg Lippitsch committed
68
    int w, h, bits_per_color, descriptor, elements, packing, total_size;
69

Georg Lippitsch's avatar
Georg Lippitsch committed
70 71
    unsigned int rgbBuffer = 0;
    int n_datum = 0;
72

73
    if (avpkt->size <= 1634) {
74 75 76 77
        av_log(avctx, AV_LOG_ERROR, "Packet too small for DPX header\n");
        return AVERROR_INVALIDDATA;
    }

78 79 80 81 82 83 84 85 86 87 88
    magic_num = AV_RB32(buf);
    buf += 4;

    /* Check if the files "magic number" is "SDPX" which means it uses
     * big-endian or XPDS which is for little-endian files */
    if (magic_num == AV_RL32("SDPX")) {
        endian = 0;
    } else if (magic_num == AV_RB32("SDPX")) {
        endian = 1;
    } else {
        av_log(avctx, AV_LOG_ERROR, "DPX marker not found\n");
89
        return AVERROR_INVALIDDATA;
90 91 92
    }

    offset = read32(&buf, endian);
93 94 95 96
    if (avpkt->size <= offset) {
        av_log(avctx, AV_LOG_ERROR, "Invalid data start offset\n");
        return AVERROR_INVALIDDATA;
    }
97 98 99 100
    // Need to end in 0x304 offset from start of file
    buf = avpkt->data + 0x304;
    w = read32(&buf, endian);
    h = read32(&buf, endian);
101 102
    if ((ret = av_image_check_size(w, h, 0, avctx)) < 0)
        return ret;
103 104 105

    if (w != avctx->width || h != avctx->height)
        avcodec_set_dimensions(avctx, w, h);
106 107 108 109 110 111 112

    // Need to end in 0x320 to read the descriptor
    buf += 20;
    descriptor = buf[0];

    // Need to end in 0x323 to read the bits per color
    buf += 3;
113
    avctx->bits_per_raw_sample =
114
    bits_per_color = buf[0];
Georg Lippitsch's avatar
Georg Lippitsch committed
115 116
    buf++;
    packing = *((uint16_t*)buf);
117

Georg Lippitsch's avatar
Georg Lippitsch committed
118
    buf += 824;
119 120
    avctx->sample_aspect_ratio.num = read32(&buf, endian);
    avctx->sample_aspect_ratio.den = read32(&buf, endian);
121 122 123 124 125
    if (avctx->sample_aspect_ratio.num > 0 && avctx->sample_aspect_ratio.den > 0)
        av_reduce(&avctx->sample_aspect_ratio.num, &avctx->sample_aspect_ratio.den,
                   avctx->sample_aspect_ratio.num,  avctx->sample_aspect_ratio.den,
                  0x10000);
    else
126
        avctx->sample_aspect_ratio = (AVRational){ 0, 1 };
127

128 129 130 131 132 133 134 135 136
    switch (descriptor) {
        case 51: // RGBA
            elements = 4;
            break;
        case 50: // RGB
            elements = 3;
            break;
        default:
            av_log(avctx, AV_LOG_ERROR, "Unsupported descriptor %d\n", descriptor);
137
            return AVERROR_INVALIDDATA;
138 139 140 141 142
    }

    switch (bits_per_color) {
        case 8:
            if (elements == 4) {
143
                avctx->pix_fmt = AV_PIX_FMT_RGBA;
144
            } else {
145
                avctx->pix_fmt = AV_PIX_FMT_RGB24;
146
            }
Georg Lippitsch's avatar
Georg Lippitsch committed
147
            total_size = avctx->width * avctx->height * elements;
148 149
            break;
        case 10:
Georg Lippitsch's avatar
Georg Lippitsch committed
150 151 152 153
            if (!packing) {
                av_log(avctx, AV_LOG_ERROR, "Packing to 32bit required\n");
                return -1;
            }
154
            avctx->pix_fmt = AV_PIX_FMT_GBRP10;
155
            total_size = (avctx->width * elements + 2) / 3 * 4 * avctx->height;
156 157
            break;
        case 12:
Georg Lippitsch's avatar
Georg Lippitsch committed
158 159 160 161
            if (!packing) {
                av_log(avctx, AV_LOG_ERROR, "Packing to 16bit required\n");
                return -1;
            }
162
            if (endian) {
Georg Lippitsch's avatar
Georg Lippitsch committed
163
                avctx->pix_fmt = AV_PIX_FMT_GBRP12BE;
164
            } else {
Georg Lippitsch's avatar
Georg Lippitsch committed
165
                avctx->pix_fmt = AV_PIX_FMT_GBRP12LE;
166
            }
Georg Lippitsch's avatar
Georg Lippitsch committed
167
            total_size = 2 * avctx->width * avctx->height * elements;
168
            break;
169 170
        case 16:
            if (endian) {
171
                avctx->pix_fmt = elements == 4 ? AV_PIX_FMT_RGBA64BE : AV_PIX_FMT_RGB48BE;
172
            } else {
173
                avctx->pix_fmt = elements == 4 ? AV_PIX_FMT_RGBA64LE : AV_PIX_FMT_RGB48LE;
174
            }
Georg Lippitsch's avatar
Georg Lippitsch committed
175
            total_size = 2 * avctx->width * avctx->height * elements;
176 177 178
            break;
        default:
            av_log(avctx, AV_LOG_ERROR, "Unsupported color depth : %d\n", bits_per_color);
179
            return AVERROR_INVALIDDATA;
180 181
    }

182
    if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
183
        return ret;
184 185 186 187

    // Move pointer to offset from start of file
    buf =  avpkt->data + offset;

188 189
    for (i=0; i<AV_NUM_DATA_POINTERS; i++)
        ptr[i] = p->data[i];
190

191
    if (total_size + (int64_t)offset > avpkt->size) {
192
        av_log(avctx, AV_LOG_ERROR, "Overread buffer. Invalid header?\n");
193
        return AVERROR_INVALIDDATA;
194
    }
195
    switch (bits_per_color) {
Georg Lippitsch's avatar
Georg Lippitsch committed
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
    case 10:
        for (x = 0; x < avctx->height; x++) {
            uint16_t *dst[3] = {(uint16_t*)ptr[0],
                                (uint16_t*)ptr[1],
                                (uint16_t*)ptr[2]};
            for (y = 0; y < avctx->width; y++) {
                *dst[2]++ = read10in32(&buf, &rgbBuffer,
                                       &n_datum, endian);
                *dst[0]++ = read10in32(&buf, &rgbBuffer,
                                       &n_datum, endian);
                *dst[1]++ = read10in32(&buf, &rgbBuffer,
                                       &n_datum, endian);
                // For 10 bit, ignore alpha
                if (elements == 4)
                    read10in32(&buf, &rgbBuffer,
                               &n_datum, endian);
212
            }
213
            n_datum = 0;
Georg Lippitsch's avatar
Georg Lippitsch committed
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
            for (i = 0; i < 3; i++)
                ptr[i] += p->linesize[i];
        }
        break;
    case 12:
        for (x = 0; x < avctx->height; x++) {
            uint16_t *dst[3] = {(uint16_t*)ptr[0],
                                (uint16_t*)ptr[1],
                                (uint16_t*)ptr[2]};
            for (y = 0; y < avctx->width; y++) {
                *dst[2] = *((uint16_t*)buf);
                *dst[2] = (*dst[2] >> 4) | (*dst[2] << 12);
                dst[2]++;
                buf += 2;
                *dst[0] = *((uint16_t*)buf);
                *dst[0] = (*dst[0] >> 4) | (*dst[0] << 12);
                dst[0]++;
                buf += 2;
                *dst[1] = *((uint16_t*)buf);
                *dst[1] = (*dst[1] >> 4) | (*dst[1] << 12);
                dst[1]++;
                buf += 2;
                // For 12 bit, ignore alpha
                if (elements == 4)
                    buf += 2;
239
            }
Georg Lippitsch's avatar
Georg Lippitsch committed
240 241 242 243 244 245 246 247 248 249 250 251 252
            for (i = 0; i < 3; i++)
                ptr[i] += p->linesize[i];
        }
        break;
    case 16:
        elements *= 2;
    case 8:
        for (x = 0; x < avctx->height; x++) {
            memcpy(ptr[0], buf, elements*avctx->width);
            ptr[0] += p->linesize[0];
            buf += elements*avctx->width;
        }
        break;
253 254
    }

255
    *got_frame = 1;
256 257 258 259

    return buf_size;
}

260
AVCodec ff_dpx_decoder = {
261 262
    .name           = "dpx",
    .type           = AVMEDIA_TYPE_VIDEO,
263
    .id             = AV_CODEC_ID_DPX,
264
    .decode         = decode_frame,
265
    .long_name      = NULL_IF_CONFIG_SMALL("DPX image"),
266
    .capabilities   = CODEC_CAP_DR1,
267
};