/src/ffmpeg/libavcodec/bmpenc.c
Line | Count | Source |
1 | | /* |
2 | | * BMP image format encoder |
3 | | * Copyright (c) 2006, 2007 Michel Bardiaux |
4 | | * Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu> |
5 | | * |
6 | | * This file is part of FFmpeg. |
7 | | * |
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. |
12 | | * |
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. |
17 | | * |
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 |
21 | | */ |
22 | | |
23 | | #include "config.h" |
24 | | |
25 | | #include "libavutil/avassert.h" |
26 | | #include "libavutil/imgutils_internal.h" |
27 | | #include "avcodec.h" |
28 | | #include "bytestream.h" |
29 | | #include "bmp.h" |
30 | | #include "codec_internal.h" |
31 | | #include "encode.h" |
32 | | |
33 | | static const uint32_t monoblack_pal[] = { 0x000000, 0xFFFFFF }; |
34 | | static const uint32_t rgb565_masks[] = { 0xF800, 0x07E0, 0x001F }; |
35 | | static const uint32_t rgb444_masks[] = { 0x0F00, 0x00F0, 0x000F }; |
36 | | |
37 | 259 | static av_cold int bmp_encode_init(AVCodecContext *avctx){ |
38 | 259 | switch (avctx->pix_fmt) { |
39 | 61 | case AV_PIX_FMT_BGRA: |
40 | 61 | avctx->bits_per_coded_sample = 32; |
41 | 61 | break; |
42 | 6 | case AV_PIX_FMT_BGR24: |
43 | 6 | avctx->bits_per_coded_sample = 24; |
44 | 6 | break; |
45 | 2 | case AV_PIX_FMT_RGB555: |
46 | 23 | case AV_PIX_FMT_RGB565: |
47 | 37 | case AV_PIX_FMT_RGB444: |
48 | 37 | avctx->bits_per_coded_sample = 16; |
49 | 37 | break; |
50 | 21 | case AV_PIX_FMT_RGB8: |
51 | 46 | case AV_PIX_FMT_BGR8: |
52 | 67 | case AV_PIX_FMT_RGB4_BYTE: |
53 | 98 | case AV_PIX_FMT_BGR4_BYTE: |
54 | 125 | case AV_PIX_FMT_GRAY8: |
55 | 141 | case AV_PIX_FMT_PAL8: |
56 | 141 | avctx->bits_per_coded_sample = 8; |
57 | 141 | break; |
58 | 14 | case AV_PIX_FMT_MONOBLACK: |
59 | 14 | avctx->bits_per_coded_sample = 1; |
60 | 14 | break; |
61 | 259 | } |
62 | | |
63 | 259 | return 0; |
64 | 259 | } |
65 | | |
66 | | static int bmp_encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
67 | | const AVFrame *pict, int *got_packet) |
68 | 9.93k | { |
69 | 9.93k | const AVFrame * const p = pict; |
70 | 9.93k | int n_bytes_image, n_bytes_per_row, n_bytes, i, n, hsize, ret; |
71 | 9.93k | const uint32_t *pal = NULL; |
72 | 9.93k | uint32_t palette256[256]; |
73 | 9.93k | int pad_bytes_per_row, pal_entries = 0, compression = BMP_RGB; |
74 | 9.93k | int bit_count = avctx->bits_per_coded_sample; |
75 | 9.93k | const uint8_t *ptr; |
76 | 9.93k | uint8_t *buf; |
77 | | |
78 | 9.93k | switch (avctx->pix_fmt) { |
79 | 216 | case AV_PIX_FMT_RGB444: |
80 | 216 | compression = BMP_BITFIELDS; |
81 | 216 | pal = rgb444_masks; // abuse pal to hold color masks |
82 | 216 | pal_entries = 3; |
83 | 216 | break; |
84 | 1.00k | case AV_PIX_FMT_RGB565: |
85 | 1.00k | compression = BMP_BITFIELDS; |
86 | 1.00k | pal = rgb565_masks; // abuse pal to hold color masks |
87 | 1.00k | pal_entries = 3; |
88 | 1.00k | break; |
89 | 1.52k | case AV_PIX_FMT_RGB8: |
90 | 2.46k | case AV_PIX_FMT_BGR8: |
91 | 3.55k | case AV_PIX_FMT_RGB4_BYTE: |
92 | 5.33k | case AV_PIX_FMT_BGR4_BYTE: |
93 | 6.74k | case AV_PIX_FMT_GRAY8: |
94 | 6.74k | av_assert1(bit_count == 8); |
95 | 6.74k | avpriv_set_systematic_pal2(palette256, avctx->pix_fmt); |
96 | 6.74k | pal = palette256; |
97 | 6.74k | break; |
98 | 297 | case AV_PIX_FMT_PAL8: |
99 | 297 | pal = (uint32_t *)p->data[1]; |
100 | 297 | break; |
101 | 680 | case AV_PIX_FMT_MONOBLACK: |
102 | 680 | pal = monoblack_pal; |
103 | 680 | break; |
104 | 9.93k | } |
105 | 9.93k | if (pal && !pal_entries) pal_entries = 1 << bit_count; |
106 | 9.93k | n_bytes_per_row = ((int64_t)avctx->width * (int64_t)bit_count + 7LL) >> 3LL; |
107 | 9.93k | pad_bytes_per_row = (4 - n_bytes_per_row) & 3; |
108 | 9.93k | n_bytes_image = avctx->height * (n_bytes_per_row + pad_bytes_per_row); |
109 | | |
110 | | // STRUCTURE.field refer to the MSVC documentation for BITMAPFILEHEADER |
111 | | // and related pages. |
112 | 9.93k | #define SIZE_BITMAPFILEHEADER 14 |
113 | 19.8k | #define SIZE_BITMAPINFOHEADER 40 |
114 | 9.93k | hsize = SIZE_BITMAPFILEHEADER + SIZE_BITMAPINFOHEADER + (pal_entries << 2); |
115 | 9.93k | n_bytes = n_bytes_image + hsize; |
116 | 9.93k | if ((ret = ff_get_encode_buffer(avctx, pkt, n_bytes, 0)) < 0) |
117 | 0 | return ret; |
118 | 9.93k | buf = pkt->data; |
119 | 9.93k | bytestream_put_byte(&buf, 'B'); // BITMAPFILEHEADER.bfType |
120 | 9.93k | bytestream_put_byte(&buf, 'M'); // do. |
121 | 9.93k | bytestream_put_le32(&buf, n_bytes); // BITMAPFILEHEADER.bfSize |
122 | 9.93k | bytestream_put_le16(&buf, 0); // BITMAPFILEHEADER.bfReserved1 |
123 | 9.93k | bytestream_put_le16(&buf, 0); // BITMAPFILEHEADER.bfReserved2 |
124 | 9.93k | bytestream_put_le32(&buf, hsize); // BITMAPFILEHEADER.bfOffBits |
125 | 9.93k | bytestream_put_le32(&buf, SIZE_BITMAPINFOHEADER); // BITMAPINFOHEADER.biSize |
126 | 9.93k | bytestream_put_le32(&buf, avctx->width); // BITMAPINFOHEADER.biWidth |
127 | 9.93k | bytestream_put_le32(&buf, avctx->height); // BITMAPINFOHEADER.biHeight |
128 | 9.93k | bytestream_put_le16(&buf, 1); // BITMAPINFOHEADER.biPlanes |
129 | 9.93k | bytestream_put_le16(&buf, bit_count); // BITMAPINFOHEADER.biBitCount |
130 | 9.93k | bytestream_put_le32(&buf, compression); // BITMAPINFOHEADER.biCompression |
131 | 9.93k | bytestream_put_le32(&buf, n_bytes_image); // BITMAPINFOHEADER.biSizeImage |
132 | 9.93k | bytestream_put_le32(&buf, 0); // BITMAPINFOHEADER.biXPelsPerMeter |
133 | 9.93k | bytestream_put_le32(&buf, 0); // BITMAPINFOHEADER.biYPelsPerMeter |
134 | 9.93k | bytestream_put_le32(&buf, 0); // BITMAPINFOHEADER.biClrUsed |
135 | 9.93k | bytestream_put_le32(&buf, 0); // BITMAPINFOHEADER.biClrImportant |
136 | 1.81M | for (i = 0; i < pal_entries; i++) |
137 | 1.80M | bytestream_put_le32(&buf, pal[i] & 0xFFFFFF); |
138 | | // BMP files are bottom-to-top so we start from the end... |
139 | 9.93k | ptr = p->data[0] + (avctx->height - 1) * p->linesize[0]; |
140 | 9.93k | buf = pkt->data + hsize; |
141 | 767k | for(i = 0; i < avctx->height; i++) { |
142 | 757k | if (HAVE_BIGENDIAN && bit_count == 16) { |
143 | 0 | const uint16_t *src = (const uint16_t *) ptr; |
144 | 0 | for(n = 0; n < avctx->width; n++) |
145 | 0 | AV_WL16(buf + 2 * n, src[n]); |
146 | 757k | } else { |
147 | 757k | memcpy(buf, ptr, n_bytes_per_row); |
148 | 757k | } |
149 | 757k | buf += n_bytes_per_row; |
150 | 757k | memset(buf, 0, pad_bytes_per_row); |
151 | 757k | buf += pad_bytes_per_row; |
152 | 757k | ptr -= p->linesize[0]; // ... and go back |
153 | 757k | } |
154 | | |
155 | 9.93k | *got_packet = 1; |
156 | 9.93k | return 0; |
157 | 9.93k | } |
158 | | |
159 | | const FFCodec ff_bmp_encoder = { |
160 | | .p.name = "bmp", |
161 | | CODEC_LONG_NAME("BMP (Windows and OS/2 bitmap)"), |
162 | | .p.type = AVMEDIA_TYPE_VIDEO, |
163 | | .p.id = AV_CODEC_ID_BMP, |
164 | | .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, |
165 | | .init = bmp_encode_init, |
166 | | FF_CODEC_ENCODE_CB(bmp_encode_frame), |
167 | | CODEC_PIXFMTS(AV_PIX_FMT_BGRA, AV_PIX_FMT_BGR24, |
168 | | AV_PIX_FMT_RGB565, AV_PIX_FMT_RGB555, AV_PIX_FMT_RGB444, |
169 | | AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, |
170 | | AV_PIX_FMT_BGR4_BYTE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, |
171 | | AV_PIX_FMT_MONOBLACK), |
172 | | }; |