*/
/**
- * TIFF image encoder
* @file
+ * TIFF image encoder
* @author Bartlomiej Wolowiec
*/
+
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+
#include "avcodec.h"
+#include "config.h"
#if CONFIG_ZLIB
#include <zlib.h>
#endif
};
typedef struct TiffEncoderContext {
+ AVClass *class; ///< for private options
AVCodecContext *avctx;
AVFrame picture;
* @param need Needed bytes
* @return 0 - ok, 1 - no free space
*/
-inline static int check_size(TiffEncoderContext * s, uint64_t need)
+static inline int check_size(TiffEncoderContext * s, uint64_t need)
{
if (s->buf_size < *s->buf - s->buf_start + need) {
*s->buf = s->buf_start + s->buf_size + 1;
}
}
-static int encode_frame(AVCodecContext * avctx, unsigned char *buf,
- int buf_size, void *data)
+static int encode_frame(AVCodecContext * avctx, AVPacket *pkt,
+ const AVFrame *pict, int *got_packet)
{
TiffEncoderContext *s = avctx->priv_data;
- AVFrame *pict = data;
- AVFrame *const p = (AVFrame *) & s->picture;
+ AVFrame *const p = &s->picture;
int i;
- int n;
- uint8_t *ptr = buf;
+ uint8_t *ptr;
uint8_t *offset;
uint32_t strips;
uint32_t *strip_sizes = NULL;
uint32_t *strip_offsets = NULL;
int bytes_per_row;
uint32_t res[2] = { 72, 1 }; // image resolution (72/1)
- static const uint16_t bpp_tab[] = { 8, 8, 8, 8 };
- int ret = -1;
+ uint16_t bpp_tab[] = { 8, 8, 8, 8 };
+ int ret;
int is_yuv = 0;
uint8_t *yuv_line = NULL;
int shift_h, shift_v;
+ const AVPixFmtDescriptor* pfd;
- s->buf_start = buf;
- s->buf = &ptr;
- s->buf_size = buf_size;
+ s->avctx = avctx;
*p = *pict;
- p->pict_type = FF_I_TYPE;
+ p->pict_type = AV_PICTURE_TYPE_I;
p->key_frame = 1;
avctx->coded_frame= &s->picture;
- s->compr = TIFF_PACKBITS;
- if (avctx->compression_level == 0) {
- s->compr = TIFF_RAW;
- } else if(avctx->compression_level == 2) {
- s->compr = TIFF_LZW;
-#if CONFIG_ZLIB
- } else if ((avctx->compression_level >= 3)) {
- s->compr = TIFF_DEFLATE;
-#endif
- }
-
s->width = avctx->width;
s->height = avctx->height;
s->subsampling[0] = 1;
s->subsampling[1] = 1;
switch (avctx->pix_fmt) {
- case PIX_FMT_RGB24:
- s->bpp = 24;
- s->photometric_interpretation = 2;
- break;
- case PIX_FMT_GRAY8:
- s->bpp = 8;
- s->photometric_interpretation = 1;
- break;
- case PIX_FMT_PAL8:
- s->bpp = 8;
- s->photometric_interpretation = 3;
+ case AV_PIX_FMT_RGB48LE:
+ case AV_PIX_FMT_GRAY16LE:
+ case AV_PIX_FMT_RGB24:
+ case AV_PIX_FMT_GRAY8:
+ case AV_PIX_FMT_PAL8:
+ pfd = av_pix_fmt_desc_get(avctx->pix_fmt);
+ s->bpp = av_get_bits_per_pixel(pfd);
+ if (pfd->flags & PIX_FMT_PAL) {
+ s->photometric_interpretation = 3;
+ } else if (pfd->flags & PIX_FMT_RGB) {
+ s->photometric_interpretation = 2;
+ } else {
+ s->photometric_interpretation = 1;
+ }
+ s->bpp_tab_size = pfd->nb_components;
+ for (i = 0; i < s->bpp_tab_size; i++) {
+ bpp_tab[i] = s->bpp / s->bpp_tab_size;
+ }
break;
- case PIX_FMT_MONOBLACK:
+ case AV_PIX_FMT_MONOBLACK:
s->bpp = 1;
s->photometric_interpretation = 1;
+ s->bpp_tab_size = 0;
break;
- case PIX_FMT_MONOWHITE:
+ case AV_PIX_FMT_MONOWHITE:
s->bpp = 1;
s->photometric_interpretation = 0;
+ s->bpp_tab_size = 0;
break;
- case PIX_FMT_YUV420P:
- case PIX_FMT_YUV422P:
- case PIX_FMT_YUV444P:
- case PIX_FMT_YUV410P:
- case PIX_FMT_YUV411P:
+ case AV_PIX_FMT_YUV420P:
+ case AV_PIX_FMT_YUV422P:
+ case AV_PIX_FMT_YUV444P:
+ case AV_PIX_FMT_YUV410P:
+ case AV_PIX_FMT_YUV411P:
s->photometric_interpretation = 6;
- avcodec_get_chroma_sub_sample(avctx->pix_fmt,
- &shift_h, &shift_v);
+ av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt,
+ &shift_h, &shift_v);
s->bpp = 8 + (16 >> (shift_h + shift_v));
s->subsampling[0] = 1 << shift_h;
s->subsampling[1] = 1 << shift_v;
"This colors format is not supported\n");
return -1;
}
- if (!is_yuv)
- s->bpp_tab_size = (s->bpp >> 3);
if (s->compr == TIFF_DEFLATE || s->compr == TIFF_ADOBE_DEFLATE || s->compr == TIFF_LZW)
//best choose for DEFLATE
strips = (s->height - 1) / s->rps + 1;
+ if (!pkt->data &&
+ (ret = av_new_packet(pkt, avctx->width * avctx->height * s->bpp * 2 +
+ avctx->height * 4 + FF_MIN_BUFFER_SIZE)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
+ return ret;
+ }
+ ptr = pkt->data;
+ s->buf_start = pkt->data;
+ s->buf = &ptr;
+ s->buf_size = pkt->size;
+
if (check_size(s, 8))
goto fail;
strip_sizes = av_mallocz(sizeof(*strip_sizes) * strips);
strip_offsets = av_mallocz(sizeof(*strip_offsets) * strips);
+ if (!strip_sizes || !strip_offsets) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
bytes_per_row = (((s->width - 1)/s->subsampling[0] + 1) * s->bpp
* s->subsampling[0] * s->subsampling[1] + 7) >> 3;
yuv_line = av_malloc(bytes_per_row);
if (yuv_line == NULL){
av_log(s->avctx, AV_LOG_ERROR, "Not enough memory\n");
+ ret = AVERROR(ENOMEM);
goto fail;
}
}
zlen = bytes_per_row * s->rps;
zbuf = av_malloc(zlen);
- strip_offsets[0] = ptr - buf;
+ if (!zbuf) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ strip_offsets[0] = ptr - pkt->data;
zn = 0;
for (j = 0; j < s->rps; j++) {
if (is_yuv){
p->data[0] + j * p->linesize[0], bytes_per_row);
zn += bytes_per_row;
}
- n = encode_strip(s, zbuf, ptr, zn, s->compr);
+ ret = encode_strip(s, zbuf, ptr, zn, s->compr);
av_free(zbuf);
- if (n<0) {
+ if (ret < 0) {
av_log(s->avctx, AV_LOG_ERROR, "Encode strip failed\n");
goto fail;
}
- ptr += n;
- strip_sizes[0] = ptr - buf - strip_offsets[0];
+ ptr += ret;
+ strip_sizes[0] = ptr - pkt->data - strip_offsets[0];
} else
#endif
{
- if(s->compr == TIFF_LZW)
+ if (s->compr == TIFF_LZW) {
s->lzws = av_malloc(ff_lzw_encode_state_size);
+ if (!s->lzws) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ }
for (i = 0; i < s->height; i++) {
if (strip_sizes[i / s->rps] == 0) {
if(s->compr == TIFF_LZW){
ff_lzw_encode_init(s->lzws, ptr, s->buf_size - (*s->buf - s->buf_start),
12, FF_LZW_TIFF, put_bits);
}
- strip_offsets[i / s->rps] = ptr - buf;
+ strip_offsets[i / s->rps] = ptr - pkt->data;
}
if (is_yuv){
pack_yuv(s, yuv_line, i);
- n = encode_strip(s, yuv_line, ptr, bytes_per_row, s->compr);
+ ret = encode_strip(s, yuv_line, ptr, bytes_per_row, s->compr);
i += s->subsampling[1] - 1;
}
else
- n = encode_strip(s, p->data[0] + i * p->linesize[0],
+ ret = encode_strip(s, p->data[0] + i * p->linesize[0],
ptr, bytes_per_row, s->compr);
- if (n < 0) {
+ if (ret < 0) {
av_log(s->avctx, AV_LOG_ERROR, "Encode strip failed\n");
goto fail;
}
- strip_sizes[i / s->rps] += n;
- ptr += n;
+ strip_sizes[i / s->rps] += ret;
+ ptr += ret;
if(s->compr == TIFF_LZW && (i==s->height-1 || i%s->rps == s->rps-1)){
- int ret;
ret = ff_lzw_encode_flush(s->lzws, flush_put_bits);
strip_sizes[(i / s->rps )] += ret ;
ptr += ret;
add_entry(s, TIFF_SOFTWARE_NAME, TIFF_STRING,
strlen(LIBAVCODEC_IDENT) + 1, LIBAVCODEC_IDENT);
- if (avctx->pix_fmt == PIX_FMT_PAL8) {
+ if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
uint16_t pal[256 * 3];
for (i = 0; i < 256; i++) {
uint32_t rgb = *(uint32_t *) (p->data[1] + i * 4);
add_entry(s, TIFF_YCBCR_SUBSAMPLING, TIFF_SHORT, 2, s->subsampling);
add_entry(s, TIFF_REFERENCE_BW, TIFF_RATIONAL, 6, refbw);
}
- bytestream_put_le32(&offset, ptr - buf); // write offset to dir
+ bytestream_put_le32(&offset, ptr - pkt->data); // write offset to dir
- if (check_size(s, 6 + s->num_entries * 12))
+ if (check_size(s, 6 + s->num_entries * 12)) {
+ ret = AVERROR(EINVAL);
goto fail;
+ }
bytestream_put_le16(&ptr, s->num_entries); // write tag count
bytestream_put_buffer(&ptr, s->entries, s->num_entries * 12);
bytestream_put_le32(&ptr, 0);
- ret = ptr - buf;
+ pkt->size = ptr - pkt->data;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
fail:
av_free(strip_sizes);
return ret;
}
+#define OFFSET(x) offsetof(TiffEncoderContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "compression_algo", NULL, OFFSET(compr), AV_OPT_TYPE_INT, {.i64 = TIFF_PACKBITS}, TIFF_RAW, TIFF_DEFLATE, VE, "compression_algo" },
+ { "packbits", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = TIFF_PACKBITS}, 0, 0, VE, "compression_algo" },
+ { "raw", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = TIFF_RAW}, 0, 0, VE, "compression_algo" },
+ { "lzw", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = TIFF_LZW}, 0, 0, VE, "compression_algo" },
+#if CONFIG_ZLIB
+ { "deflate", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = TIFF_DEFLATE}, 0, 0, VE, "compression_algo" },
+#endif
+ { NULL },
+};
+
+static const AVClass tiffenc_class = {
+ .class_name = "TIFF encoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_tiff_encoder = {
- "tiff",
- AVMEDIA_TYPE_VIDEO,
- CODEC_ID_TIFF,
- sizeof(TiffEncoderContext),
- NULL,
- encode_frame,
- NULL,
- NULL,
- 0,
- NULL,
- .pix_fmts =
- (const enum PixelFormat[]) {PIX_FMT_RGB24, PIX_FMT_PAL8, PIX_FMT_GRAY8,
- PIX_FMT_MONOBLACK, PIX_FMT_MONOWHITE,
- PIX_FMT_YUV420P, PIX_FMT_YUV422P,
- PIX_FMT_YUV444P, PIX_FMT_YUV410P,
- PIX_FMT_YUV411P,
- PIX_FMT_NONE},
- .long_name = NULL_IF_CONFIG_SMALL("TIFF image"),
+ .name = "tiff",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_TIFF,
+ .priv_data_size = sizeof(TiffEncoderContext),
+ .encode2 = encode_frame,
+ .pix_fmts = (const enum AVPixelFormat[]) {
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48LE, AV_PIX_FMT_PAL8,
+ AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16LE,
+ AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_MONOWHITE,
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_NONE
+ },
+ .long_name = NULL_IF_CONFIG_SMALL("TIFF image"),
+ .priv_class = &tiffenc_class,
};