[Ffmpeg-devel] [PATCH] TIFF encoder (Google SoC qualification task)
Kamil Nowosad
k.nowosad
Thu Mar 29 11:55:30 CEST 2007
On Thu, Mar 29, 2007 at 01:39:17AM +0200, Michael Niedermayer wrote:
> Hi
>
> are you going to send a second revission of your tiff encoder patch, which
> takes care of the review comments?
> or did you decide to work on some other task?
Hi,
Yes, I do. I have made some changes, according to the comments. However, I have planned to submit more extended version (this week I have two big tests on my studies, and it was impossible for me to do more, but I have planned to start work on Saturday (the whole time from Sat. until the deadline is free for me, so I can do my best :-) )) and then make the final fixes, after the review. I have forgotten what you have written in the "Patch review process" section in the documentation, sorry.
I have attached the patch. The next steps, according to the reviews,
are:
- YUV support
- support for horizontal predictor (and maybe LZW compression)
- support for JPEG compression
- optional choice of the best compression algorithm for every image
- maybe some others ;-)
You have written that new files (like tiff.h) have to be diffed against
the parent file. Do you mean doing svn copy tiff.c tiff.h insted of svn
add tiff.h ?
--
Pozdrawiam!
Kamil Nowosad
#gg: 1611683
-------------- next part --------------
Index: libavcodec/allcodecs.c
===================================================================
--- libavcodec/allcodecs.c (wersja 8542)
+++ libavcodec/allcodecs.c (kopia robocza)
@@ -131,7 +131,7 @@
REGISTER_ENCDEC (TARGA, targa);
REGISTER_DECODER(THEORA, theora);
REGISTER_DECODER(TIERTEXSEQVIDEO, tiertexseqvideo);
- REGISTER_DECODER(TIFF, tiff);
+ REGISTER_ENCDEC (TIFF, tiff);
REGISTER_DECODER(TRUEMOTION1, truemotion1);
REGISTER_DECODER(TRUEMOTION2, truemotion2);
REGISTER_DECODER(TSCC, tscc);
Index: libavcodec/utils.c
===================================================================
--- libavcodec/utils.c (wersja 8542)
+++ libavcodec/utils.c (kopia robocza)
@@ -636,6 +636,9 @@
{"coder", NULL, OFFSET(coder_type), FF_OPT_TYPE_INT, DEFAULT, INT_MIN, INT_MAX, V|E, "coder"},
{"vlc", "variable length coder / huffman coder", 0, FF_OPT_TYPE_CONST, FF_CODER_TYPE_VLC, INT_MIN, INT_MAX, V|E, "coder"},
{"ac", "arithmetic coder", 0, FF_OPT_TYPE_CONST, FF_CODER_TYPE_AC, INT_MIN, INT_MAX, V|E, "coder"},
+{"raw", "raw (no encoding)", 0, FF_OPT_TYPE_CONST, FF_CODER_TYPE_RAW, INT_MIN, INT_MAX, V|E, "coder"},
+{"rle", "run-lenghth coder", 0, FF_OPT_TYPE_CONST, FF_CODER_TYPE_RL, INT_MIN, INT_MAX, V|E, "coder"},
+{"def", "deflate", 0, FF_OPT_TYPE_CONST, FF_CODER_TYPE_DEFLATE, INT_MIN, INT_MAX, V|E, "coder"},
{"context", "context model", OFFSET(context_model), FF_OPT_TYPE_INT, DEFAULT, INT_MIN, INT_MAX, V|E},
{"slice_flags", NULL, OFFSET(slice_flags), FF_OPT_TYPE_INT, DEFAULT, INT_MIN, INT_MAX},
{"xvmc_acceleration", NULL, OFFSET(xvmc_acceleration), FF_OPT_TYPE_INT, DEFAULT, INT_MIN, INT_MAX},
Index: libavcodec/Makefile
===================================================================
--- libavcodec/Makefile (wersja 8542)
+++ libavcodec/Makefile (kopia robocza)
@@ -144,6 +144,7 @@
OBJS-$(CONFIG_THEORA_DECODER) += vp3.o xiph.o
OBJS-$(CONFIG_TIERTEXSEQVIDEO_DECODER) += tiertexseqv.o
OBJS-$(CONFIG_TIFF_DECODER) += tiff.o lzw.o
+OBJS-$(CONFIG_TIFF_ENCODER) += tiffenc.o
OBJS-$(CONFIG_TRUEMOTION1_DECODER) += truemotion1.o
OBJS-$(CONFIG_TRUEMOTION2_DECODER) += truemotion2.o
OBJS-$(CONFIG_TRUESPEECH_DECODER) += truespeech.o
Index: libavcodec/avcodec.h
===================================================================
--- libavcodec/avcodec.h (wersja 8542)
+++ libavcodec/avcodec.h (kopia robocza)
@@ -1565,8 +1565,11 @@
*/
int global_quality;
-#define FF_CODER_TYPE_VLC 0
-#define FF_CODER_TYPE_AC 1
+#define FF_CODER_TYPE_VLC 0
+#define FF_CODER_TYPE_AC 1
+#define FF_CODER_TYPE_RAW 2 // no coder
+#define FF_CODER_TYPE_RL 3 // run-length
+#define FF_CODER_TYPE_DEFLATE 4
/**
* coder type
* - encoding: set by user.
@@ -2221,6 +2224,7 @@
extern AVCodec sonic_ls_encoder;
extern AVCodec svq1_encoder;
extern AVCodec targa_encoder;
+extern AVCodec tiff_encoder;
extern AVCodec vcr1_encoder;
extern AVCodec vorbis_encoder;
extern AVCodec wmav1_encoder;
Index: libavcodec/tiff.c
===================================================================
--- libavcodec/tiff.c (wersja 8542)
+++ libavcodec/tiff.c (kopia robocza)
@@ -20,54 +20,12 @@
*
*/
#include "avcodec.h"
+#include "tiff.h"
#ifdef CONFIG_ZLIB
#include <zlib.h>
#endif
#include "lzw.h"
-/* abridged list of TIFF tags */
-enum TiffTags{
- TIFF_WIDTH = 0x100,
- TIFF_HEIGHT,
- TIFF_BPP,
- TIFF_COMPR,
- TIFF_INVERT = 0x106,
- TIFF_STRIP_OFFS = 0x111,
- TIFF_ROWSPERSTRIP = 0x116,
- TIFF_STRIP_SIZE,
- TIFF_PLANAR = 0x11C,
- TIFF_XPOS = 0x11E,
- TIFF_YPOS = 0x11F,
- TIFF_PREDICTOR = 0x13D,
- TIFF_PAL = 0x140
-};
-
-enum TiffCompr{
- TIFF_RAW = 1,
- TIFF_CCITT_RLE,
- TIFF_G3,
- TIFF_G4,
- TIFF_LZW,
- TIFF_JPEG,
- TIFF_NEWJPEG,
- TIFF_ADOBE_DEFLATE,
- TIFF_PACKBITS = 0x8005,
- TIFF_DEFLATE = 0x80B2
-};
-
-enum TiffTypes{
- TIFF_BYTE = 1,
- TIFF_STRING,
- TIFF_SHORT,
- TIFF_LONG,
- TIFF_LONGLONG
-};
-
-/** sizes of various TIFF field types */
-static const int type_sizes[6] = {
- 0, 1, 100, 2, 4, 8
-};
-
typedef struct TiffContext {
AVCodecContext *avctx;
AVFrame picture;
Index: libavcodec/tiff.h
===================================================================
--- libavcodec/tiff.h (wersja 0)
+++ libavcodec/tiff.h (wersja 0)
@@ -0,0 +1,74 @@
+/*
+ * TIFF image encoder/decoder
+ * Copyright (c) 2006 Konstantin Shishkov
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef TIFF_H
+#define TIFF_H
+
+/* abridged list of TIFF tags */
+enum TiffTags{
+ TIFF_WIDTH = 0x100,
+ TIFF_HEIGHT,
+ TIFF_BPP,
+ TIFF_COMPR,
+ TIFF_INVERT = 0x106,
+ TIFF_STRIP_OFFS = 0x111,
+ TIFF_SAMPLESPERPIX = 0x115,
+ TIFF_ROWSPERSTRIP,
+ TIFF_STRIP_SIZE,
+ TIFF_PLANAR = 0x11C,
+ TIFF_XRES = 0x11A,
+ TIFF_YRES = 0x11B,
+ TIFF_XPOS = 0x11E,
+ TIFF_YPOS = 0x11F,
+ TIFF_RES_UNIT = 0x128,
+ TIFF_PREDICTOR = 0x13D,
+ TIFF_PAL = 0x140
+};
+
+/* list of TIFF compression types */
+enum TiffCompr{
+ TIFF_RAW = 1,
+ TIFF_CCITT_RLE,
+ TIFF_G3,
+ TIFF_G4,
+ TIFF_LZW,
+ TIFF_JPEG,
+ TIFF_NEWJPEG,
+ TIFF_ADOBE_DEFLATE,
+ TIFF_PACKBITS = 0x8005,
+ TIFF_DEFLATE = 0x80B2
+};
+
+enum TiffTypes{
+ TIFF_BYTE = 1,
+ TIFF_STRING,
+ TIFF_SHORT,
+ TIFF_LONG,
+ TIFF_LONGLONG
+};
+
+/** sizes of various TIFF field types */
+static const int type_sizes[6] = {
+ 0, 1, 100, 2, 4, 8
+};
+#endif // TIFF_H
Index: libavcodec/tiffenc.c
===================================================================
--- libavcodec/tiffenc.c (wersja 0)
+++ libavcodec/tiffenc.c (wersja 0)
@@ -0,0 +1,617 @@
+/*
+ * TIFF image encoder
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/**
+ * TIFF format encoder
+ * @file tiffenc.c
+ * @author Kamil Nowosad
+ */
+#include "avcodec.h"
+#include "bytestream.h"
+#include "tiff.h"
+#ifdef CONFIG_ZLIB
+#include <zlib.h>
+#endif
+
+#define CURR_OFFSET(s) (s->buf - s->buf_start + s->offset)
+
+typedef struct TiffIfdEntry {
+ uint16_t tag;
+ uint16_t type;
+ uint32_t count;
+ uint32_t value; /// value or offset
+} TiffIfdEntry;
+
+typedef struct TiffEncoderContext {
+ enum TiffCompr compression;
+ uint8_t *buf, *buf_start, *buf_end, *entry_point;
+
+ /// the offset in stream at the beginning
+ int offset;
+
+ int strip,
+ num_of_strips,
+ lines_per_strip,
+ *strip_offset,
+ *strip_size;
+
+ int has_color_map;
+ uint16_t *color_map;
+
+ AVFrame *p;
+
+ TiffIfdEntry *ifd_entries;
+ /// size of ifd_entries buffer
+ int num_ifd_entries, max_ifd_entries;
+
+ int bpp,
+ bytes_per_line,
+ /// the number of samples
+ nsamples;
+
+ uint16_t bpp_info[4];
+
+ int photometric_interpretation;
+
+ int write_trailer;
+} TiffEncoderContext;
+
+
+#ifdef CONFIG_ZLIB
+const enum TiffCompr tiff_default_compression = TIFF_DEFLATE;
+#else
+const enum TiffCompr tiff_default_compression = TIFF_PACKBITS;
+#endif
+
+static int value_size(uint16_t type, uint32_t count, uint8_t * value)
+{
+ switch (type) {
+ case TIFF_BYTE:
+ return count;
+ case TIFF_SHORT:
+ return 2 * count;
+ case TIFF_LONG:
+ return 4 * count;
+ case TIFF_LONGLONG:
+ return 8 * count;
+ case TIFF_STRING:
+ return strlen(value) + 1;
+ }
+ return 0; // never reached
+}
+
+/**
+ * adds an entry to the IFD (referenced by a pointer)
+ */
+static int tiff_add_ifd_entryp(AVCodecContext * avctx, uint16_t tag,
+ uint16_t type, uint32_t count,
+ uint8_t * value)
+{
+ TiffEncoderContext *s = avctx->priv_data;
+ int size = value_size(type, count, value);
+ TiffIfdEntry *entr;
+
+ if (s->num_ifd_entries == s->max_ifd_entries) { // time to enlarge the buffer
+ s->max_ifd_entries *= 2;
+ s->ifd_entries =
+ av_realloc(s->ifd_entries,
+ s->max_ifd_entries * sizeof(TiffIfdEntry));
+ if (s->ifd_entries == NULL) {
+ av_log(avctx, AV_LOG_ERROR, "not enough memory\n");
+ return -1;
+ }
+ }
+
+ entr = s->ifd_entries + s->num_ifd_entries;
+ entr->tag = tag;
+ entr->type = type;
+ entr->count = count;
+ if (size > 4) {
+ if (s->buf + size >= s->buf_end){
+ av_log(avctx, AV_LOG_ERROR, "the buffer given is too short\n");
+ return -1;
+ }
+ entr->value = CURR_OFFSET(s);
+ memcpy(s->buf, value, size);
+ s->buf += size;
+ } else {
+ entr->value = 0;
+ memcpy((uint8_t *) & entr->value, value, size);
+ }
+ s->num_ifd_entries++;
+ return 0;
+}
+/**
+ * adds an entry to the IFD (referenced by a value)
+ * [it is helpful when passing constants]
+ */
+static int tiff_add_ifd_entryv(AVCodecContext * avctx, uint16_t tag,
+ uint16_t type, uint32_t count,
+ uint32_t value)
+{
+ if (type == TIFF_BYTE) {
+ uint8_t x = value;
+ return tiff_add_ifd_entryp(avctx, tag, type, count, &x);
+ } else if (type == TIFF_SHORT) {
+ uint16_t x = value;
+ return tiff_add_ifd_entryp(avctx, tag, type, count, &x);
+ } else if (type == TIFF_LONG) {
+ uint32_t x = value;
+ return tiff_add_ifd_entryp(avctx, tag, type, count, &x);
+ }
+ return -1;
+}
+/**
+ * writes the whole ifd to stream
+ */
+static int tiff_write_ifd(AVCodecContext * avctx)
+{
+ TiffEncoderContext *s = avctx->priv_data;
+ TiffIfdEntry *entr = s->ifd_entries;
+ int entry;
+
+ /* image file directory starts here: */
+ bytestream_put_le32(&s->entry_point, CURR_OFFSET(s));
+
+ if (s->buf + s->num_ifd_entries * 12 + 2 + 4 >= s->buf_end){
+ av_log(avctx, AV_LOG_ERROR, "the buffer given is too short\n");
+ return -1;
+ }
+
+ /* the number of IFD entries */
+ bytestream_put_le16(&s->buf, s->num_ifd_entries);
+ for (entry = 0; entry < s->num_ifd_entries; entry++, entr++) {
+ bytestream_put_le16(&s->buf, entr->tag);
+ bytestream_put_le16(&s->buf, entr->type);
+ bytestream_put_le32(&s->buf, entr->count);
+ bytestream_put_le32(&s->buf, entr->value);
+ }
+ return 0;
+}
+
+/**
+ * packbits compression implementation
+ */
+static int tiff_pack_bits(uint8_t * dst, int *dst_len, uint8_t * src,
+ int src_len)
+{
+ uint8_t *dst_begin = dst, *last_literal, special_case_ch;
+ enum { START, RUN, LITERAL, SPECIAL } last;
+ last = START;
+ while (src_len > 0) {
+ uint8_t *sp;
+ int num = 1;
+
+ for (sp = src + 1, src_len--; (*sp == *src) && (src_len > 0);
+ src++, src_len--)
+ num++;
+
+ if (dst - dst_begin + (num + 127) / 128 + 2 >= *dst_len) // check if has enough space
+ return -1;
+
+
+#define CHECK_AND_ADD(x, expr){ \
+ if ((expr) || *last_literal == 127){\
+ *dst = -1;\
+ last_literal = dst++;\
+ }\
+ (*last_literal)++;\
+ *dst++ = x;\
+ }
+ if (num == 1) {
+ if (last == SPECIAL) {
+ CHECK_AND_ADD(special_case_ch, 0);
+ CHECK_AND_ADD(special_case_ch, 0);
+ CHECK_AND_ADD(*sp, 0);
+ } else
+ CHECK_AND_ADD(*sp, last != LITERAL);
+ last = LITERAL;
+ } else if (num == 2) {
+ switch (last) {
+ case LITERAL:
+ special_case_ch = *sp;
+ last = SPECIAL;
+ break;
+ case SPECIAL:
+ CHECK_AND_ADD(special_case_ch, 0);
+ CHECK_AND_ADD(special_case_ch, 0);
+ special_case_ch = *sp;
+ default:
+ *dst++ = -1;
+ *dst++ = *sp;
+ last = RUN;
+ }
+ } else {
+ if (last == SPECIAL) {
+ *dst++ = -1;
+ *dst++ = special_case_ch;
+ }
+ while (num > 0) {
+ *dst++ = (uint8_t) (-FFMIN(num, 128) + 1);
+ *dst++ = *sp;
+ num -= 128;
+ }
+ last = RUN;
+ }
+ }
+ if (last == SPECIAL) {
+ if (*last_literal < 126) {
+ *last_literal += 2;
+ *dst++ = special_case_ch;
+ *dst++ = special_case_ch;
+ } else {
+ *dst++ = -1;
+ *dst++ = special_case_ch;
+ }
+ }
+#undef CHECK_AND_ADD
+ *dst_len = dst - dst_begin;
+ return 0;
+}
+
+static int tiff_prepare_color_map(AVCodecContext * avctx)
+{
+ TiffEncoderContext *s = avctx->priv_data;
+ AVFrame *p = s->p;
+ int i;
+ uint32_t *src = p->data[1];
+
+ s->color_map = av_malloc((1 << s->bpp) * 3 * sizeof(uint16_t));
+ if (s->color_map == NULL) {
+ av_log(avctx, AV_LOG_ERROR, "not enough memory\n");
+ return -1;
+ }
+
+ for (i = 0; i < (1 << s->bpp); i++) {
+ uint32_t sample = *src;
+ s->color_map[2 * (1 << s->bpp) + i] = (sample & 255) << 8; // B
+ sample = sample >> 8;
+ s->color_map[(1 << s->bpp) + i] = (sample & 255) << 8; // G
+ sample = sample >> 8;
+ s->color_map[i] = (sample & 255) << 8; // R
+ src++;
+ }
+ return 0;
+}
+
+static int tiff_write_image_data(AVCodecContext * avctx)
+{
+ TiffEncoderContext *s = avctx->priv_data;
+ AVFrame *p = s->p;
+ int i, y, len;
+#ifdef CONFIG_ZLIB
+ uint8_t *zbuf_start, *zbuf;
+ uLongf zlen;
+#endif
+
+ /* set the compression */
+ switch (avctx->coder_type) {
+ case 0: // XXX: when a user chose vlc it also assigns the default
+ s->compression = tiff_default_compression;
+ break;
+ case FF_CODER_TYPE_RAW:
+ s->compression = TIFF_RAW;
+ break;
+ case FF_CODER_TYPE_RL:
+ s->compression = TIFF_PACKBITS;
+ break;
+ case FF_CODER_TYPE_DEFLATE:
+#ifdef CONFIG_ZLIB
+ s->compression = TIFF_DEFLATE;
+ break;
+#else
+ av_log(avctx, AV_LOG_ERROR,
+ "Couldn't use deflate - ZLib not compiled in\n");
+ return -1;
+#endif
+ default:
+ av_log(avctx, AV_LOG_ERROR,
+ "Chosen compression type not supported\n");
+ return -1;
+ }
+
+ /* compute the number of strips */
+ if (avctx->width == 0 || avctx->height == 0) {
+ av_log(avctx, AV_LOG_ERROR, "invalid image size\n");
+ return -1;
+ } else if (s->compression == TIFF_DEFLATE) {
+ s->lines_per_strip = avctx->height;
+ s->num_of_strips = 1;
+ } else {
+ s->lines_per_strip = (8192 + s->bytes_per_line - 1) / (s->bytes_per_line); // =ceil(height/num_of_strips)
+ s->num_of_strips =
+ (avctx->height + s->lines_per_strip - 1) / s->lines_per_strip;
+ }
+
+ /* write the image data */
+ s->strip_offset = av_malloc((s->num_of_strips + 1) * sizeof(int));
+ s->strip_size = av_malloc((s->num_of_strips + 1) * sizeof(int));
+ if (s->strip_offset == NULL || s->strip_size == NULL) {
+ av_log(avctx, AV_LOG_ERROR, "not enough memory\n");
+ return -1;
+ }
+ s->strip = 0;
+ switch (s->compression) {
+ case TIFF_RAW:
+ if (s->buf + avctx->height * s->bytes_per_line >= s->buf_end){
+ av_log(avctx, AV_LOG_ERROR, "the buffer given is too short\n");
+ return -1;
+ }
+ for (y = 0; y < avctx->height; y += s->lines_per_strip) {
+ uint8_t *src;
+ int i;
+
+ s->strip_offset[s->strip++] = CURR_OFFSET(s);
+ for (i = 0;
+ (i < s->lines_per_strip) && (y + i < avctx->height);
+ i++) {
+ src = p->data[0] + (y + i) * p->linesize[0];
+ memcpy(s->buf, src, s->bytes_per_line);
+ s->buf += s->bytes_per_line;
+ }
+ }
+ break;
+ case TIFF_PACKBITS:
+ for (y = 0; y < avctx->height; y += s->lines_per_strip) {
+ uint8_t *src;
+ int i;
+
+ s->strip_offset[s->strip++] = CURR_OFFSET(s);
+ for (i = 0;
+ (i < s->lines_per_strip) && (y + i < avctx->height);
+ i++) {
+ int plen = s->buf_end - s->buf;
+ src = p->data[0] + (y + i) * p->linesize[0];
+ if (tiff_pack_bits(s->buf, &plen, src, s->bytes_per_line)
+ == -1) {
+ av_log(avctx, AV_LOG_ERROR,
+ "packbits compression error\n");
+ return -1;
+ }
+ s->buf += plen;
+ }
+ }
+ s->strip_offset[s->strip] = CURR_OFFSET(s);
+ break;
+#ifdef CONFIG_ZLIB
+ case TIFF_DEFLATE:
+ zbuf_start = zbuf =
+ av_malloc(s->bytes_per_line * s->lines_per_strip);
+ if (zbuf == NULL) {
+ av_log(avctx, AV_LOG_ERROR, "not enough memory\n");
+ return -1;
+ }
+ for (y = 0; y < avctx->height; y++) {
+ uint8_t *src;
+ src = p->data[0] + y * p->linesize[0];
+ memcpy(zbuf, src, s->bytes_per_line);
+ zbuf += s->bytes_per_line;
+ }
+ s->strip_offset[0] = CURR_OFFSET(s);
+ zlen = s->buf_end - s->buf;
+ if (compress(s->buf, &zlen, zbuf_start, zbuf - zbuf_start) != Z_OK) {
+ av_log(avctx, AV_LOG_ERROR, "ZLib compression error\n");
+ av_free(zbuf_start);
+ return -1;
+ }
+ s->buf += zlen;
+ s->strip = 1; // just one strip for better compression
+ av_free(zbuf_start);
+ break;
+#endif
+ }
+ s->strip_offset[s->strip] = CURR_OFFSET(s);
+
+ /* compute strip sizes */
+ for (i = 0; i < s->strip; i++)
+ s->strip_size[i] = s->strip_offset[i + 1] - s->strip_offset[i];
+
+ return 0;
+}
+
+/**
+ * encoding scheme:
+ * @li [if the client has not set it] TIFF signature
+ * @li offset of the IFD
+ * @li image data [divided into strips]
+ * @li IFD data which doesn't fit inside the IFD
+ * @li IFD, sorted by tag
+ * @li [if the client will not set it] 32 zero bits
+ */
+static int tiff_encode_frame(AVCodecContext * avctx, unsigned char *buf,
+ int buf_size, void *data)
+{
+ TiffEncoderContext *s = avctx->priv_data;
+ const uint8_t header[4] = {0x49, 0x49, 42, 0},
+ trailer[4] = {0, 0, 0, 0};
+ uint32_t xres[2] = {72, 1},
+ yres[2] = {72, 1};
+ int ret;
+
+ s->buf_start = s->buf = buf;
+ s->buf_end = s->buf + buf_size;
+ s->p = data;
+
+ if (avctx->frame_number == 0) {
+ /* do we have to write the header? (the TIFF muxer does it
+ * for us - it is useful when creating TIFFs with multiple images in one file) */
+ if (!avctx->extradata_size) { // i'm sure that there exists a nicer solution - maybe adding flags?
+ memcpy(s->buf, header, 4);
+ s->buf += 4;
+ s->offset = 0;
+ s->write_trailer = 1;
+ } else
+ s->offset = *(int *) avctx->extradata;
+ }
+
+ switch (avctx->pix_fmt) {
+ case PIX_FMT_PAL8:
+ s->bpp_info[0] = 8;
+ s->nsamples = 1;
+ s->bpp = 8;
+ s->photometric_interpretation = 3;
+ s->has_color_map = 1;
+ break;
+ case PIX_FMT_RGB24:
+ s->bpp_info[0] = 8;
+ s->bpp_info[1] = 8;
+ s->bpp_info[2] = 8;
+ s->nsamples = 3;
+ s->bpp = 24;
+ s->photometric_interpretation = 2;
+ break;
+ case PIX_FMT_GRAY8:
+ s->bpp_info[0] = 8;
+ s->nsamples = 1;
+ s->bpp = 8;
+ s->photometric_interpretation = 1;
+ break;
+ case PIX_FMT_MONOBLACK:
+ s->bpp_info[0] = 1;
+ s->nsamples = 1;
+ s->bpp = 1;
+ s->photometric_interpretation = 1;
+ break;
+ case PIX_FMT_MONOWHITE:
+ s->bpp_info[0] = 1;
+ s->nsamples = 1;
+ s->bpp = 1;
+ s->photometric_interpretation = 0;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "this pix_fmt (%d) is not supported\n",
+ avctx->pix_fmt);
+ return -1;
+ }
+
+ s->bytes_per_line = (avctx->width * s->bpp + 7) / 8;
+
+ s->entry_point = s->buf;
+ s->buf += 4; // a place for next IFD offset [later updated]
+
+ if (s->has_color_map)
+ if (tiff_prepare_color_map(avctx) < 0) {
+ return -1;
+ }
+
+ /* write the image data */
+ if (tiff_write_image_data(avctx)) {
+ if (s->strip_offset)
+ av_free(s->strip_offset);
+ if (s->strip_size)
+ av_free(s->strip_size);
+ if (s->has_color_map)
+ av_free(s->color_map);
+ return -1;
+ }
+
+ /* IFD entries */
+ s->num_ifd_entries = 0;
+
+ if(
+ tiff_add_ifd_entryv(avctx, TIFF_WIDTH, TIFF_LONG, 1, avctx->width) ||
+ tiff_add_ifd_entryv(avctx, TIFF_HEIGHT, TIFF_LONG, 1, avctx->height) ||
+ tiff_add_ifd_entryp(avctx, TIFF_BPP, TIFF_SHORT, s->nsamples,s->bpp_info) ||
+ tiff_add_ifd_entryv(avctx, TIFF_COMPR, TIFF_SHORT, 1, s->compression) ||
+ tiff_add_ifd_entryv(avctx, TIFF_INVERT, TIFF_SHORT, 1, s->photometric_interpretation) ||
+ tiff_add_ifd_entryp(avctx, TIFF_STRIP_OFFS, TIFF_LONG, s->strip, s->strip_offset) ||
+ tiff_add_ifd_entryv(avctx, TIFF_SAMPLESPERPIX, TIFF_SHORT, 1, s->nsamples) ||
+ tiff_add_ifd_entryv(avctx, TIFF_ROWSPERSTRIP, TIFF_LONG, 1, s->lines_per_strip) ||
+ tiff_add_ifd_entryp(avctx, TIFF_STRIP_SIZE, TIFF_LONG, s->strip, s->strip_size) ||
+ tiff_add_ifd_entryp(avctx, TIFF_XRES, TIFF_LONGLONG, 1, xres) ||
+ tiff_add_ifd_entryp(avctx, TIFF_YRES, TIFF_LONGLONG, 1, yres) ||
+ tiff_add_ifd_entryv(avctx, TIFF_RES_UNIT, TIFF_SHORT, 1, 2) ||
+((s->has_color_map) &&
+ tiff_add_ifd_entryp(avctx, TIFF_PAL, TIFF_SHORT, 3*(1<<s->bpp), s->color_map))
+ ){
+ ret = -1;
+ goto cleanup;
+ }
+
+
+ if (tiff_write_ifd(avctx)){
+ ret = -1;
+ goto cleanup;
+ }
+
+ /* do we have to write the trailer? */
+ if (s->write_trailer) {
+ memcpy(s->buf, trailer, 4);
+ s->buf += 4;
+ }
+
+ /* end writing */
+ s->offset = CURR_OFFSET(s);
+ ret = s->buf - s->buf_start;
+cleanup:
+ av_free(s->strip_offset);
+ av_free(s->strip_size);
+ if (s->has_color_map)
+ av_free(s->color_map);
+
+ return ret;
+}
+
+static int tiff_encoder_init(AVCodecContext * avctx)
+{
+ TiffEncoderContext *s = avctx->priv_data;
+
+ s->max_ifd_entries = 16;
+ s->ifd_entries = av_malloc(s->max_ifd_entries * sizeof(TiffIfdEntry));
+ if (s->ifd_entries == NULL) {
+ av_log(avctx, AV_LOG_ERROR, "not enough memory\n");
+ return -1;
+ }
+
+ s->offset = 4;
+
+ return 0;
+}
+
+static int tiff_encoder_end(AVCodecContext * avctx)
+{
+ TiffEncoderContext *s = avctx->priv_data;
+
+ if (s->ifd_entries != NULL)
+ av_free(s->ifd_entries);
+ return 0;
+}
+
+AVCodec tiff_encoder = {
+ "tiff",
+ CODEC_TYPE_VIDEO,
+ CODEC_ID_TIFF,
+ sizeof(TiffEncoderContext),
+ tiff_encoder_init,
+ tiff_encode_frame,
+ tiff_encoder_end,
+ NULL,
+ 0,
+ NULL,
+ .pix_fmts = (enum PixelFormat[]) {
+ PIX_FMT_RGB24,
+ PIX_FMT_GRAY8,
+ PIX_FMT_MONOWHITE,
+ PIX_FMT_MONOBLACK,
+ PIX_FMT_PAL8,
+ -1},
+};
Index: libavformat/raw.c
===================================================================
--- libavformat/raw.c (wersja 8542)
+++ libavformat/raw.c (kopia robocza)
@@ -43,6 +43,24 @@
return 0;
}
+static int tiff_write_header(struct AVFormatContext *s)
+{
+ static const uint8_t header[4] = {0x49, 0x49, 42, 0};
+ AVStream *st = s->streams[0];
+
+ st->codec->extradata = av_malloc(sizeof(int));
+ if (!st->codec->extradata){
+ av_log(NULL, AV_LOG_ERROR, "not enough memory\n");
+ return -1;
+ }
+ st->codec->extradata_size = sizeof(int);
+ *((int*)st->codec->extradata) = 4;
+
+ put_buffer(&s->pb, header, 4);
+
+ return 0;
+}
+
static int raw_write_packet(struct AVFormatContext *s, AVPacket *pkt)
{
put_buffer(&s->pb, pkt->data, pkt->size);
@@ -54,6 +72,18 @@
{
return 0;
}
+
+static int tiff_write_trailer(struct AVFormatContext *s)
+{
+ static const uint8_t trailer[4] = {0, 0, 0, 0};
+ AVStream *st = s->streams[0];
+
+ put_buffer(&s->pb, trailer, 4);
+
+ av_free(st->codec->extradata);
+ return 0;
+}
+
#endif //CONFIG_MUXERS
/* raw input */
@@ -873,6 +903,20 @@
raw_write_trailer,
.flags= AVFMT_NOTIMESTAMPS,
};
+
+AVOutputFormat tiff_muxer = {
+ "tiff",
+ "tiff video format",
+ "image/tiff",
+ "tiff,tif",
+ 0,
+ CODEC_ID_NONE,
+ CODEC_ID_TIFF,
+ tiff_write_header,
+ raw_write_packet,
+ tiff_write_trailer,
+ .flags = AVFMT_NOTIMESTAMPS,
+};
#endif //CONFIG_MUXERS
#ifdef CONFIG_MUXERS
Index: libavformat/allformats.c
===================================================================
--- libavformat/allformats.c (wersja 8542)
+++ libavformat/allformats.c (kopia robocza)
@@ -143,6 +143,7 @@
REGISTER_MUXER (TG2, tg2);
REGISTER_MUXER (TGP, tgp);
REGISTER_DEMUXER (TIERTEXSEQ, tiertexseq);
+ REGISTER_MUXER (TIFF, tiff);
REGISTER_DEMUXER (TTA, tta);
REGISTER_DEMUXER (V4L2, v4l2);
REGISTER_DEMUXER (VC1, vc1);
Index: libavformat/allformats.h
===================================================================
--- libavformat/allformats.h (wersja 8542)
+++ libavformat/allformats.h (kopia robocza)
@@ -153,6 +153,7 @@
extern AVInputFormat sol_demuxer;
extern AVInputFormat swf_demuxer;
extern AVOutputFormat swf_muxer;
+extern AVOutputFormat tiff_muxer;
extern AVInputFormat tta_demuxer;
extern AVInputFormat v4l2_demuxer;
extern AVInputFormat vc1_demuxer;
More information about the ffmpeg-devel
mailing list