1/* 2 * PNM image format 3 * Copyright (c) 2002, 2003 Fabrice Bellard 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include "config_components.h" 23 24#include "libavutil/intreadwrite.h" 25#include "libavutil/imgutils.h" 26#include "libavutil/pixdesc.h" 27#include "avcodec.h" 28#include "codec_internal.h" 29#include "encode.h" 30#include "float2half.h" 31 32typedef struct PHMEncContext { 33 uint16_t basetable[512]; 34 uint8_t shifttable[512]; 35} PHMEncContext; 36 37static int pnm_encode_frame(AVCodecContext *avctx, AVPacket *pkt, 38 const AVFrame *p, int *got_packet) 39{ 40 PHMEncContext *s = avctx->priv_data; 41 uint8_t *bytestream, *bytestream_start, *bytestream_end; 42 int i, h, h1, c, n, linesize, ret; 43 uint8_t *ptr, *ptr1, *ptr2; 44 int size = av_image_get_buffer_size(avctx->pix_fmt, 45 avctx->width, avctx->height, 1); 46 47 if ((ret = ff_get_encode_buffer(avctx, pkt, size + 200, 0)) < 0) 48 return ret; 49 50 bytestream_start = 51 bytestream = pkt->data; 52 bytestream_end = pkt->data + pkt->size; 53 54 h = avctx->height; 55 h1 = h; 56 switch (avctx->pix_fmt) { 57 case AV_PIX_FMT_MONOWHITE: 58 c = '4'; 59 n = (avctx->width + 7) >> 3; 60 break; 61 case AV_PIX_FMT_GRAY8: 62 c = '5'; 63 n = avctx->width; 64 break; 65 case AV_PIX_FMT_GRAY16BE: 66 c = '5'; 67 n = avctx->width * 2; 68 break; 69 case AV_PIX_FMT_RGB24: 70 c = '6'; 71 n = avctx->width * 3; 72 break; 73 case AV_PIX_FMT_RGB48BE: 74 c = '6'; 75 n = avctx->width * 6; 76 break; 77 case AV_PIX_FMT_YUV420P: 78 if (avctx->width & 1 || avctx->height & 1) { 79 av_log(avctx, AV_LOG_ERROR, "pgmyuv needs even width and height\n"); 80 return AVERROR(EINVAL); 81 } 82 c = '5'; 83 n = avctx->width; 84 h1 = (h * 3) / 2; 85 break; 86 case AV_PIX_FMT_YUV420P16BE: 87 c = '5'; 88 n = avctx->width * 2; 89 h1 = (h * 3) / 2; 90 break; 91 case AV_PIX_FMT_GBRPF32BE: 92 case AV_PIX_FMT_GBRPF32LE: 93 if (avctx->codec_id == AV_CODEC_ID_PFM) { 94 c = 'F'; 95 n = avctx->width * 4; 96 } else { 97 c = 'H'; 98 n = avctx->width * 2; 99 } 100 break; 101 case AV_PIX_FMT_GRAYF32BE: 102 case AV_PIX_FMT_GRAYF32LE: 103 if (avctx->codec_id == AV_CODEC_ID_PFM) { 104 c = 'f'; 105 n = avctx->width * 4; 106 } else { 107 c = 'h'; 108 n = avctx->width * 2; 109 } 110 break; 111 default: 112 return -1; 113 } 114 snprintf(bytestream, bytestream_end - bytestream, 115 "P%c\n%d %d\n", c, avctx->width, h1); 116 bytestream += strlen(bytestream); 117 if (avctx->pix_fmt == AV_PIX_FMT_GBRPF32LE || 118 avctx->pix_fmt == AV_PIX_FMT_GRAYF32LE || 119 avctx->pix_fmt == AV_PIX_FMT_GBRPF32BE || 120 avctx->pix_fmt == AV_PIX_FMT_GRAYF32BE) 121 snprintf(bytestream, bytestream_end - bytestream, 122 "%f\n", (avctx->pix_fmt == AV_PIX_FMT_GBRPF32BE || 123 avctx->pix_fmt == AV_PIX_FMT_GRAYF32BE) ? 1.f: -1.f); 124 bytestream += strlen(bytestream); 125 if (avctx->pix_fmt != AV_PIX_FMT_MONOWHITE && 126 avctx->pix_fmt != AV_PIX_FMT_GBRPF32LE && 127 avctx->pix_fmt != AV_PIX_FMT_GRAYF32LE && 128 avctx->pix_fmt != AV_PIX_FMT_GBRPF32BE && 129 avctx->pix_fmt != AV_PIX_FMT_GRAYF32BE) { 130 int maxdepth = (1 << av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth) - 1; 131 snprintf(bytestream, bytestream_end - bytestream, 132 "%d\n", maxdepth); 133 bytestream += strlen(bytestream); 134 } 135 136 if ((avctx->pix_fmt == AV_PIX_FMT_GBRPF32LE || 137 avctx->pix_fmt == AV_PIX_FMT_GBRPF32BE) && c == 'F') { 138 float *r = (float *)p->data[2]; 139 float *g = (float *)p->data[0]; 140 float *b = (float *)p->data[1]; 141 142 for (int i = 0; i < avctx->height; i++) { 143 for (int j = 0; j < avctx->width; j++) { 144 AV_WN32(bytestream + 0, av_float2int(r[j])); 145 AV_WN32(bytestream + 4, av_float2int(g[j])); 146 AV_WN32(bytestream + 8, av_float2int(b[j])); 147 bytestream += 12; 148 } 149 150 r += p->linesize[2] / 4; 151 g += p->linesize[0] / 4; 152 b += p->linesize[1] / 4; 153 } 154 } else if ((avctx->pix_fmt == AV_PIX_FMT_GRAYF32LE || 155 avctx->pix_fmt == AV_PIX_FMT_GRAYF32BE) && c == 'f') { 156 const float *g = (const float *)p->data[0]; 157 158 for (int i = 0; i < avctx->height; i++) { 159 for (int j = 0; j < avctx->width; j++) { 160 AV_WN32(bytestream, av_float2int(g[j])); 161 bytestream += 4; 162 } 163 164 g += p->linesize[0] / 4; 165 } 166 } else if (avctx->pix_fmt == AV_PIX_FMT_GBRPF32 && c == 'H') { 167 float *r = (float *)p->data[2]; 168 float *g = (float *)p->data[0]; 169 float *b = (float *)p->data[1]; 170 171 for (int i = 0; i < avctx->height; i++) { 172 for (int j = 0; j < avctx->width; j++) { 173 AV_WN16(bytestream + 0, float2half(av_float2int(r[j]), s->basetable, s->shifttable)); 174 AV_WN16(bytestream + 2, float2half(av_float2int(g[j]), s->basetable, s->shifttable)); 175 AV_WN16(bytestream + 4, float2half(av_float2int(b[j]), s->basetable, s->shifttable)); 176 bytestream += 6; 177 } 178 179 r += p->linesize[2] / 4; 180 g += p->linesize[0] / 4; 181 b += p->linesize[1] / 4; 182 } 183 } else if (avctx->pix_fmt == AV_PIX_FMT_GRAYF32 && c == 'h') { 184 const float *g = (const float *)p->data[0]; 185 186 for (int i = 0; i < avctx->height; i++) { 187 for (int j = 0; j < avctx->width; j++) { 188 AV_WN16(bytestream, float2half(av_float2int(g[j]), s->basetable, s->shifttable)); 189 bytestream += 2; 190 } 191 192 g += p->linesize[0] / 4; 193 } 194 } else { 195 ptr = p->data[0]; 196 linesize = p->linesize[0]; 197 for (i = 0; i < h; i++) { 198 memcpy(bytestream, ptr, n); 199 bytestream += n; 200 ptr += linesize; 201 } 202 } 203 204 if (avctx->pix_fmt == AV_PIX_FMT_YUV420P || avctx->pix_fmt == AV_PIX_FMT_YUV420P16BE) { 205 h >>= 1; 206 n >>= 1; 207 ptr1 = p->data[1]; 208 ptr2 = p->data[2]; 209 for (i = 0; i < h; i++) { 210 memcpy(bytestream, ptr1, n); 211 bytestream += n; 212 memcpy(bytestream, ptr2, n); 213 bytestream += n; 214 ptr1 += p->linesize[1]; 215 ptr2 += p->linesize[2]; 216 } 217 } 218 av_shrink_packet(pkt, bytestream - bytestream_start); 219 *got_packet = 1; 220 221 return 0; 222} 223 224#if CONFIG_PGM_ENCODER 225const FFCodec ff_pgm_encoder = { 226 .p.name = "pgm", 227 .p.long_name = NULL_IF_CONFIG_SMALL("PGM (Portable GrayMap) image"), 228 .p.type = AVMEDIA_TYPE_VIDEO, 229 .p.id = AV_CODEC_ID_PGM, 230 .p.capabilities = AV_CODEC_CAP_DR1, 231 FF_CODEC_ENCODE_CB(pnm_encode_frame), 232 .p.pix_fmts = (const enum AVPixelFormat[]){ 233 AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_NONE 234 }, 235 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 236}; 237#endif 238 239#if CONFIG_PGMYUV_ENCODER 240const FFCodec ff_pgmyuv_encoder = { 241 .p.name = "pgmyuv", 242 .p.long_name = NULL_IF_CONFIG_SMALL("PGMYUV (Portable GrayMap YUV) image"), 243 .p.type = AVMEDIA_TYPE_VIDEO, 244 .p.id = AV_CODEC_ID_PGMYUV, 245 .p.capabilities = AV_CODEC_CAP_DR1, 246 FF_CODEC_ENCODE_CB(pnm_encode_frame), 247 .p.pix_fmts = (const enum AVPixelFormat[]){ 248 AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_NONE 249 }, 250 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 251}; 252#endif 253 254#if CONFIG_PPM_ENCODER 255const FFCodec ff_ppm_encoder = { 256 .p.name = "ppm", 257 .p.long_name = NULL_IF_CONFIG_SMALL("PPM (Portable PixelMap) image"), 258 .p.type = AVMEDIA_TYPE_VIDEO, 259 .p.id = AV_CODEC_ID_PPM, 260 .p.capabilities = AV_CODEC_CAP_DR1, 261 FF_CODEC_ENCODE_CB(pnm_encode_frame), 262 .p.pix_fmts = (const enum AVPixelFormat[]){ 263 AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48BE, AV_PIX_FMT_NONE 264 }, 265 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 266}; 267#endif 268 269#if CONFIG_PBM_ENCODER 270const FFCodec ff_pbm_encoder = { 271 .p.name = "pbm", 272 .p.long_name = NULL_IF_CONFIG_SMALL("PBM (Portable BitMap) image"), 273 .p.type = AVMEDIA_TYPE_VIDEO, 274 .p.id = AV_CODEC_ID_PBM, 275 .p.capabilities = AV_CODEC_CAP_DR1, 276 FF_CODEC_ENCODE_CB(pnm_encode_frame), 277 .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_MONOWHITE, 278 AV_PIX_FMT_NONE }, 279 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 280}; 281#endif 282 283#if CONFIG_PFM_ENCODER 284const FFCodec ff_pfm_encoder = { 285 .p.name = "pfm", 286 .p.long_name = NULL_IF_CONFIG_SMALL("PFM (Portable FloatMap) image"), 287 .p.type = AVMEDIA_TYPE_VIDEO, 288 .p.id = AV_CODEC_ID_PFM, 289 .p.capabilities = AV_CODEC_CAP_DR1, 290 FF_CODEC_ENCODE_CB(pnm_encode_frame), 291 .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_GBRPF32LE, 292 AV_PIX_FMT_GRAYF32LE, 293 AV_PIX_FMT_GBRPF32BE, 294 AV_PIX_FMT_GRAYF32BE, 295 AV_PIX_FMT_NONE }, 296 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 297}; 298#endif 299 300#if CONFIG_PHM_ENCODER 301static av_cold int phm_enc_init(AVCodecContext *avctx) 302{ 303 PHMEncContext *s = avctx->priv_data; 304 305 float2half_tables(s->basetable, s->shifttable); 306 307 return 0; 308} 309 310const FFCodec ff_phm_encoder = { 311 .p.name = "phm", 312 .p.long_name = NULL_IF_CONFIG_SMALL("PHM (Portable HalfFloatMap) image"), 313 .p.type = AVMEDIA_TYPE_VIDEO, 314 .p.id = AV_CODEC_ID_PHM, 315 .p.capabilities = AV_CODEC_CAP_DR1, 316 .priv_data_size = sizeof(PHMEncContext), 317 .init = phm_enc_init, 318 FF_CODEC_ENCODE_CB(pnm_encode_frame), 319 .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_GBRPF32, 320 AV_PIX_FMT_GRAYF32, 321 AV_PIX_FMT_NONE }, 322 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 323}; 324#endif 325