1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * TIFF image encoder
3cabdff1aSopenharmony_ci * Copyright (c) 2007 Bartlomiej Wolowiec
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci/**
23cabdff1aSopenharmony_ci * @file
24cabdff1aSopenharmony_ci * TIFF image encoder
25cabdff1aSopenharmony_ci * @author Bartlomiej Wolowiec
26cabdff1aSopenharmony_ci */
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_ci#include "config.h"
29cabdff1aSopenharmony_ci#if CONFIG_ZLIB
30cabdff1aSopenharmony_ci#include <zlib.h>
31cabdff1aSopenharmony_ci#endif
32cabdff1aSopenharmony_ci
33cabdff1aSopenharmony_ci#include "libavutil/imgutils.h"
34cabdff1aSopenharmony_ci#include "libavutil/log.h"
35cabdff1aSopenharmony_ci#include "libavutil/opt.h"
36cabdff1aSopenharmony_ci#include "libavutil/pixdesc.h"
37cabdff1aSopenharmony_ci#include "avcodec.h"
38cabdff1aSopenharmony_ci#include "bytestream.h"
39cabdff1aSopenharmony_ci#include "codec_internal.h"
40cabdff1aSopenharmony_ci#include "encode.h"
41cabdff1aSopenharmony_ci#include "lzw.h"
42cabdff1aSopenharmony_ci#include "put_bits.h"
43cabdff1aSopenharmony_ci#include "rle.h"
44cabdff1aSopenharmony_ci#include "tiff.h"
45cabdff1aSopenharmony_ci#include "version.h"
46cabdff1aSopenharmony_ci
47cabdff1aSopenharmony_ci#define TIFF_MAX_ENTRY 32
48cabdff1aSopenharmony_ci
49cabdff1aSopenharmony_ci/** sizes of various TIFF field types (string size = 1)*/
50cabdff1aSopenharmony_cistatic const uint8_t type_sizes2[14] = {
51cabdff1aSopenharmony_ci    0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4
52cabdff1aSopenharmony_ci};
53cabdff1aSopenharmony_ci
54cabdff1aSopenharmony_citypedef struct TiffEncoderContext {
55cabdff1aSopenharmony_ci    AVClass *class;                         ///< for private options
56cabdff1aSopenharmony_ci    AVCodecContext *avctx;
57cabdff1aSopenharmony_ci
58cabdff1aSopenharmony_ci    int width;                              ///< picture width
59cabdff1aSopenharmony_ci    int height;                             ///< picture height
60cabdff1aSopenharmony_ci    unsigned int bpp;                       ///< bits per pixel
61cabdff1aSopenharmony_ci    int compr;                              ///< compression level
62cabdff1aSopenharmony_ci    int bpp_tab_size;                       ///< bpp_tab size
63cabdff1aSopenharmony_ci    enum TiffPhotometric photometric_interpretation;  ///< photometric interpretation
64cabdff1aSopenharmony_ci    int strips;                             ///< number of strips
65cabdff1aSopenharmony_ci    uint32_t *strip_sizes;
66cabdff1aSopenharmony_ci    unsigned int strip_sizes_size;
67cabdff1aSopenharmony_ci    uint32_t *strip_offsets;
68cabdff1aSopenharmony_ci    unsigned int strip_offsets_size;
69cabdff1aSopenharmony_ci    uint8_t *yuv_line;
70cabdff1aSopenharmony_ci    unsigned int yuv_line_size;
71cabdff1aSopenharmony_ci    int rps;                                ///< row per strip
72cabdff1aSopenharmony_ci    uint8_t entries[TIFF_MAX_ENTRY * 12];   ///< entries in header
73cabdff1aSopenharmony_ci    int num_entries;                        ///< number of entries
74cabdff1aSopenharmony_ci    uint8_t **buf;                          ///< actual position in buffer
75cabdff1aSopenharmony_ci    uint8_t *buf_start;                     ///< pointer to first byte in buffer
76cabdff1aSopenharmony_ci    int buf_size;                           ///< buffer size
77cabdff1aSopenharmony_ci    uint16_t subsampling[2];                ///< YUV subsampling factors
78cabdff1aSopenharmony_ci    struct LZWEncodeState *lzws;            ///< LZW encode state
79cabdff1aSopenharmony_ci    uint32_t dpi;                           ///< image resolution in DPI
80cabdff1aSopenharmony_ci} TiffEncoderContext;
81cabdff1aSopenharmony_ci
82cabdff1aSopenharmony_ci/**
83cabdff1aSopenharmony_ci * Check free space in buffer.
84cabdff1aSopenharmony_ci *
85cabdff1aSopenharmony_ci * @param s Tiff context
86cabdff1aSopenharmony_ci * @param need Needed bytes
87cabdff1aSopenharmony_ci * @return 0 - ok, 1 - no free space
88cabdff1aSopenharmony_ci */
89cabdff1aSopenharmony_cistatic inline int check_size(TiffEncoderContext *s, uint64_t need)
90cabdff1aSopenharmony_ci{
91cabdff1aSopenharmony_ci    if (s->buf_size < *s->buf - s->buf_start + need) {
92cabdff1aSopenharmony_ci        *s->buf = s->buf_start + s->buf_size + 1;
93cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_ERROR, "Buffer is too small\n");
94cabdff1aSopenharmony_ci        return 1;
95cabdff1aSopenharmony_ci    }
96cabdff1aSopenharmony_ci    return 0;
97cabdff1aSopenharmony_ci}
98cabdff1aSopenharmony_ci
99cabdff1aSopenharmony_ci/**
100cabdff1aSopenharmony_ci * Put n values to buffer.
101cabdff1aSopenharmony_ci *
102cabdff1aSopenharmony_ci * @param p pointer to pointer to output buffer
103cabdff1aSopenharmony_ci * @param n number of values
104cabdff1aSopenharmony_ci * @param val pointer to values
105cabdff1aSopenharmony_ci * @param type type of values
106cabdff1aSopenharmony_ci * @param flip = 0 - normal copy, >0 - flip
107cabdff1aSopenharmony_ci */
108cabdff1aSopenharmony_cistatic void tnput(uint8_t **p, int n, const uint8_t *val, enum TiffTypes type,
109cabdff1aSopenharmony_ci                  int flip)
110cabdff1aSopenharmony_ci{
111cabdff1aSopenharmony_ci    int i;
112cabdff1aSopenharmony_ci#if HAVE_BIGENDIAN
113cabdff1aSopenharmony_ci    flip ^= ((int[]) { 0, 0, 0, 1, 3, 3 })[type];
114cabdff1aSopenharmony_ci#endif
115cabdff1aSopenharmony_ci    for (i = 0; i < n * type_sizes2[type]; i++)
116cabdff1aSopenharmony_ci        *(*p)++ = val[i ^ flip];
117cabdff1aSopenharmony_ci}
118cabdff1aSopenharmony_ci
119cabdff1aSopenharmony_ci/**
120cabdff1aSopenharmony_ci * Add entry to directory in tiff header.
121cabdff1aSopenharmony_ci *
122cabdff1aSopenharmony_ci * @param s Tiff context
123cabdff1aSopenharmony_ci * @param tag tag that identifies the entry
124cabdff1aSopenharmony_ci * @param type entry type
125cabdff1aSopenharmony_ci * @param count the number of values
126cabdff1aSopenharmony_ci * @param ptr_val pointer to values
127cabdff1aSopenharmony_ci */
128cabdff1aSopenharmony_cistatic int add_entry(TiffEncoderContext *s, enum TiffTags tag,
129cabdff1aSopenharmony_ci                     enum TiffTypes type, int count, const void *ptr_val)
130cabdff1aSopenharmony_ci{
131cabdff1aSopenharmony_ci    uint8_t *entries_ptr = s->entries + 12 * s->num_entries;
132cabdff1aSopenharmony_ci
133cabdff1aSopenharmony_ci    av_assert0(s->num_entries < TIFF_MAX_ENTRY);
134cabdff1aSopenharmony_ci
135cabdff1aSopenharmony_ci    bytestream_put_le16(&entries_ptr, tag);
136cabdff1aSopenharmony_ci    bytestream_put_le16(&entries_ptr, type);
137cabdff1aSopenharmony_ci    bytestream_put_le32(&entries_ptr, count);
138cabdff1aSopenharmony_ci
139cabdff1aSopenharmony_ci    if (type_sizes[type] * (int64_t)count <= 4) {
140cabdff1aSopenharmony_ci        tnput(&entries_ptr, count, ptr_val, type, 0);
141cabdff1aSopenharmony_ci    } else {
142cabdff1aSopenharmony_ci        bytestream_put_le32(&entries_ptr, *s->buf - s->buf_start);
143cabdff1aSopenharmony_ci        if (check_size(s, count * (int64_t)type_sizes2[type]))
144cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
145cabdff1aSopenharmony_ci        tnput(s->buf, count, ptr_val, type, 0);
146cabdff1aSopenharmony_ci    }
147cabdff1aSopenharmony_ci
148cabdff1aSopenharmony_ci    s->num_entries++;
149cabdff1aSopenharmony_ci    return 0;
150cabdff1aSopenharmony_ci}
151cabdff1aSopenharmony_ci
152cabdff1aSopenharmony_cistatic int add_entry1(TiffEncoderContext *s,
153cabdff1aSopenharmony_ci                      enum TiffTags tag, enum TiffTypes type, int val)
154cabdff1aSopenharmony_ci{
155cabdff1aSopenharmony_ci    uint16_t w  = val;
156cabdff1aSopenharmony_ci    uint32_t dw = val;
157cabdff1aSopenharmony_ci    return add_entry(s, tag, type, 1,
158cabdff1aSopenharmony_ci                     type == TIFF_SHORT ? (void *)&w : (void *)&dw);
159cabdff1aSopenharmony_ci}
160cabdff1aSopenharmony_ci
161cabdff1aSopenharmony_ci/**
162cabdff1aSopenharmony_ci * Encode one strip in tiff file.
163cabdff1aSopenharmony_ci *
164cabdff1aSopenharmony_ci * @param s Tiff context
165cabdff1aSopenharmony_ci * @param src input buffer
166cabdff1aSopenharmony_ci * @param dst output buffer
167cabdff1aSopenharmony_ci * @param n size of input buffer
168cabdff1aSopenharmony_ci * @param compr compression method
169cabdff1aSopenharmony_ci * @return number of output bytes. If an output error is encountered, a negative
170cabdff1aSopenharmony_ci * value corresponding to an AVERROR error code is returned.
171cabdff1aSopenharmony_ci */
172cabdff1aSopenharmony_cistatic int encode_strip(TiffEncoderContext *s, const int8_t *src,
173cabdff1aSopenharmony_ci                        uint8_t *dst, int n, int compr)
174cabdff1aSopenharmony_ci{
175cabdff1aSopenharmony_ci    switch (compr) {
176cabdff1aSopenharmony_ci#if CONFIG_ZLIB
177cabdff1aSopenharmony_ci    case TIFF_DEFLATE:
178cabdff1aSopenharmony_ci    case TIFF_ADOBE_DEFLATE:
179cabdff1aSopenharmony_ci    {
180cabdff1aSopenharmony_ci        unsigned long zlen = s->buf_size - (*s->buf - s->buf_start);
181cabdff1aSopenharmony_ci        if (compress(dst, &zlen, src, n) != Z_OK) {
182cabdff1aSopenharmony_ci            av_log(s->avctx, AV_LOG_ERROR, "Compressing failed\n");
183cabdff1aSopenharmony_ci            return AVERROR_EXTERNAL;
184cabdff1aSopenharmony_ci        }
185cabdff1aSopenharmony_ci        return zlen;
186cabdff1aSopenharmony_ci    }
187cabdff1aSopenharmony_ci#endif
188cabdff1aSopenharmony_ci    case TIFF_RAW:
189cabdff1aSopenharmony_ci        if (check_size(s, n))
190cabdff1aSopenharmony_ci            return AVERROR(EINVAL);
191cabdff1aSopenharmony_ci        memcpy(dst, src, n);
192cabdff1aSopenharmony_ci        return n;
193cabdff1aSopenharmony_ci    case TIFF_PACKBITS:
194cabdff1aSopenharmony_ci        return ff_rle_encode(dst, s->buf_size - (*s->buf - s->buf_start),
195cabdff1aSopenharmony_ci                             src, 1, n, 2, 0xff, -1, 0);
196cabdff1aSopenharmony_ci    case TIFF_LZW:
197cabdff1aSopenharmony_ci        return ff_lzw_encode(s->lzws, src, n);
198cabdff1aSopenharmony_ci    default:
199cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_ERROR, "Unsupported compression method: %d\n",
200cabdff1aSopenharmony_ci               compr);
201cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
202cabdff1aSopenharmony_ci    }
203cabdff1aSopenharmony_ci}
204cabdff1aSopenharmony_ci
205cabdff1aSopenharmony_cistatic void pack_yuv(TiffEncoderContext *s, const AVFrame *p,
206cabdff1aSopenharmony_ci                     uint8_t *dst, int lnum)
207cabdff1aSopenharmony_ci{
208cabdff1aSopenharmony_ci    int i, j, k;
209cabdff1aSopenharmony_ci    int w       = (s->width - 1) / s->subsampling[0] + 1;
210cabdff1aSopenharmony_ci    uint8_t *pu = &p->data[1][lnum / s->subsampling[1] * p->linesize[1]];
211cabdff1aSopenharmony_ci    uint8_t *pv = &p->data[2][lnum / s->subsampling[1] * p->linesize[2]];
212cabdff1aSopenharmony_ci    if (s->width % s->subsampling[0] || s->height % s->subsampling[1]) {
213cabdff1aSopenharmony_ci        for (i = 0; i < w; i++) {
214cabdff1aSopenharmony_ci            for (j = 0; j < s->subsampling[1]; j++)
215cabdff1aSopenharmony_ci                for (k = 0; k < s->subsampling[0]; k++)
216cabdff1aSopenharmony_ci                    *dst++ = p->data[0][FFMIN(lnum + j, s->height-1) * p->linesize[0] +
217cabdff1aSopenharmony_ci                                        FFMIN(i * s->subsampling[0] + k, s->width-1)];
218cabdff1aSopenharmony_ci            *dst++ = *pu++;
219cabdff1aSopenharmony_ci            *dst++ = *pv++;
220cabdff1aSopenharmony_ci        }
221cabdff1aSopenharmony_ci    }else{
222cabdff1aSopenharmony_ci        for (i = 0; i < w; i++) {
223cabdff1aSopenharmony_ci            for (j = 0; j < s->subsampling[1]; j++)
224cabdff1aSopenharmony_ci                for (k = 0; k < s->subsampling[0]; k++)
225cabdff1aSopenharmony_ci                    *dst++ = p->data[0][(lnum + j) * p->linesize[0] +
226cabdff1aSopenharmony_ci                                        i * s->subsampling[0] + k];
227cabdff1aSopenharmony_ci            *dst++ = *pu++;
228cabdff1aSopenharmony_ci            *dst++ = *pv++;
229cabdff1aSopenharmony_ci        }
230cabdff1aSopenharmony_ci    }
231cabdff1aSopenharmony_ci}
232cabdff1aSopenharmony_ci
233cabdff1aSopenharmony_ci#define ADD_ENTRY(s, tag, type, count, ptr_val)         \
234cabdff1aSopenharmony_ci    do {                                                \
235cabdff1aSopenharmony_ci        ret = add_entry(s, tag, type, count, ptr_val);  \
236cabdff1aSopenharmony_ci        if (ret < 0)                                    \
237cabdff1aSopenharmony_ci            goto fail;                                  \
238cabdff1aSopenharmony_ci    } while (0)
239cabdff1aSopenharmony_ci
240cabdff1aSopenharmony_ci#define ADD_ENTRY1(s, tag, type, val)           \
241cabdff1aSopenharmony_ci    do {                                        \
242cabdff1aSopenharmony_ci        ret = add_entry1(s, tag, type, val);    \
243cabdff1aSopenharmony_ci        if (ret < 0)                            \
244cabdff1aSopenharmony_ci            goto fail;                          \
245cabdff1aSopenharmony_ci    } while (0)
246cabdff1aSopenharmony_ci
247cabdff1aSopenharmony_cistatic int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
248cabdff1aSopenharmony_ci                        const AVFrame *pict, int *got_packet)
249cabdff1aSopenharmony_ci{
250cabdff1aSopenharmony_ci    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
251cabdff1aSopenharmony_ci    TiffEncoderContext *s = avctx->priv_data;
252cabdff1aSopenharmony_ci    const AVFrame *const p = pict;
253cabdff1aSopenharmony_ci    int i;
254cabdff1aSopenharmony_ci    uint8_t *ptr;
255cabdff1aSopenharmony_ci    uint8_t *offset;
256cabdff1aSopenharmony_ci    uint32_t strips;
257cabdff1aSopenharmony_ci    int bytes_per_row;
258cabdff1aSopenharmony_ci    uint32_t res[2] = { s->dpi, 1 };    // image resolution (72/1)
259cabdff1aSopenharmony_ci    uint16_t bpp_tab[4];
260cabdff1aSopenharmony_ci    int ret = 0;
261cabdff1aSopenharmony_ci    int is_yuv = 0, alpha = 0;
262cabdff1aSopenharmony_ci    int shift_h, shift_v;
263cabdff1aSopenharmony_ci    int packet_size;
264cabdff1aSopenharmony_ci
265cabdff1aSopenharmony_ci    s->width          = avctx->width;
266cabdff1aSopenharmony_ci    s->height         = avctx->height;
267cabdff1aSopenharmony_ci    s->subsampling[0] = 1;
268cabdff1aSopenharmony_ci    s->subsampling[1] = 1;
269cabdff1aSopenharmony_ci
270cabdff1aSopenharmony_ci    if (!desc)
271cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
272cabdff1aSopenharmony_ci
273cabdff1aSopenharmony_ci    avctx->bits_per_coded_sample =
274cabdff1aSopenharmony_ci    s->bpp          = av_get_bits_per_pixel(desc);
275cabdff1aSopenharmony_ci    s->bpp_tab_size = desc->nb_components;
276cabdff1aSopenharmony_ci
277cabdff1aSopenharmony_ci    switch (avctx->pix_fmt) {
278cabdff1aSopenharmony_ci    case AV_PIX_FMT_RGBA64LE:
279cabdff1aSopenharmony_ci    case AV_PIX_FMT_RGBA:
280cabdff1aSopenharmony_ci        alpha = 1;
281cabdff1aSopenharmony_ci    case AV_PIX_FMT_RGB48LE:
282cabdff1aSopenharmony_ci    case AV_PIX_FMT_RGB24:
283cabdff1aSopenharmony_ci        s->photometric_interpretation = TIFF_PHOTOMETRIC_RGB;
284cabdff1aSopenharmony_ci        break;
285cabdff1aSopenharmony_ci    case AV_PIX_FMT_GRAY8:
286cabdff1aSopenharmony_ci        avctx->bits_per_coded_sample = 0x28;
287cabdff1aSopenharmony_ci    case AV_PIX_FMT_GRAY8A:
288cabdff1aSopenharmony_ci    case AV_PIX_FMT_YA16LE:
289cabdff1aSopenharmony_ci        alpha = avctx->pix_fmt == AV_PIX_FMT_GRAY8A || avctx->pix_fmt == AV_PIX_FMT_YA16LE;
290cabdff1aSopenharmony_ci    case AV_PIX_FMT_GRAY16LE:
291cabdff1aSopenharmony_ci    case AV_PIX_FMT_MONOBLACK:
292cabdff1aSopenharmony_ci        s->photometric_interpretation = TIFF_PHOTOMETRIC_BLACK_IS_ZERO;
293cabdff1aSopenharmony_ci        break;
294cabdff1aSopenharmony_ci    case AV_PIX_FMT_PAL8:
295cabdff1aSopenharmony_ci        s->photometric_interpretation = TIFF_PHOTOMETRIC_PALETTE;
296cabdff1aSopenharmony_ci        break;
297cabdff1aSopenharmony_ci    case AV_PIX_FMT_MONOWHITE:
298cabdff1aSopenharmony_ci        s->photometric_interpretation = TIFF_PHOTOMETRIC_WHITE_IS_ZERO;
299cabdff1aSopenharmony_ci        break;
300cabdff1aSopenharmony_ci    case AV_PIX_FMT_YUV420P:
301cabdff1aSopenharmony_ci    case AV_PIX_FMT_YUV422P:
302cabdff1aSopenharmony_ci    case AV_PIX_FMT_YUV440P:
303cabdff1aSopenharmony_ci    case AV_PIX_FMT_YUV444P:
304cabdff1aSopenharmony_ci    case AV_PIX_FMT_YUV410P:
305cabdff1aSopenharmony_ci    case AV_PIX_FMT_YUV411P:
306cabdff1aSopenharmony_ci        av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &shift_h, &shift_v);
307cabdff1aSopenharmony_ci        s->photometric_interpretation = TIFF_PHOTOMETRIC_YCBCR;
308cabdff1aSopenharmony_ci        s->subsampling[0]             = 1 << shift_h;
309cabdff1aSopenharmony_ci        s->subsampling[1]             = 1 << shift_v;
310cabdff1aSopenharmony_ci        is_yuv                        = 1;
311cabdff1aSopenharmony_ci        break;
312cabdff1aSopenharmony_ci    default:
313cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_ERROR,
314cabdff1aSopenharmony_ci               "This colors format is not supported\n");
315cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
316cabdff1aSopenharmony_ci    }
317cabdff1aSopenharmony_ci
318cabdff1aSopenharmony_ci    for (i = 0; i < s->bpp_tab_size; i++)
319cabdff1aSopenharmony_ci        bpp_tab[i] = desc->comp[i].depth;
320cabdff1aSopenharmony_ci
321cabdff1aSopenharmony_ci    if (s->compr == TIFF_DEFLATE       ||
322cabdff1aSopenharmony_ci        s->compr == TIFF_ADOBE_DEFLATE ||
323cabdff1aSopenharmony_ci        s->compr == TIFF_LZW)
324cabdff1aSopenharmony_ci        // best choice for DEFLATE
325cabdff1aSopenharmony_ci        s->rps = s->height;
326cabdff1aSopenharmony_ci    else
327cabdff1aSopenharmony_ci        // suggest size of strip
328cabdff1aSopenharmony_ci        s->rps = FFMAX(8192 / (((s->width * s->bpp) >> 3) + 1), 1);
329cabdff1aSopenharmony_ci    // round rps up
330cabdff1aSopenharmony_ci    s->rps = ((s->rps - 1) / s->subsampling[1] + 1) * s->subsampling[1];
331cabdff1aSopenharmony_ci
332cabdff1aSopenharmony_ci    strips = (s->height - 1) / s->rps + 1;
333cabdff1aSopenharmony_ci
334cabdff1aSopenharmony_ci    bytes_per_row = (((s->width - 1) / s->subsampling[0] + 1) * s->bpp *
335cabdff1aSopenharmony_ci                     s->subsampling[0] * s->subsampling[1] + 7) >> 3;
336cabdff1aSopenharmony_ci    packet_size = avctx->height * bytes_per_row * 2 +
337cabdff1aSopenharmony_ci                  avctx->height * 4 + AV_INPUT_BUFFER_MIN_SIZE;
338cabdff1aSopenharmony_ci
339cabdff1aSopenharmony_ci    if ((ret = ff_alloc_packet(avctx, pkt, packet_size)) < 0)
340cabdff1aSopenharmony_ci        return ret;
341cabdff1aSopenharmony_ci    ptr          = pkt->data;
342cabdff1aSopenharmony_ci    s->buf_start = pkt->data;
343cabdff1aSopenharmony_ci    s->buf       = &ptr;
344cabdff1aSopenharmony_ci    s->buf_size  = pkt->size;
345cabdff1aSopenharmony_ci
346cabdff1aSopenharmony_ci    if (check_size(s, 8)) {
347cabdff1aSopenharmony_ci        ret = AVERROR(EINVAL);
348cabdff1aSopenharmony_ci        goto fail;
349cabdff1aSopenharmony_ci    }
350cabdff1aSopenharmony_ci
351cabdff1aSopenharmony_ci    // write header
352cabdff1aSopenharmony_ci    bytestream_put_le16(&ptr, 0x4949);
353cabdff1aSopenharmony_ci    bytestream_put_le16(&ptr, 42);
354cabdff1aSopenharmony_ci
355cabdff1aSopenharmony_ci    offset = ptr;
356cabdff1aSopenharmony_ci    bytestream_put_le32(&ptr, 0);
357cabdff1aSopenharmony_ci
358cabdff1aSopenharmony_ci    if (strips > INT_MAX / FFMAX(sizeof(s->strip_sizes[0]), sizeof(s->strip_offsets[0]))) {
359cabdff1aSopenharmony_ci        ret = AVERROR(ENOMEM);
360cabdff1aSopenharmony_ci        goto fail;
361cabdff1aSopenharmony_ci    }
362cabdff1aSopenharmony_ci    av_fast_padded_mallocz(&s->strip_sizes  , &s->strip_sizes_size  , sizeof(s->strip_sizes  [0]) * strips);
363cabdff1aSopenharmony_ci    av_fast_padded_mallocz(&s->strip_offsets, &s->strip_offsets_size, sizeof(s->strip_offsets[0]) * strips);
364cabdff1aSopenharmony_ci
365cabdff1aSopenharmony_ci    if (!s->strip_sizes || !s->strip_offsets) {
366cabdff1aSopenharmony_ci        ret = AVERROR(ENOMEM);
367cabdff1aSopenharmony_ci        goto fail;
368cabdff1aSopenharmony_ci    }
369cabdff1aSopenharmony_ci
370cabdff1aSopenharmony_ci    if (is_yuv) {
371cabdff1aSopenharmony_ci        av_fast_padded_malloc(&s->yuv_line, &s->yuv_line_size, bytes_per_row);
372cabdff1aSopenharmony_ci        if (s->yuv_line == NULL) {
373cabdff1aSopenharmony_ci            av_log(s->avctx, AV_LOG_ERROR, "Not enough memory\n");
374cabdff1aSopenharmony_ci            ret = AVERROR(ENOMEM);
375cabdff1aSopenharmony_ci            goto fail;
376cabdff1aSopenharmony_ci        }
377cabdff1aSopenharmony_ci    }
378cabdff1aSopenharmony_ci
379cabdff1aSopenharmony_ci#if CONFIG_ZLIB
380cabdff1aSopenharmony_ci    if (s->compr == TIFF_DEFLATE || s->compr == TIFF_ADOBE_DEFLATE) {
381cabdff1aSopenharmony_ci        uint8_t *zbuf;
382cabdff1aSopenharmony_ci        int zlen, zn;
383cabdff1aSopenharmony_ci        int j;
384cabdff1aSopenharmony_ci
385cabdff1aSopenharmony_ci        zlen = bytes_per_row * s->rps;
386cabdff1aSopenharmony_ci        zbuf = av_malloc(zlen);
387cabdff1aSopenharmony_ci        if (!zbuf) {
388cabdff1aSopenharmony_ci            ret = AVERROR(ENOMEM);
389cabdff1aSopenharmony_ci            goto fail;
390cabdff1aSopenharmony_ci        }
391cabdff1aSopenharmony_ci        s->strip_offsets[0] = ptr - pkt->data;
392cabdff1aSopenharmony_ci        zn               = 0;
393cabdff1aSopenharmony_ci        for (j = 0; j < s->rps; j++) {
394cabdff1aSopenharmony_ci            if (is_yuv) {
395cabdff1aSopenharmony_ci                pack_yuv(s, p, s->yuv_line, j);
396cabdff1aSopenharmony_ci                memcpy(zbuf + zn, s->yuv_line, bytes_per_row);
397cabdff1aSopenharmony_ci                j += s->subsampling[1] - 1;
398cabdff1aSopenharmony_ci            } else
399cabdff1aSopenharmony_ci                memcpy(zbuf + j * bytes_per_row,
400cabdff1aSopenharmony_ci                       p->data[0] + j * p->linesize[0], bytes_per_row);
401cabdff1aSopenharmony_ci            zn += bytes_per_row;
402cabdff1aSopenharmony_ci        }
403cabdff1aSopenharmony_ci        ret = encode_strip(s, zbuf, ptr, zn, s->compr);
404cabdff1aSopenharmony_ci        av_free(zbuf);
405cabdff1aSopenharmony_ci        if (ret < 0) {
406cabdff1aSopenharmony_ci            av_log(s->avctx, AV_LOG_ERROR, "Encode strip failed\n");
407cabdff1aSopenharmony_ci            goto fail;
408cabdff1aSopenharmony_ci        }
409cabdff1aSopenharmony_ci        ptr           += ret;
410cabdff1aSopenharmony_ci        s->strip_sizes[0] = ptr - pkt->data - s->strip_offsets[0];
411cabdff1aSopenharmony_ci    } else
412cabdff1aSopenharmony_ci#endif
413cabdff1aSopenharmony_ci    {
414cabdff1aSopenharmony_ci    if (s->compr == TIFF_LZW) {
415cabdff1aSopenharmony_ci        s->lzws = av_malloc(ff_lzw_encode_state_size);
416cabdff1aSopenharmony_ci        if (!s->lzws) {
417cabdff1aSopenharmony_ci            ret = AVERROR(ENOMEM);
418cabdff1aSopenharmony_ci            goto fail;
419cabdff1aSopenharmony_ci        }
420cabdff1aSopenharmony_ci    }
421cabdff1aSopenharmony_ci    for (i = 0; i < s->height; i++) {
422cabdff1aSopenharmony_ci        if (s->strip_sizes[i / s->rps] == 0) {
423cabdff1aSopenharmony_ci            if (s->compr == TIFF_LZW) {
424cabdff1aSopenharmony_ci                ff_lzw_encode_init(s->lzws, ptr,
425cabdff1aSopenharmony_ci                                   s->buf_size - (*s->buf - s->buf_start),
426cabdff1aSopenharmony_ci                                   12, FF_LZW_TIFF, 0);
427cabdff1aSopenharmony_ci            }
428cabdff1aSopenharmony_ci            s->strip_offsets[i / s->rps] = ptr - pkt->data;
429cabdff1aSopenharmony_ci        }
430cabdff1aSopenharmony_ci        if (is_yuv) {
431cabdff1aSopenharmony_ci            pack_yuv(s, p, s->yuv_line, i);
432cabdff1aSopenharmony_ci            ret = encode_strip(s, s->yuv_line, ptr, bytes_per_row, s->compr);
433cabdff1aSopenharmony_ci            i  += s->subsampling[1] - 1;
434cabdff1aSopenharmony_ci        } else
435cabdff1aSopenharmony_ci            ret = encode_strip(s, p->data[0] + i * p->linesize[0],
436cabdff1aSopenharmony_ci                               ptr, bytes_per_row, s->compr);
437cabdff1aSopenharmony_ci        if (ret < 0) {
438cabdff1aSopenharmony_ci            av_log(s->avctx, AV_LOG_ERROR, "Encode strip failed\n");
439cabdff1aSopenharmony_ci            goto fail;
440cabdff1aSopenharmony_ci        }
441cabdff1aSopenharmony_ci        s->strip_sizes[i / s->rps] += ret;
442cabdff1aSopenharmony_ci        ptr                     += ret;
443cabdff1aSopenharmony_ci        if (s->compr == TIFF_LZW &&
444cabdff1aSopenharmony_ci            (i == s->height - 1 || i % s->rps == s->rps - 1)) {
445cabdff1aSopenharmony_ci            ret = ff_lzw_encode_flush(s->lzws);
446cabdff1aSopenharmony_ci            s->strip_sizes[(i / s->rps)] += ret;
447cabdff1aSopenharmony_ci            ptr                          += ret;
448cabdff1aSopenharmony_ci        }
449cabdff1aSopenharmony_ci    }
450cabdff1aSopenharmony_ci    if (s->compr == TIFF_LZW)
451cabdff1aSopenharmony_ci        av_freep(&s->lzws);
452cabdff1aSopenharmony_ci    }
453cabdff1aSopenharmony_ci
454cabdff1aSopenharmony_ci    s->num_entries = 0;
455cabdff1aSopenharmony_ci
456cabdff1aSopenharmony_ci    ADD_ENTRY1(s, TIFF_SUBFILE, TIFF_LONG, 0);
457cabdff1aSopenharmony_ci    ADD_ENTRY1(s, TIFF_WIDTH,   TIFF_LONG, s->width);
458cabdff1aSopenharmony_ci    ADD_ENTRY1(s, TIFF_HEIGHT,  TIFF_LONG, s->height);
459cabdff1aSopenharmony_ci
460cabdff1aSopenharmony_ci    if (s->bpp_tab_size)
461cabdff1aSopenharmony_ci        ADD_ENTRY(s, TIFF_BPP, TIFF_SHORT, s->bpp_tab_size, bpp_tab);
462cabdff1aSopenharmony_ci
463cabdff1aSopenharmony_ci    ADD_ENTRY1(s, TIFF_COMPR,       TIFF_SHORT, s->compr);
464cabdff1aSopenharmony_ci    ADD_ENTRY1(s, TIFF_PHOTOMETRIC, TIFF_SHORT, s->photometric_interpretation);
465cabdff1aSopenharmony_ci    ADD_ENTRY(s,  TIFF_STRIP_OFFS,  TIFF_LONG,  strips, s->strip_offsets);
466cabdff1aSopenharmony_ci
467cabdff1aSopenharmony_ci    if (s->bpp_tab_size)
468cabdff1aSopenharmony_ci        ADD_ENTRY1(s, TIFF_SAMPLES_PER_PIXEL, TIFF_SHORT, s->bpp_tab_size);
469cabdff1aSopenharmony_ci
470cabdff1aSopenharmony_ci    ADD_ENTRY1(s, TIFF_ROWSPERSTRIP, TIFF_LONG,     s->rps);
471cabdff1aSopenharmony_ci    ADD_ENTRY(s,  TIFF_STRIP_SIZE,   TIFF_LONG,     strips, s->strip_sizes);
472cabdff1aSopenharmony_ci    ADD_ENTRY(s,  TIFF_XRES,         TIFF_RATIONAL, 1,      res);
473cabdff1aSopenharmony_ci    if (avctx->sample_aspect_ratio.num > 0 &&
474cabdff1aSopenharmony_ci        avctx->sample_aspect_ratio.den > 0) {
475cabdff1aSopenharmony_ci        AVRational y = av_mul_q(av_make_q(s->dpi, 1),
476cabdff1aSopenharmony_ci                                avctx->sample_aspect_ratio);
477cabdff1aSopenharmony_ci        res[0] = y.num;
478cabdff1aSopenharmony_ci        res[1] = y.den;
479cabdff1aSopenharmony_ci    }
480cabdff1aSopenharmony_ci    ADD_ENTRY(s,  TIFF_YRES,         TIFF_RATIONAL, 1,      res);
481cabdff1aSopenharmony_ci    ADD_ENTRY1(s, TIFF_RES_UNIT,     TIFF_SHORT,    2);
482cabdff1aSopenharmony_ci
483cabdff1aSopenharmony_ci    if (!(avctx->flags & AV_CODEC_FLAG_BITEXACT))
484cabdff1aSopenharmony_ci        ADD_ENTRY(s, TIFF_SOFTWARE_NAME, TIFF_STRING,
485cabdff1aSopenharmony_ci                  strlen(LIBAVCODEC_IDENT) + 1, LIBAVCODEC_IDENT);
486cabdff1aSopenharmony_ci
487cabdff1aSopenharmony_ci    if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
488cabdff1aSopenharmony_ci        uint16_t pal[256 * 3];
489cabdff1aSopenharmony_ci        for (i = 0; i < 256; i++) {
490cabdff1aSopenharmony_ci            uint32_t rgb = *(uint32_t *) (p->data[1] + i * 4);
491cabdff1aSopenharmony_ci            pal[i]       = ((rgb >> 16) & 0xff) * 257;
492cabdff1aSopenharmony_ci            pal[i + 256] = ((rgb >>  8) & 0xff) * 257;
493cabdff1aSopenharmony_ci            pal[i + 512] =  (rgb        & 0xff) * 257;
494cabdff1aSopenharmony_ci        }
495cabdff1aSopenharmony_ci        ADD_ENTRY(s, TIFF_PAL, TIFF_SHORT, 256 * 3, pal);
496cabdff1aSopenharmony_ci    }
497cabdff1aSopenharmony_ci    if (alpha)
498cabdff1aSopenharmony_ci        ADD_ENTRY1(s,TIFF_EXTRASAMPLES,      TIFF_SHORT,            2);
499cabdff1aSopenharmony_ci    if (is_yuv) {
500cabdff1aSopenharmony_ci        /** according to CCIR Recommendation 601.1 */
501cabdff1aSopenharmony_ci        uint32_t refbw[12] = { 15, 1, 235, 1, 128, 1, 240, 1, 128, 1, 240, 1 };
502cabdff1aSopenharmony_ci        ADD_ENTRY(s, TIFF_YCBCR_SUBSAMPLING, TIFF_SHORT,    2, s->subsampling);
503cabdff1aSopenharmony_ci        if (avctx->chroma_sample_location == AVCHROMA_LOC_TOPLEFT)
504cabdff1aSopenharmony_ci            ADD_ENTRY1(s, TIFF_YCBCR_POSITIONING, TIFF_SHORT, 2);
505cabdff1aSopenharmony_ci        ADD_ENTRY(s, TIFF_REFERENCE_BW,      TIFF_RATIONAL, 6, refbw);
506cabdff1aSopenharmony_ci    }
507cabdff1aSopenharmony_ci    // write offset to dir
508cabdff1aSopenharmony_ci    bytestream_put_le32(&offset, ptr - pkt->data);
509cabdff1aSopenharmony_ci
510cabdff1aSopenharmony_ci    if (check_size(s, 6 + s->num_entries * 12)) {
511cabdff1aSopenharmony_ci        ret = AVERROR(EINVAL);
512cabdff1aSopenharmony_ci        goto fail;
513cabdff1aSopenharmony_ci    }
514cabdff1aSopenharmony_ci    bytestream_put_le16(&ptr, s->num_entries);  // write tag count
515cabdff1aSopenharmony_ci    bytestream_put_buffer(&ptr, s->entries, s->num_entries * 12);
516cabdff1aSopenharmony_ci    bytestream_put_le32(&ptr, 0);
517cabdff1aSopenharmony_ci
518cabdff1aSopenharmony_ci    pkt->size   = ptr - pkt->data;
519cabdff1aSopenharmony_ci    *got_packet = 1;
520cabdff1aSopenharmony_ci
521cabdff1aSopenharmony_cifail:
522cabdff1aSopenharmony_ci    return ret < 0 ? ret : 0;
523cabdff1aSopenharmony_ci}
524cabdff1aSopenharmony_ci
525cabdff1aSopenharmony_cistatic av_cold int encode_init(AVCodecContext *avctx)
526cabdff1aSopenharmony_ci{
527cabdff1aSopenharmony_ci    TiffEncoderContext *s = avctx->priv_data;
528cabdff1aSopenharmony_ci
529cabdff1aSopenharmony_ci#if !CONFIG_ZLIB
530cabdff1aSopenharmony_ci    if (s->compr == TIFF_DEFLATE) {
531cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
532cabdff1aSopenharmony_ci               "Deflate compression needs zlib compiled in\n");
533cabdff1aSopenharmony_ci        return AVERROR(ENOSYS);
534cabdff1aSopenharmony_ci    }
535cabdff1aSopenharmony_ci#endif
536cabdff1aSopenharmony_ci
537cabdff1aSopenharmony_ci    s->avctx = avctx;
538cabdff1aSopenharmony_ci
539cabdff1aSopenharmony_ci    return 0;
540cabdff1aSopenharmony_ci}
541cabdff1aSopenharmony_ci
542cabdff1aSopenharmony_cistatic av_cold int encode_close(AVCodecContext *avctx)
543cabdff1aSopenharmony_ci{
544cabdff1aSopenharmony_ci    TiffEncoderContext *s = avctx->priv_data;
545cabdff1aSopenharmony_ci
546cabdff1aSopenharmony_ci    av_freep(&s->strip_sizes);
547cabdff1aSopenharmony_ci    av_freep(&s->strip_offsets);
548cabdff1aSopenharmony_ci    av_freep(&s->yuv_line);
549cabdff1aSopenharmony_ci
550cabdff1aSopenharmony_ci    return 0;
551cabdff1aSopenharmony_ci}
552cabdff1aSopenharmony_ci
553cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(TiffEncoderContext, x)
554cabdff1aSopenharmony_ci#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
555cabdff1aSopenharmony_cistatic const AVOption options[] = {
556cabdff1aSopenharmony_ci    {"dpi", "set the image resolution (in dpi)", OFFSET(dpi), AV_OPT_TYPE_INT, {.i64 = 72}, 1, 0x10000, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_ENCODING_PARAM},
557cabdff1aSopenharmony_ci    { "compression_algo", NULL, OFFSET(compr), AV_OPT_TYPE_INT,   { .i64 = TIFF_PACKBITS }, TIFF_RAW, TIFF_DEFLATE, VE, "compression_algo" },
558cabdff1aSopenharmony_ci    { "packbits",         NULL, 0,             AV_OPT_TYPE_CONST, { .i64 = TIFF_PACKBITS }, 0,        0,            VE, "compression_algo" },
559cabdff1aSopenharmony_ci    { "raw",              NULL, 0,             AV_OPT_TYPE_CONST, { .i64 = TIFF_RAW      }, 0,        0,            VE, "compression_algo" },
560cabdff1aSopenharmony_ci    { "lzw",              NULL, 0,             AV_OPT_TYPE_CONST, { .i64 = TIFF_LZW      }, 0,        0,            VE, "compression_algo" },
561cabdff1aSopenharmony_ci    { "deflate",          NULL, 0,             AV_OPT_TYPE_CONST, { .i64 = TIFF_DEFLATE  }, 0,        0,            VE, "compression_algo" },
562cabdff1aSopenharmony_ci    { NULL },
563cabdff1aSopenharmony_ci};
564cabdff1aSopenharmony_ci
565cabdff1aSopenharmony_cistatic const AVClass tiffenc_class = {
566cabdff1aSopenharmony_ci    .class_name = "TIFF encoder",
567cabdff1aSopenharmony_ci    .item_name  = av_default_item_name,
568cabdff1aSopenharmony_ci    .option     = options,
569cabdff1aSopenharmony_ci    .version    = LIBAVUTIL_VERSION_INT,
570cabdff1aSopenharmony_ci};
571cabdff1aSopenharmony_ci
572cabdff1aSopenharmony_ciconst FFCodec ff_tiff_encoder = {
573cabdff1aSopenharmony_ci    .p.name         = "tiff",
574cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("TIFF image"),
575cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
576cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_TIFF,
577cabdff1aSopenharmony_ci    .priv_data_size = sizeof(TiffEncoderContext),
578cabdff1aSopenharmony_ci    .init           = encode_init,
579cabdff1aSopenharmony_ci    .close          = encode_close,
580cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_FRAME_THREADS,
581cabdff1aSopenharmony_ci    FF_CODEC_ENCODE_CB(encode_frame),
582cabdff1aSopenharmony_ci    .p.pix_fmts     = (const enum AVPixelFormat[]) {
583cabdff1aSopenharmony_ci        AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48LE, AV_PIX_FMT_PAL8,
584cabdff1aSopenharmony_ci        AV_PIX_FMT_RGBA, AV_PIX_FMT_RGBA64LE,
585cabdff1aSopenharmony_ci        AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_YA16LE,
586cabdff1aSopenharmony_ci        AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_MONOWHITE,
587cabdff1aSopenharmony_ci        AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
588cabdff1aSopenharmony_ci        AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
589cabdff1aSopenharmony_ci        AV_PIX_FMT_NONE
590cabdff1aSopenharmony_ci    },
591cabdff1aSopenharmony_ci    .p.priv_class   = &tiffenc_class,
592cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
593cabdff1aSopenharmony_ci};
594