1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * BMP image format encoder 3cabdff1aSopenharmony_ci * Copyright (c) 2006, 2007 Michel Bardiaux 4cabdff1aSopenharmony_ci * Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu> 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * This file is part of FFmpeg. 7cabdff1aSopenharmony_ci * 8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 12cabdff1aSopenharmony_ci * 13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16cabdff1aSopenharmony_ci * Lesser General Public License for more details. 17cabdff1aSopenharmony_ci * 18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21cabdff1aSopenharmony_ci */ 22cabdff1aSopenharmony_ci 23cabdff1aSopenharmony_ci#include "config.h" 24cabdff1aSopenharmony_ci 25cabdff1aSopenharmony_ci#include "libavutil/imgutils.h" 26cabdff1aSopenharmony_ci#include "libavutil/avassert.h" 27cabdff1aSopenharmony_ci#include "avcodec.h" 28cabdff1aSopenharmony_ci#include "bytestream.h" 29cabdff1aSopenharmony_ci#include "bmp.h" 30cabdff1aSopenharmony_ci#include "codec_internal.h" 31cabdff1aSopenharmony_ci#include "encode.h" 32cabdff1aSopenharmony_ci 33cabdff1aSopenharmony_cistatic const uint32_t monoblack_pal[] = { 0x000000, 0xFFFFFF }; 34cabdff1aSopenharmony_cistatic const uint32_t rgb565_masks[] = { 0xF800, 0x07E0, 0x001F }; 35cabdff1aSopenharmony_cistatic const uint32_t rgb444_masks[] = { 0x0F00, 0x00F0, 0x000F }; 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_cistatic av_cold int bmp_encode_init(AVCodecContext *avctx){ 38cabdff1aSopenharmony_ci switch (avctx->pix_fmt) { 39cabdff1aSopenharmony_ci case AV_PIX_FMT_BGRA: 40cabdff1aSopenharmony_ci avctx->bits_per_coded_sample = 32; 41cabdff1aSopenharmony_ci break; 42cabdff1aSopenharmony_ci case AV_PIX_FMT_BGR24: 43cabdff1aSopenharmony_ci avctx->bits_per_coded_sample = 24; 44cabdff1aSopenharmony_ci break; 45cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB555: 46cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB565: 47cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB444: 48cabdff1aSopenharmony_ci avctx->bits_per_coded_sample = 16; 49cabdff1aSopenharmony_ci break; 50cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB8: 51cabdff1aSopenharmony_ci case AV_PIX_FMT_BGR8: 52cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB4_BYTE: 53cabdff1aSopenharmony_ci case AV_PIX_FMT_BGR4_BYTE: 54cabdff1aSopenharmony_ci case AV_PIX_FMT_GRAY8: 55cabdff1aSopenharmony_ci case AV_PIX_FMT_PAL8: 56cabdff1aSopenharmony_ci avctx->bits_per_coded_sample = 8; 57cabdff1aSopenharmony_ci break; 58cabdff1aSopenharmony_ci case AV_PIX_FMT_MONOBLACK: 59cabdff1aSopenharmony_ci avctx->bits_per_coded_sample = 1; 60cabdff1aSopenharmony_ci break; 61cabdff1aSopenharmony_ci } 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_ci return 0; 64cabdff1aSopenharmony_ci} 65cabdff1aSopenharmony_ci 66cabdff1aSopenharmony_cistatic int bmp_encode_frame(AVCodecContext *avctx, AVPacket *pkt, 67cabdff1aSopenharmony_ci const AVFrame *pict, int *got_packet) 68cabdff1aSopenharmony_ci{ 69cabdff1aSopenharmony_ci const AVFrame * const p = pict; 70cabdff1aSopenharmony_ci int n_bytes_image, n_bytes_per_row, n_bytes, i, n, hsize, ret; 71cabdff1aSopenharmony_ci const uint32_t *pal = NULL; 72cabdff1aSopenharmony_ci uint32_t palette256[256]; 73cabdff1aSopenharmony_ci int pad_bytes_per_row, pal_entries = 0, compression = BMP_RGB; 74cabdff1aSopenharmony_ci int bit_count = avctx->bits_per_coded_sample; 75cabdff1aSopenharmony_ci uint8_t *ptr, *buf; 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci switch (avctx->pix_fmt) { 78cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB444: 79cabdff1aSopenharmony_ci compression = BMP_BITFIELDS; 80cabdff1aSopenharmony_ci pal = rgb444_masks; // abuse pal to hold color masks 81cabdff1aSopenharmony_ci pal_entries = 3; 82cabdff1aSopenharmony_ci break; 83cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB565: 84cabdff1aSopenharmony_ci compression = BMP_BITFIELDS; 85cabdff1aSopenharmony_ci pal = rgb565_masks; // abuse pal to hold color masks 86cabdff1aSopenharmony_ci pal_entries = 3; 87cabdff1aSopenharmony_ci break; 88cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB8: 89cabdff1aSopenharmony_ci case AV_PIX_FMT_BGR8: 90cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB4_BYTE: 91cabdff1aSopenharmony_ci case AV_PIX_FMT_BGR4_BYTE: 92cabdff1aSopenharmony_ci case AV_PIX_FMT_GRAY8: 93cabdff1aSopenharmony_ci av_assert1(bit_count == 8); 94cabdff1aSopenharmony_ci avpriv_set_systematic_pal2(palette256, avctx->pix_fmt); 95cabdff1aSopenharmony_ci pal = palette256; 96cabdff1aSopenharmony_ci break; 97cabdff1aSopenharmony_ci case AV_PIX_FMT_PAL8: 98cabdff1aSopenharmony_ci pal = (uint32_t *)p->data[1]; 99cabdff1aSopenharmony_ci break; 100cabdff1aSopenharmony_ci case AV_PIX_FMT_MONOBLACK: 101cabdff1aSopenharmony_ci pal = monoblack_pal; 102cabdff1aSopenharmony_ci break; 103cabdff1aSopenharmony_ci } 104cabdff1aSopenharmony_ci if (pal && !pal_entries) pal_entries = 1 << bit_count; 105cabdff1aSopenharmony_ci n_bytes_per_row = ((int64_t)avctx->width * (int64_t)bit_count + 7LL) >> 3LL; 106cabdff1aSopenharmony_ci pad_bytes_per_row = (4 - n_bytes_per_row) & 3; 107cabdff1aSopenharmony_ci n_bytes_image = avctx->height * (n_bytes_per_row + pad_bytes_per_row); 108cabdff1aSopenharmony_ci 109cabdff1aSopenharmony_ci // STRUCTURE.field refer to the MSVC documentation for BITMAPFILEHEADER 110cabdff1aSopenharmony_ci // and related pages. 111cabdff1aSopenharmony_ci#define SIZE_BITMAPFILEHEADER 14 112cabdff1aSopenharmony_ci#define SIZE_BITMAPINFOHEADER 40 113cabdff1aSopenharmony_ci hsize = SIZE_BITMAPFILEHEADER + SIZE_BITMAPINFOHEADER + (pal_entries << 2); 114cabdff1aSopenharmony_ci n_bytes = n_bytes_image + hsize; 115cabdff1aSopenharmony_ci if ((ret = ff_get_encode_buffer(avctx, pkt, n_bytes, 0)) < 0) 116cabdff1aSopenharmony_ci return ret; 117cabdff1aSopenharmony_ci buf = pkt->data; 118cabdff1aSopenharmony_ci bytestream_put_byte(&buf, 'B'); // BITMAPFILEHEADER.bfType 119cabdff1aSopenharmony_ci bytestream_put_byte(&buf, 'M'); // do. 120cabdff1aSopenharmony_ci bytestream_put_le32(&buf, n_bytes); // BITMAPFILEHEADER.bfSize 121cabdff1aSopenharmony_ci bytestream_put_le16(&buf, 0); // BITMAPFILEHEADER.bfReserved1 122cabdff1aSopenharmony_ci bytestream_put_le16(&buf, 0); // BITMAPFILEHEADER.bfReserved2 123cabdff1aSopenharmony_ci bytestream_put_le32(&buf, hsize); // BITMAPFILEHEADER.bfOffBits 124cabdff1aSopenharmony_ci bytestream_put_le32(&buf, SIZE_BITMAPINFOHEADER); // BITMAPINFOHEADER.biSize 125cabdff1aSopenharmony_ci bytestream_put_le32(&buf, avctx->width); // BITMAPINFOHEADER.biWidth 126cabdff1aSopenharmony_ci bytestream_put_le32(&buf, avctx->height); // BITMAPINFOHEADER.biHeight 127cabdff1aSopenharmony_ci bytestream_put_le16(&buf, 1); // BITMAPINFOHEADER.biPlanes 128cabdff1aSopenharmony_ci bytestream_put_le16(&buf, bit_count); // BITMAPINFOHEADER.biBitCount 129cabdff1aSopenharmony_ci bytestream_put_le32(&buf, compression); // BITMAPINFOHEADER.biCompression 130cabdff1aSopenharmony_ci bytestream_put_le32(&buf, n_bytes_image); // BITMAPINFOHEADER.biSizeImage 131cabdff1aSopenharmony_ci bytestream_put_le32(&buf, 0); // BITMAPINFOHEADER.biXPelsPerMeter 132cabdff1aSopenharmony_ci bytestream_put_le32(&buf, 0); // BITMAPINFOHEADER.biYPelsPerMeter 133cabdff1aSopenharmony_ci bytestream_put_le32(&buf, 0); // BITMAPINFOHEADER.biClrUsed 134cabdff1aSopenharmony_ci bytestream_put_le32(&buf, 0); // BITMAPINFOHEADER.biClrImportant 135cabdff1aSopenharmony_ci for (i = 0; i < pal_entries; i++) 136cabdff1aSopenharmony_ci bytestream_put_le32(&buf, pal[i] & 0xFFFFFF); 137cabdff1aSopenharmony_ci // BMP files are bottom-to-top so we start from the end... 138cabdff1aSopenharmony_ci ptr = p->data[0] + (avctx->height - 1) * p->linesize[0]; 139cabdff1aSopenharmony_ci buf = pkt->data + hsize; 140cabdff1aSopenharmony_ci for(i = 0; i < avctx->height; i++) { 141cabdff1aSopenharmony_ci if (HAVE_BIGENDIAN && bit_count == 16) { 142cabdff1aSopenharmony_ci const uint16_t *src = (const uint16_t *) ptr; 143cabdff1aSopenharmony_ci for(n = 0; n < avctx->width; n++) 144cabdff1aSopenharmony_ci AV_WL16(buf + 2 * n, src[n]); 145cabdff1aSopenharmony_ci } else { 146cabdff1aSopenharmony_ci memcpy(buf, ptr, n_bytes_per_row); 147cabdff1aSopenharmony_ci } 148cabdff1aSopenharmony_ci buf += n_bytes_per_row; 149cabdff1aSopenharmony_ci memset(buf, 0, pad_bytes_per_row); 150cabdff1aSopenharmony_ci buf += pad_bytes_per_row; 151cabdff1aSopenharmony_ci ptr -= p->linesize[0]; // ... and go back 152cabdff1aSopenharmony_ci } 153cabdff1aSopenharmony_ci 154cabdff1aSopenharmony_ci *got_packet = 1; 155cabdff1aSopenharmony_ci return 0; 156cabdff1aSopenharmony_ci} 157cabdff1aSopenharmony_ci 158cabdff1aSopenharmony_ciconst FFCodec ff_bmp_encoder = { 159cabdff1aSopenharmony_ci .p.name = "bmp", 160cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("BMP (Windows and OS/2 bitmap)"), 161cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 162cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_BMP, 163cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 164cabdff1aSopenharmony_ci .init = bmp_encode_init, 165cabdff1aSopenharmony_ci FF_CODEC_ENCODE_CB(bmp_encode_frame), 166cabdff1aSopenharmony_ci .p.pix_fmts = (const enum AVPixelFormat[]){ 167cabdff1aSopenharmony_ci AV_PIX_FMT_BGRA, AV_PIX_FMT_BGR24, 168cabdff1aSopenharmony_ci AV_PIX_FMT_RGB565, AV_PIX_FMT_RGB555, AV_PIX_FMT_RGB444, 169cabdff1aSopenharmony_ci 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, 170cabdff1aSopenharmony_ci AV_PIX_FMT_MONOBLACK, 171cabdff1aSopenharmony_ci AV_PIX_FMT_NONE 172cabdff1aSopenharmony_ci }, 173cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 174cabdff1aSopenharmony_ci}; 175