00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "libavutil/imgutils.h"
00029 #include "avcodec.h"
00030 #include "bytestream.h"
00031 #include "internal.h"
00032
00033 typedef struct BRPixContext {
00034 AVFrame frame;
00035 } BRPixContext;
00036
00037 typedef struct BRPixHeader {
00038 int format;
00039 unsigned int width, height;
00040 } BRPixHeader;
00041
00042 static av_cold int brpix_init(AVCodecContext *avctx)
00043 {
00044 BRPixContext *s = avctx->priv_data;
00045
00046 avcodec_get_frame_defaults(&s->frame);
00047 avctx->coded_frame = &s->frame;
00048
00049 return 0;
00050 }
00051
00052 static int brpix_decode_header(BRPixHeader *out, GetByteContext *pgb)
00053 {
00054 unsigned int header_len = bytestream2_get_be32(pgb);
00055
00056 out->format = bytestream2_get_byte(pgb);
00057 bytestream2_skip(pgb, 2);
00058 out->width = bytestream2_get_be16(pgb);
00059 out->height = bytestream2_get_be16(pgb);
00060
00061
00062 if (header_len < 11) {
00063 return 0;
00064 }
00065
00066
00067 bytestream2_skip(pgb, header_len-7);
00068
00069 return 1;
00070 }
00071
00072 static int brpix_decode_frame(AVCodecContext *avctx,
00073 void *data, int *got_frame,
00074 AVPacket *avpkt)
00075 {
00076 BRPixContext *s = avctx->priv_data;
00077 AVFrame *frame_out = data;
00078
00079 int ret;
00080 GetByteContext gb;
00081
00082 unsigned int bytes_pp;
00083
00084 unsigned int magic[4];
00085 unsigned int chunk_type;
00086 unsigned int data_len;
00087 BRPixHeader hdr;
00088
00089 bytestream2_init(&gb, avpkt->data, avpkt->size);
00090
00091 magic[0] = bytestream2_get_be32(&gb);
00092 magic[1] = bytestream2_get_be32(&gb);
00093 magic[2] = bytestream2_get_be32(&gb);
00094 magic[3] = bytestream2_get_be32(&gb);
00095
00096 if (magic[0] != 0x12 ||
00097 magic[1] != 0x8 ||
00098 magic[2] != 0x2 ||
00099 magic[3] != 0x2) {
00100 av_log(avctx, AV_LOG_ERROR, "Not a BRender PIX file\n");
00101 return AVERROR_INVALIDDATA;
00102 }
00103
00104 chunk_type = bytestream2_get_be32(&gb);
00105 if (chunk_type != 0x3 && chunk_type != 0x3d) {
00106 av_log(avctx, AV_LOG_ERROR, "Invalid chunk type %d\n", chunk_type);
00107 return AVERROR_INVALIDDATA;
00108 }
00109
00110 ret = brpix_decode_header(&hdr, &gb);
00111 if (!ret) {
00112 av_log(avctx, AV_LOG_ERROR, "Invalid header length\n");
00113 return AVERROR_INVALIDDATA;
00114 }
00115 switch (hdr.format) {
00116 case 3:
00117 avctx->pix_fmt = AV_PIX_FMT_PAL8;
00118 bytes_pp = 1;
00119 break;
00120 case 4:
00121 avctx->pix_fmt = AV_PIX_FMT_RGB555BE;
00122 bytes_pp = 2;
00123 break;
00124 case 5:
00125 avctx->pix_fmt = AV_PIX_FMT_RGB565BE;
00126 bytes_pp = 2;
00127 break;
00128 case 6:
00129 avctx->pix_fmt = AV_PIX_FMT_RGB24;
00130 bytes_pp = 3;
00131 break;
00132 case 7:
00133 avctx->pix_fmt = AV_PIX_FMT_0RGB;
00134 bytes_pp = 4;
00135 break;
00136 case 18:
00137 avctx->pix_fmt = AV_PIX_FMT_GRAY8A;
00138 bytes_pp = 2;
00139 break;
00140 default:
00141 av_log(avctx, AV_LOG_ERROR, "Format %d is not supported\n",
00142 hdr.format);
00143 return AVERROR_PATCHWELCOME;
00144 }
00145
00146 if (s->frame.data[0])
00147 avctx->release_buffer(avctx, &s->frame);
00148
00149 if (av_image_check_size(hdr.width, hdr.height, 0, avctx) < 0)
00150 return AVERROR_INVALIDDATA;
00151
00152 if (hdr.width != avctx->width || hdr.height != avctx->height)
00153 avcodec_set_dimensions(avctx, hdr.width, hdr.height);
00154
00155 if ((ret = ff_get_buffer(avctx, &s->frame)) < 0) {
00156 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00157 return ret;
00158 }
00159
00160 chunk_type = bytestream2_get_be32(&gb);
00161
00162 if (avctx->pix_fmt == AV_PIX_FMT_PAL8 &&
00163 (chunk_type == 0x3 || chunk_type == 0x3d)) {
00164 BRPixHeader palhdr;
00165 uint32_t *pal_out = (uint32_t *)s->frame.data[1];
00166 int i;
00167
00168 ret = brpix_decode_header(&palhdr, &gb);
00169 if (!ret) {
00170 av_log(avctx, AV_LOG_ERROR, "Invalid palette header length\n");
00171 return AVERROR_INVALIDDATA;
00172 }
00173 if (palhdr.format != 7) {
00174 av_log(avctx, AV_LOG_ERROR, "Palette is not in 0RGB format\n");
00175 return AVERROR_INVALIDDATA;
00176 }
00177
00178 chunk_type = bytestream2_get_be32(&gb);
00179 data_len = bytestream2_get_be32(&gb);
00180 bytestream2_skip(&gb, 8);
00181 if (chunk_type != 0x21 || data_len != 1032 ||
00182 bytestream2_get_bytes_left(&gb) < 1032) {
00183 av_log(avctx, AV_LOG_ERROR, "Invalid palette data\n");
00184 return AVERROR_INVALIDDATA;
00185 }
00186
00187 for (i = 0; i < 256; ++i) {
00188 bytestream2_skipu(&gb, 1);
00189 *pal_out++ = (0xFFU << 24) | bytestream2_get_be24u(&gb);
00190 }
00191 bytestream2_skip(&gb, 8);
00192
00193 s->frame.palette_has_changed = 1;
00194
00195 chunk_type = bytestream2_get_be32(&gb);
00196 }
00197
00198 data_len = bytestream2_get_be32(&gb);
00199 bytestream2_skip(&gb, 8);
00200
00201
00202 {
00203 unsigned int bytes_per_scanline = bytes_pp * hdr.width;
00204 unsigned int bytes_left = bytestream2_get_bytes_left(&gb);
00205
00206 if (chunk_type != 0x21 || data_len != bytes_left ||
00207 bytes_left / bytes_per_scanline < hdr.height)
00208 {
00209 av_log(avctx, AV_LOG_ERROR, "Invalid image data\n");
00210 return AVERROR_INVALIDDATA;
00211 }
00212
00213 av_image_copy_plane(s->frame.data[0], s->frame.linesize[0],
00214 avpkt->data + bytestream2_tell(&gb),
00215 bytes_per_scanline,
00216 bytes_per_scanline, hdr.height);
00217 }
00218
00219 *frame_out = s->frame;
00220 *got_frame = 1;
00221
00222 return avpkt->size;
00223 }
00224
00225 static av_cold int brpix_end(AVCodecContext *avctx)
00226 {
00227 BRPixContext *s = avctx->priv_data;
00228
00229 if(s->frame.data[0])
00230 avctx->release_buffer(avctx, &s->frame);
00231
00232 return 0;
00233 }
00234
00235 AVCodec ff_brender_pix_decoder = {
00236 .name = "brender_pix",
00237 .type = AVMEDIA_TYPE_VIDEO,
00238 .id = AV_CODEC_ID_BRENDER_PIX,
00239 .priv_data_size = sizeof(BRPixContext),
00240 .init = brpix_init,
00241 .close = brpix_end,
00242 .decode = brpix_decode_frame,
00243 .capabilities = CODEC_CAP_DR1,
00244 .long_name = NULL_IF_CONFIG_SMALL("BRender PIX image"),
00245 };