libavcodec/bmpenc.c
52548eee
 /*
  * BMP image format encoder
  * Copyright (c) 2006, 2007 Michel Bardiaux
5cf59463
  * Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu>
52548eee
  *
  * 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
  */
 
7ffe76e5
 #include "libavutil/imgutils.h"
92779658
 #include "libavutil/avassert.h"
52548eee
 #include "avcodec.h"
 #include "bytestream.h"
 #include "bmp.h"
3f77c411
 #include "internal.h"
52548eee
 
5cf59463
 static const uint32_t monoblack_pal[] = { 0x000000, 0xFFFFFF };
 static const uint32_t rgb565_masks[]  = { 0xF800, 0x07E0, 0x001F };
047a28f7
 static const uint32_t rgb444_masks[]  = { 0x0F00, 0x00F0, 0x000F };
5cf59463
 
98a6fff9
 static av_cold int bmp_encode_init(AVCodecContext *avctx){
82dadb90
     switch (avctx->pix_fmt) {
ac627b3d
     case AV_PIX_FMT_BGRA:
8b87fd98
         avctx->bits_per_coded_sample = 32;
         break;
716d413c
     case AV_PIX_FMT_BGR24:
82dadb90
         avctx->bits_per_coded_sample = 24;
         break;
716d413c
     case AV_PIX_FMT_RGB555:
     case AV_PIX_FMT_RGB565:
     case AV_PIX_FMT_RGB444:
82dadb90
         avctx->bits_per_coded_sample = 16;
         break;
716d413c
     case AV_PIX_FMT_RGB8:
     case AV_PIX_FMT_BGR8:
     case AV_PIX_FMT_RGB4_BYTE:
     case AV_PIX_FMT_BGR4_BYTE:
     case AV_PIX_FMT_GRAY8:
     case AV_PIX_FMT_PAL8:
82dadb90
         avctx->bits_per_coded_sample = 8;
         break;
716d413c
     case AV_PIX_FMT_MONOBLACK:
82dadb90
         avctx->bits_per_coded_sample = 1;
         break;
     default:
         av_log(avctx, AV_LOG_INFO, "unsupported pixel format\n");
9bc59c10
         return AVERROR(EINVAL);
82dadb90
     }
 
badb8e15
     avctx->coded_frame = av_frame_alloc();
     if (!avctx->coded_frame)
         return AVERROR(ENOMEM);
 
52548eee
     return 0;
 }
 
