yading@10: /* yading@10: * BMP image format decoder yading@10: * Copyright (c) 2005 Mans Rullgard yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: #include "avcodec.h" yading@10: #include "bytestream.h" yading@10: #include "bmp.h" yading@10: #include "internal.h" yading@10: #include "msrledec.h" yading@10: yading@10: static int bmp_decode_frame(AVCodecContext *avctx, yading@10: void *data, int *got_frame, yading@10: AVPacket *avpkt) yading@10: { yading@10: const uint8_t *buf = avpkt->data; yading@10: int buf_size = avpkt->size; yading@10: AVFrame *p = data; yading@10: unsigned int fsize, hsize; yading@10: int width, height; yading@10: unsigned int depth; yading@10: BiCompression comp; yading@10: unsigned int ihsize; yading@10: int i, j, n, linesize, ret; yading@10: uint32_t rgb[3] = {0}; yading@10: uint32_t alpha = 0; yading@10: uint8_t *ptr; yading@10: int dsize; yading@10: const uint8_t *buf0 = buf; yading@10: GetByteContext gb; yading@10: yading@10: if (buf_size < 14) { yading@10: av_log(avctx, AV_LOG_ERROR, "buf size too small (%d)\n", buf_size); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: if (bytestream_get_byte(&buf) != 'B' || yading@10: bytestream_get_byte(&buf) != 'M') { yading@10: av_log(avctx, AV_LOG_ERROR, "bad magic number\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: fsize = bytestream_get_le32(&buf); yading@10: if (buf_size < fsize) { yading@10: av_log(avctx, AV_LOG_ERROR, "not enough data (%d < %d), trying to decode anyway\n", yading@10: buf_size, fsize); yading@10: fsize = buf_size; yading@10: } yading@10: yading@10: buf += 2; /* reserved1 */ yading@10: buf += 2; /* reserved2 */ yading@10: yading@10: hsize = bytestream_get_le32(&buf); /* header size */ yading@10: ihsize = bytestream_get_le32(&buf); /* more header size */ yading@10: if (ihsize + 14 > hsize) { yading@10: av_log(avctx, AV_LOG_ERROR, "invalid header size %d\n", hsize); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: /* sometimes file size is set to some headers size, set a real size in that case */ yading@10: if (fsize == 14 || fsize == ihsize + 14) yading@10: fsize = buf_size - 2; yading@10: yading@10: if (fsize <= hsize) { yading@10: av_log(avctx, AV_LOG_ERROR, "declared file size is less than header size (%d < %d)\n", yading@10: fsize, hsize); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: switch (ihsize) { yading@10: case 40: // windib yading@10: case 56: // windib v3 yading@10: case 64: // OS/2 v2 yading@10: case 108: // windib v4 yading@10: case 124: // windib v5 yading@10: width = bytestream_get_le32(&buf); yading@10: height = bytestream_get_le32(&buf); yading@10: break; yading@10: case 12: // OS/2 v1 yading@10: width = bytestream_get_le16(&buf); yading@10: height = bytestream_get_le16(&buf); yading@10: break; yading@10: default: yading@10: av_log(avctx, AV_LOG_ERROR, "unsupported BMP file, patch welcome\n"); yading@10: return AVERROR_PATCHWELCOME; yading@10: } yading@10: yading@10: /* planes */ yading@10: if (bytestream_get_le16(&buf) != 1) { yading@10: av_log(avctx, AV_LOG_ERROR, "invalid BMP header\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: depth = bytestream_get_le16(&buf); yading@10: yading@10: if (ihsize >= 40) yading@10: comp = bytestream_get_le32(&buf); yading@10: else yading@10: comp = BMP_RGB; yading@10: yading@10: if (comp != BMP_RGB && comp != BMP_BITFIELDS && comp != BMP_RLE4 && yading@10: comp != BMP_RLE8) { yading@10: av_log(avctx, AV_LOG_ERROR, "BMP coding %d not supported\n", comp); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: if (comp == BMP_BITFIELDS) { yading@10: buf += 20; yading@10: rgb[0] = bytestream_get_le32(&buf); yading@10: rgb[1] = bytestream_get_le32(&buf); yading@10: rgb[2] = bytestream_get_le32(&buf); yading@10: alpha = bytestream_get_le32(&buf); yading@10: } yading@10: yading@10: avctx->width = width; yading@10: avctx->height = height > 0 ? height : -height; yading@10: yading@10: avctx->pix_fmt = AV_PIX_FMT_NONE; yading@10: yading@10: switch (depth) { yading@10: case 32: yading@10: if (comp == BMP_BITFIELDS) { yading@10: if (rgb[0] == 0xFF000000 && rgb[1] == 0x00FF0000 && rgb[2] == 0x0000FF00) yading@10: avctx->pix_fmt = alpha ? AV_PIX_FMT_ABGR : AV_PIX_FMT_0BGR; yading@10: else if (rgb[0] == 0x00FF0000 && rgb[1] == 0x0000FF00 && rgb[2] == 0x000000FF) yading@10: avctx->pix_fmt = alpha ? AV_PIX_FMT_BGRA : AV_PIX_FMT_BGR0; yading@10: else if (rgb[0] == 0x0000FF00 && rgb[1] == 0x00FF0000 && rgb[2] == 0xFF000000) yading@10: avctx->pix_fmt = alpha ? AV_PIX_FMT_ARGB : AV_PIX_FMT_0RGB; yading@10: else if (rgb[0] == 0x000000FF && rgb[1] == 0x0000FF00 && rgb[2] == 0x00FF0000) yading@10: avctx->pix_fmt = alpha ? AV_PIX_FMT_RGBA : AV_PIX_FMT_RGB0; yading@10: else { yading@10: av_log(avctx, AV_LOG_ERROR, "Unknown bitfields %0X %0X %0X\n", rgb[0], rgb[1], rgb[2]); yading@10: return AVERROR(EINVAL); yading@10: } yading@10: } else { yading@10: avctx->pix_fmt = AV_PIX_FMT_BGRA; yading@10: } yading@10: break; yading@10: case 24: yading@10: avctx->pix_fmt = AV_PIX_FMT_BGR24; yading@10: break; yading@10: case 16: yading@10: if (comp == BMP_RGB) yading@10: avctx->pix_fmt = AV_PIX_FMT_RGB555; yading@10: else if (comp == BMP_BITFIELDS) { yading@10: if (rgb[0] == 0xF800 && rgb[1] == 0x07E0 && rgb[2] == 0x001F) yading@10: avctx->pix_fmt = AV_PIX_FMT_RGB565; yading@10: else if (rgb[0] == 0x7C00 && rgb[1] == 0x03E0 && rgb[2] == 0x001F) yading@10: avctx->pix_fmt = AV_PIX_FMT_RGB555; yading@10: else if (rgb[0] == 0x0F00 && rgb[1] == 0x00F0 && rgb[2] == 0x000F) yading@10: avctx->pix_fmt = AV_PIX_FMT_RGB444; yading@10: else { yading@10: av_log(avctx, AV_LOG_ERROR, "Unknown bitfields %0X %0X %0X\n", rgb[0], rgb[1], rgb[2]); yading@10: return AVERROR(EINVAL); yading@10: } yading@10: } yading@10: break; yading@10: case 8: yading@10: if (hsize - ihsize - 14 > 0) yading@10: avctx->pix_fmt = AV_PIX_FMT_PAL8; yading@10: else yading@10: avctx->pix_fmt = AV_PIX_FMT_GRAY8; yading@10: break; yading@10: case 1: yading@10: case 4: yading@10: if (hsize - ihsize - 14 > 0) { yading@10: avctx->pix_fmt = AV_PIX_FMT_PAL8; yading@10: } else { yading@10: av_log(avctx, AV_LOG_ERROR, "Unknown palette for %d-colour BMP\n", 1<pix_fmt == AV_PIX_FMT_NONE) { yading@10: av_log(avctx, AV_LOG_ERROR, "unsupported pixel format\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: if ((ret = ff_get_buffer(avctx, p, 0)) < 0) yading@10: return ret; yading@10: p->pict_type = AV_PICTURE_TYPE_I; yading@10: p->key_frame = 1; yading@10: yading@10: buf = buf0 + hsize; yading@10: dsize = buf_size - hsize; yading@10: yading@10: /* Line size in file multiple of 4 */ yading@10: n = ((avctx->width * depth + 31) / 8) & ~3; yading@10: yading@10: if (n * avctx->height > dsize && comp != BMP_RLE4 && comp != BMP_RLE8) { yading@10: av_log(avctx, AV_LOG_ERROR, "not enough data (%d < %d)\n", yading@10: dsize, n * avctx->height); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: // RLE may skip decoding some picture areas, so blank picture before decoding yading@10: if (comp == BMP_RLE4 || comp == BMP_RLE8) yading@10: memset(p->data[0], 0, avctx->height * p->linesize[0]); yading@10: yading@10: if (height > 0) { yading@10: ptr = p->data[0] + (avctx->height - 1) * p->linesize[0]; yading@10: linesize = -p->linesize[0]; yading@10: } else { yading@10: ptr = p->data[0]; yading@10: linesize = p->linesize[0]; yading@10: } yading@10: yading@10: if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { yading@10: int colors = 1 << depth; yading@10: yading@10: memset(p->data[1], 0, 1024); yading@10: yading@10: if (ihsize >= 36) { yading@10: int t; yading@10: buf = buf0 + 46; yading@10: t = bytestream_get_le32(&buf); yading@10: if (t < 0 || t > (1 << depth)) { yading@10: av_log(avctx, AV_LOG_ERROR, "Incorrect number of colors - %X for bitdepth %d\n", t, depth); yading@10: } else if (t) { yading@10: colors = t; yading@10: } yading@10: } yading@10: buf = buf0 + 14 + ihsize; //palette location yading@10: // OS/2 bitmap, 3 bytes per palette entry yading@10: if ((hsize-ihsize-14) < (colors << 2)) { yading@10: if ((hsize-ihsize-14) < colors * 3) { yading@10: av_log(avctx, AV_LOG_ERROR, "palette doesnt fit in packet\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: for (i = 0; i < colors; i++) yading@10: ((uint32_t*)p->data[1])[i] = (0xFFU<<24) | bytestream_get_le24(&buf); yading@10: } else { yading@10: for (i = 0; i < colors; i++) yading@10: ((uint32_t*)p->data[1])[i] = 0xFFU << 24 | bytestream_get_le32(&buf); yading@10: } yading@10: buf = buf0 + hsize; yading@10: } yading@10: if (comp == BMP_RLE4 || comp == BMP_RLE8) { yading@10: if (height < 0) { yading@10: p->data[0] += p->linesize[0] * (avctx->height - 1); yading@10: p->linesize[0] = -p->linesize[0]; yading@10: } yading@10: bytestream2_init(&gb, buf, dsize); yading@10: ff_msrle_decode(avctx, (AVPicture*)p, depth, &gb); yading@10: if (height < 0) { yading@10: p->data[0] += p->linesize[0] * (avctx->height - 1); yading@10: p->linesize[0] = -p->linesize[0]; yading@10: } yading@10: } else { yading@10: switch (depth) { yading@10: case 1: yading@10: for (i = 0; i < avctx->height; i++) { yading@10: int j; yading@10: for (j = 0; j < n; j++) { yading@10: ptr[j*8+0] = buf[j] >> 7; yading@10: ptr[j*8+1] = (buf[j] >> 6) & 1; yading@10: ptr[j*8+2] = (buf[j] >> 5) & 1; yading@10: ptr[j*8+3] = (buf[j] >> 4) & 1; yading@10: ptr[j*8+4] = (buf[j] >> 3) & 1; yading@10: ptr[j*8+5] = (buf[j] >> 2) & 1; yading@10: ptr[j*8+6] = (buf[j] >> 1) & 1; yading@10: ptr[j*8+7] = buf[j] & 1; yading@10: } yading@10: buf += n; yading@10: ptr += linesize; yading@10: } yading@10: break; yading@10: case 8: yading@10: case 24: yading@10: case 32: yading@10: for (i = 0; i < avctx->height; i++) { yading@10: memcpy(ptr, buf, n); yading@10: buf += n; yading@10: ptr += linesize; yading@10: } yading@10: break; yading@10: case 4: yading@10: for (i = 0; i < avctx->height; i++) { yading@10: int j; yading@10: for (j = 0; j < n; j++) { yading@10: ptr[j*2+0] = (buf[j] >> 4) & 0xF; yading@10: ptr[j*2+1] = buf[j] & 0xF; yading@10: } yading@10: buf += n; yading@10: ptr += linesize; yading@10: } yading@10: break; yading@10: case 16: yading@10: for (i = 0; i < avctx->height; i++) { yading@10: const uint16_t *src = (const uint16_t *) buf; yading@10: uint16_t *dst = (uint16_t *) ptr; yading@10: yading@10: for (j = 0; j < avctx->width; j++) yading@10: *dst++ = av_le2ne16(*src++); yading@10: yading@10: buf += n; yading@10: ptr += linesize; yading@10: } yading@10: break; yading@10: default: yading@10: av_log(avctx, AV_LOG_ERROR, "BMP decoder is broken\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: } yading@10: yading@10: *got_frame = 1; yading@10: yading@10: return buf_size; yading@10: } yading@10: yading@10: AVCodec ff_bmp_decoder = { yading@10: .name = "bmp", yading@10: .type = AVMEDIA_TYPE_VIDEO, yading@10: .id = AV_CODEC_ID_BMP, yading@10: .decode = bmp_decode_frame, yading@10: .capabilities = CODEC_CAP_DR1, yading@10: .long_name = NULL_IF_CONFIG_SMALL("BMP (Windows and OS/2 bitmap)"), yading@10: };