2 * BMP image format encoder
3 * Copyright (c) 2006, 2007 Michel Bardiaux
4 * Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu>
6 * This file is part of FFmpeg.
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "libavutil/imgutils.h"
24 #include "libavutil/avassert.h"
26 #include "bytestream.h"
30 static const uint32_t monoblack_pal
[] = { 0x000000, 0xFFFFFF };
31 static const uint32_t rgb565_masks
[] = { 0xF800, 0x07E0, 0x001F };
32 static const uint32_t rgb444_masks
[] = { 0x0F00, 0x00F0, 0x000F };
34 static av_cold
int bmp_encode_init(AVCodecContext
*avctx
){
35 switch (avctx
->pix_fmt
) {
37 avctx
->bits_per_coded_sample
= 32;
39 case AV_PIX_FMT_BGR24
:
40 avctx
->bits_per_coded_sample
= 24;
42 case AV_PIX_FMT_RGB555
:
43 case AV_PIX_FMT_RGB565
:
44 case AV_PIX_FMT_RGB444
:
45 avctx
->bits_per_coded_sample
= 16;
49 case AV_PIX_FMT_RGB4_BYTE
:
50 case AV_PIX_FMT_BGR4_BYTE
:
51 case AV_PIX_FMT_GRAY8
:
53 avctx
->bits_per_coded_sample
= 8;
55 case AV_PIX_FMT_MONOBLACK
:
56 avctx
->bits_per_coded_sample
= 1;
59 av_log(avctx
, AV_LOG_INFO
, "unsupported pixel format\n");
60 return AVERROR(EINVAL
);
63 avctx
->coded_frame
= av_frame_alloc();
64 if (!avctx
->coded_frame
)
65 return AVERROR(ENOMEM
);
70 static int bmp_encode_frame(AVCodecContext
*avctx
, AVPacket
*pkt
,
71 const AVFrame
*pict
, int *got_packet
)
73 const AVFrame
* const p
= pict
;
74 int n_bytes_image
, n_bytes_per_row
, n_bytes
, i
, n
, hsize
, ret
;
75 const uint32_t *pal
= NULL
;
76 uint32_t palette256
[256];
77 int pad_bytes_per_row
, pal_entries
= 0, compression
= BMP_RGB
;
78 int bit_count
= avctx
->bits_per_coded_sample
;
81 avctx
->coded_frame
->pict_type
= AV_PICTURE_TYPE_I
;
82 avctx
->coded_frame
->key_frame
= 1;
83 switch (avctx
->pix_fmt
) {
84 case AV_PIX_FMT_RGB444
:
85 compression
= BMP_BITFIELDS
;
86 pal
= rgb444_masks
; // abuse pal to hold color masks
89 case AV_PIX_FMT_RGB565
:
90 compression
= BMP_BITFIELDS
;
91 pal
= rgb565_masks
; // abuse pal to hold color masks
96 case AV_PIX_FMT_RGB4_BYTE
:
97 case AV_PIX_FMT_BGR4_BYTE
:
98 case AV_PIX_FMT_GRAY8
:
99 av_assert1(bit_count
== 8);
100 avpriv_set_systematic_pal2(palette256
, avctx
->pix_fmt
);
103 case AV_PIX_FMT_PAL8
:
104 pal
= (uint32_t *)p
->data
[1];
106 case AV_PIX_FMT_MONOBLACK
:
110 if (pal
&& !pal_entries
) pal_entries
= 1 << bit_count
;
111 n_bytes_per_row
= ((int64_t)avctx
->width
* (int64_t)bit_count
+ 7LL) >> 3LL;
112 pad_bytes_per_row
= (4 - n_bytes_per_row
) & 3;
113 n_bytes_image
= avctx
->height
* (n_bytes_per_row
+ pad_bytes_per_row
);
115 // STRUCTURE.field refer to the MSVC documentation for BITMAPFILEHEADER
116 // and related pages.
117 #define SIZE_BITMAPFILEHEADER 14
118 #define SIZE_BITMAPINFOHEADER 40
119 hsize
= SIZE_BITMAPFILEHEADER
+ SIZE_BITMAPINFOHEADER
+ (pal_entries
<< 2);
120 n_bytes
= n_bytes_image
+ hsize
;
121 if ((ret
= ff_alloc_packet2(avctx
, pkt
, n_bytes
)) < 0)
124 bytestream_put_byte(&buf
, 'B'); // BITMAPFILEHEADER.bfType
125 bytestream_put_byte(&buf
, 'M'); // do.
126 bytestream_put_le32(&buf
, n_bytes
); // BITMAPFILEHEADER.bfSize
127 bytestream_put_le16(&buf
, 0); // BITMAPFILEHEADER.bfReserved1
128 bytestream_put_le16(&buf
, 0); // BITMAPFILEHEADER.bfReserved2
129 bytestream_put_le32(&buf
, hsize
); // BITMAPFILEHEADER.bfOffBits
130 bytestream_put_le32(&buf
, SIZE_BITMAPINFOHEADER
); // BITMAPINFOHEADER.biSize
131 bytestream_put_le32(&buf
, avctx
->width
); // BITMAPINFOHEADER.biWidth
132 bytestream_put_le32(&buf
, avctx
->height
); // BITMAPINFOHEADER.biHeight
133 bytestream_put_le16(&buf
, 1); // BITMAPINFOHEADER.biPlanes
134 bytestream_put_le16(&buf
, bit_count
); // BITMAPINFOHEADER.biBitCount
135 bytestream_put_le32(&buf
, compression
); // BITMAPINFOHEADER.biCompression
136 bytestream_put_le32(&buf
, n_bytes_image
); // BITMAPINFOHEADER.biSizeImage
137 bytestream_put_le32(&buf
, 0); // BITMAPINFOHEADER.biXPelsPerMeter
138 bytestream_put_le32(&buf
, 0); // BITMAPINFOHEADER.biYPelsPerMeter
139 bytestream_put_le32(&buf
, 0); // BITMAPINFOHEADER.biClrUsed
140 bytestream_put_le32(&buf
, 0); // BITMAPINFOHEADER.biClrImportant
141 for (i
= 0; i
< pal_entries
; i
++)
142 bytestream_put_le32(&buf
, pal
[i
] & 0xFFFFFF);
143 // BMP files are bottom-to-top so we start from the end...
144 ptr
= p
->data
[0] + (avctx
->height
- 1) * p
->linesize
[0];
145 buf
= pkt
->data
+ hsize
;
146 for(i
= 0; i
< avctx
->height
; i
++) {
147 if (bit_count
== 16) {
148 const uint16_t *src
= (const uint16_t *) ptr
;
149 uint16_t *dst
= (uint16_t *) buf
;
150 for(n
= 0; n
< avctx
->width
; n
++)
151 AV_WL16(dst
+ n
, src
[n
]);
153 memcpy(buf
, ptr
, n_bytes_per_row
);
155 buf
+= n_bytes_per_row
;
156 memset(buf
, 0, pad_bytes_per_row
);
157 buf
+= pad_bytes_per_row
;
158 ptr
-= p
->linesize
[0]; // ... and go back
161 pkt
->flags
|= AV_PKT_FLAG_KEY
;
166 static av_cold
int bmp_encode_close(AVCodecContext
*avctx
)
168 av_frame_free(&avctx
->coded_frame
);
172 AVCodec ff_bmp_encoder
= {
174 .long_name
= NULL_IF_CONFIG_SMALL("BMP (Windows and OS/2 bitmap)"),
175 .type
= AVMEDIA_TYPE_VIDEO
,
176 .id
= AV_CODEC_ID_BMP
,
177 .init
= bmp_encode_init
,
178 .encode2
= bmp_encode_frame
,
179 .close
= bmp_encode_close
,
180 .pix_fmts
= (const enum AVPixelFormat
[]){
181 AV_PIX_FMT_BGRA
, AV_PIX_FMT_BGR24
,
182 AV_PIX_FMT_RGB565
, AV_PIX_FMT_RGB555
, AV_PIX_FMT_RGB444
,
183 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
,
184 AV_PIX_FMT_MONOBLACK
,