3f77c411
 static int bmp_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
                             const AVFrame *pict, int *got_packet)
 {
badb8e15
     const AVFrame * const p = pict;
3f77c411
     int n_bytes_image, n_bytes_per_row, n_bytes, i, n, hsize, ret;
5cf59463
     const uint32_t *pal = NULL;
ad1c5025
     uint32_t palette256[256];
82dadb90
     int pad_bytes_per_row, pal_entries = 0, compression = BMP_RGB;
     int bit_count = avctx->bits_per_coded_sample;
3f77c411
     uint8_t *ptr, *buf;
77535bb3
 
badb8e15
     avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
     avctx->coded_frame->key_frame = 1;
5cf59463
     switch (avctx->pix_fmt) {
716d413c
     case AV_PIX_FMT_RGB444:
047a28f7
         compression = BMP_BITFIELDS;
         pal = rgb444_masks; // abuse pal to hold color masks
         pal_entries = 3;
         break;
716d413c
     case AV_PIX_FMT_RGB565:
5cf59463
         compression = BMP_BITFIELDS;
         pal = rgb565_masks; // abuse pal to hold color masks
         pal_entries = 3;
         break;
716d413c
     case AV_PIX_FMT_RGB8:
     case AV_PIX_FMT_BGR8:
     case AV_PIX_FMT_RGB4_BYTE:
     case AV_PIX_FMT_BGR4_BYTE:
     case AV_PIX_FMT_GRAY8:
92779658
         av_assert1(bit_count == 8);
d6f6a755
         avpriv_set_systematic_pal2(palette256, avctx->pix_fmt);
ad1c5025
         pal = palette256;
         break;
716d413c
     case AV_PIX_FMT_PAL8:
5cf59463
         pal = (uint32_t *)p->data[1];
         break;
716d413c
     case AV_PIX_FMT_MONOBLACK:
5cf59463
         pal = monoblack_pal;
         break;
     }
     if (pal && !pal_entries) pal_entries = 1 << bit_count;
     n_bytes_per_row = ((int64_t)avctx->width * (int64_t)bit_count + 7LL) >> 3LL;
     pad_bytes_per_row = (4 - n_bytes_per_row) & 3;
     n_bytes_image = avctx->height * (n_bytes_per_row + pad_bytes_per_row);
52548eee
 
     // STRUCTURE.field refer to the MSVC documentation for BITMAPFILEHEADER
     // and related pages.
 #define SIZE_BITMAPFILEHEADER 14
 #define SIZE_BITMAPINFOHEADER 40
5cf59463
     hsize = SIZE_BITMAPFILEHEADER + SIZE_BITMAPINFOHEADER + (pal_entries << 2);
52548eee
     n_bytes = n_bytes_image + hsize;
ae2c33b0
     if ((ret = ff_alloc_packet2(avctx, pkt, n_bytes)) < 0)
3f77c411
         return ret;
     buf = pkt->data;
52548eee
     bytestream_put_byte(&buf, 'B');                   // BITMAPFILEHEADER.bfType
     bytestream_put_byte(&buf, 'M');                   // do.
     bytestream_put_le32(&buf, n_bytes);               // BITMAPFILEHEADER.bfSize
     bytestream_put_le16(&buf, 0);                     // BITMAPFILEHEADER.bfReserved1
     bytestream_put_le16(&buf, 0);                     // BITMAPFILEHEADER.bfReserved2
     bytestream_put_le32(&buf, hsize);                 // BITMAPFILEHEADER.bfOffBits
     bytestream_put_le32(&buf, SIZE_BITMAPINFOHEADER); // BITMAPINFOHEADER.biSize
     bytestream_put_le32(&buf, avctx->width);          // BITMAPINFOHEADER.biWidth
     bytestream_put_le32(&buf, avctx->height);         // BITMAPINFOHEADER.biHeight
     bytestream_put_le16(&buf, 1);                     // BITMAPINFOHEADER.biPlanes
5cf59463
     bytestream_put_le16(&buf, bit_count);             // BITMAPINFOHEADER.biBitCount
     bytestream_put_le32(&buf, compression);           // BITMAPINFOHEADER.biCompression
52548eee
     bytestream_put_le32(&buf, n_bytes_image);         // BITMAPINFOHEADER.biSizeImage
     bytestream_put_le32(&buf, 0);                     // BITMAPINFOHEADER.biXPelsPerMeter
     bytestream_put_le32(&buf, 0);                     // BITMAPINFOHEADER.biYPelsPerMeter
     bytestream_put_le32(&buf, 0);                     // BITMAPINFOHEADER.biClrUsed
     bytestream_put_le32(&buf, 0);                     // BITMAPINFOHEADER.biClrImportant
5cf59463
     for (i = 0; i < pal_entries; i++)
         bytestream_put_le32(&buf, pal[i] & 0xFFFFFF);
52548eee
     // BMP files are bottom-to-top so we start from the end...
     ptr = p->data[0] + (avctx->height - 1) * p->linesize[0];
3f77c411
     buf = pkt->data + hsize;
52548eee
     for(i = 0; i < avctx->height; i++) {
5cf59463
         if (bit_count == 16) {
             const uint16_t *src = (const uint16_t *) ptr;
             uint16_t *dst = (uint16_t *) buf;
             for(n = 0; n < avctx->width; n++)
                 AV_WL16(dst + n, src[n]);
         } else {
             memcpy(buf, ptr, n_bytes_per_row);
         }
         buf += n_bytes_per_row;
         memset(buf, 0, pad_bytes_per_row);
         buf += pad_bytes_per_row;
52548eee
         ptr -= p->linesize[0]; // ... and go back
     }
3f77c411
 
     pkt->flags |= AV_PKT_FLAG_KEY;
     *got_packet = 1;
     return 0;
52548eee
 }
 
badb8e15
 static av_cold int bmp_encode_close(AVCodecContext *avctx)
 {
     av_frame_free(&avctx->coded_frame);
     return 0;
 }
 
e7e2df27
 AVCodec ff_bmp_encoder = {
ec6402b7
     .name           = "bmp",
b2bed932
     .long_name      = NULL_IF_CONFIG_SMALL("BMP (Windows and OS/2 bitmap)"),
ec6402b7
     .type           = AVMEDIA_TYPE_VIDEO,
36ef5369
     .id             = AV_CODEC_ID_BMP,
ec6402b7
     .init           = bmp_encode_init,
3f77c411
     .encode2        = bmp_encode_frame,
badb8e15
     .close          = bmp_encode_close,
716d413c
     .pix_fmts       = (const enum AVPixelFormat[]){
ac627b3d
         AV_PIX_FMT_BGRA, AV_PIX_FMT_BGR24,
         AV_PIX_FMT_RGB565, AV_PIX_FMT_RGB555, AV_PIX_FMT_RGB444,
716d413c
         AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8,
         AV_PIX_FMT_MONOBLACK,
         AV_PIX_FMT_NONE
00c3b67b
     },
52548eee
 };