summaryrefslogtreecommitdiff
path: root/libavcodec/huffyuvenc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavcodec/huffyuvenc.c')
-rw-r--r--libavcodec/huffyuvenc.c229
1 files changed, 195 insertions, 34 deletions
diff --git a/libavcodec/huffyuvenc.c b/libavcodec/huffyuvenc.c
index ec07abdcc1..f825fe3f2c 100644
--- a/libavcodec/huffyuvenc.c
+++ b/libavcodec/huffyuvenc.c
@@ -4,20 +4,20 @@
* see http://www.pcisys.net/~melanson/codecs/huffyuv.txt for a description of
* the algorithm used
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,10 +29,12 @@
#include "avcodec.h"
#include "huffyuv.h"
#include "huffman.h"
+#include "internal.h"
#include "put_bits.h"
+#include "libavutil/pixdesc.h"
static inline int sub_left_prediction(HYuvContext *s, uint8_t *dst,
- uint8_t *src, int w, int left)
+ const uint8_t *src, int w, int left)
{
int i;
if (w < 32) {
@@ -54,7 +56,7 @@ static inline int sub_left_prediction(HYuvContext *s, uint8_t *dst,
}
static inline void sub_left_prediction_bgr32(HYuvContext *s, uint8_t *dst,
- uint8_t *src, int w,
+ const uint8_t *src, int w,
int *red, int *green, int *blue,
int *alpha)
{
@@ -128,8 +130,8 @@ static int store_table(HYuvContext *s, const uint8_t *len, uint8_t *buf)
for (; i < 256 && len[i] == val && repeat < 255; i++)
repeat++;
- assert(val < 32 && val >0 && repeat<256 && repeat>0);
- if ( repeat > 7) {
+ av_assert0(val < 32 && val >0 && repeat<256 && repeat>0);
+ if (repeat > 7) {
buf[index++] = val;
buf[index++] = repeat;
} else {
@@ -144,11 +146,17 @@ static av_cold int encode_init(AVCodecContext *avctx)
{
HYuvContext *s = avctx->priv_data;
int i, j;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+ int extradata_tables;
ff_huffyuv_common_init(avctx);
avctx->extradata = av_mallocz(1024*30); // 256*3+4 == 772
avctx->stats_out = av_mallocz(1024*30); // 21*256*3(%llu ) + 3(\n) + 1(0) = 16132
+ if (!avctx->extradata || !avctx->stats_out) {
+ av_freep(&avctx->stats_out);
+ return AVERROR(ENOMEM);
+ }
s->version = 2;
avctx->coded_frame = av_frame_alloc();
@@ -158,15 +166,36 @@ static av_cold int encode_init(AVCodecContext *avctx)
avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
avctx->coded_frame->key_frame = 1;
+ s->bps = 8;
+ s->yuv = !(desc->flags & AV_PIX_FMT_FLAG_RGB) && desc->nb_components >= 2;
+ s->chroma = desc->nb_components > 2;
+ s->alpha = !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA);
+ av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt,
+ &s->chroma_h_shift,
+ &s->chroma_v_shift);
+
switch (avctx->pix_fmt) {
case AV_PIX_FMT_YUV420P:
case AV_PIX_FMT_YUV422P:
if (s->width & 1) {
av_log(avctx, AV_LOG_ERROR, "Width must be even for this colorspace.\n");
- return -1;
+ return AVERROR(EINVAL);
}
s->bitstream_bpp = avctx->pix_fmt == AV_PIX_FMT_YUV420P ? 12 : 16;
break;
+ case AV_PIX_FMT_YUV444P:
+ case AV_PIX_FMT_YUV410P:
+ case AV_PIX_FMT_YUV411P:
+ case AV_PIX_FMT_YUV440P:
+ case AV_PIX_FMT_GBRP:
+ case AV_PIX_FMT_GRAY8:
+ case AV_PIX_FMT_YUVA444P:
+ case AV_PIX_FMT_YUVA420P:
+ case AV_PIX_FMT_YUVA422P:
+ case AV_PIX_FMT_GBRAP:
+ case AV_PIX_FMT_GRAY8A:
+ s->version = 3;
+ break;
case AV_PIX_FMT_RGB32:
s->bitstream_bpp = 32;
break;
@@ -175,10 +204,11 @@ static av_cold int encode_init(AVCodecContext *avctx)
break;
default:
av_log(avctx, AV_LOG_ERROR, "format not supported\n");
- return -1;
+ return AVERROR(EINVAL);
}
+
avctx->bits_per_coded_sample = s->bitstream_bpp;
- s->decorrelate = s->bitstream_bpp >= 24;
+ s->decorrelate = s->bitstream_bpp >= 24 && !s->yuv && avctx->pix_fmt != AV_PIX_FMT_GBRP;
s->predictor = avctx->prediction_method;
s->interlaced = avctx->flags&CODEC_FLAG_INTERLACED_ME ? 1 : 0;
if (avctx->context_model == 1) {
@@ -187,7 +217,7 @@ static av_cold int encode_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_ERROR,
"context=1 is not compatible with "
"2 pass huffyuv encoding\n");
- return -1;
+ return AVERROR(EINVAL);
}
}else s->context= 0;
@@ -196,42 +226,65 @@ static av_cold int encode_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_ERROR,
"Error: YV12 is not supported by huffyuv; use "
"vcodec=ffvhuff or format=422p\n");
- return -1;
+ return AVERROR(EINVAL);
}
if (avctx->context_model) {
av_log(avctx, AV_LOG_ERROR,
"Error: per-frame huffman tables are not supported "
"by huffyuv; use vcodec=ffvhuff\n");
- return -1;
+ return AVERROR(EINVAL);
+ }
+ if (s->version > 2) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Error: ver>2 is not supported "
+ "by huffyuv; use vcodec=ffvhuff\n");
+ return AVERROR(EINVAL);
}
if (s->interlaced != ( s->height > 288 ))
av_log(avctx, AV_LOG_INFO,
"using huffyuv 2.2.0 or newer interlacing flag\n");
}
+ if (s->version > 2 && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
+ av_log(avctx, AV_LOG_ERROR, "Ver > 2 is under development, files encoded with it may not be decodable with future versions!!!\n"
+ "Use vstrict=-2 / -strict -2 to use it anyway.\n");
+ return AVERROR(EINVAL);
+ }
+
if (s->bitstream_bpp >= 24 && s->predictor == MEDIAN) {
av_log(avctx, AV_LOG_ERROR,
"Error: RGB is incompatible with median predictor\n");
- return -1;
+ return AVERROR(EINVAL);
}
+ extradata_tables = 1 + 2*s->chroma + s->alpha;
((uint8_t*)avctx->extradata)[0] = s->predictor | (s->decorrelate << 6);
- ((uint8_t*)avctx->extradata)[1] = s->bitstream_bpp;
((uint8_t*)avctx->extradata)[2] = s->interlaced ? 0x10 : 0x20;
if (s->context)
((uint8_t*)avctx->extradata)[2] |= 0x40;
- ((uint8_t*)avctx->extradata)[3] = 0;
+ if (s->version < 3) {
+ ((uint8_t*)avctx->extradata)[1] = s->bitstream_bpp;
+ ((uint8_t*)avctx->extradata)[3] = 0;
+ extradata_tables = 3;
+ } else {
+ ((uint8_t*)avctx->extradata)[1] = ((s->bps-1)<<4) | s->chroma_h_shift | (s->chroma_v_shift<<2);
+ if (s->chroma)
+ ((uint8_t*)avctx->extradata)[2] |= s->yuv ? 1 : 2;
+ if (s->alpha)
+ ((uint8_t*)avctx->extradata)[2] |= 4;
+ ((uint8_t*)avctx->extradata)[3] = 1;
+ }
s->avctx->extradata_size = 4;
if (avctx->stats_in) {
char *p = avctx->stats_in;
- for (i = 0; i < 3; i++)
+ for (i = 0; i < 4; i++)
for (j = 0; j < 256; j++)
s->stats[i][j] = 1;
for (;;) {
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 4; i++) {
char *next;
for (j = 0; j < 256; j++) {
@@ -243,7 +296,7 @@ static av_cold int encode_init(AVCodecContext *avctx)
if (p[0] == 0 || p[1] == 0 || p[2] == 0) break;
}
} else {
- for (i = 0; i < 3; i++)
+ for (i = 0; i < 4; i++)
for (j = 0; j < 256; j++) {
int d = FFMIN(j, 256 - j);
@@ -251,7 +304,7 @@ static av_cold int encode_init(AVCodecContext *avctx)
}
}
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < extradata_tables; i++) {
ff_huff_gen_len_table(s->len[i], s->stats[i]);
if (ff_huffyuv_generate_bits_table(s->bits[i], s->len[i]) < 0) {
@@ -263,7 +316,7 @@ static av_cold int encode_init(AVCodecContext *avctx)
}
if (s->context) {
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 4; i++) {
int pels = s->width * s->height / (i ? 40 : 10);
for (j = 0; j < 256; j++) {
int d = FFMIN(j, 256 - j);
@@ -271,12 +324,15 @@ static av_cold int encode_init(AVCodecContext *avctx)
}
}
} else {
- for (i = 0; i < 3; i++)
+ for (i = 0; i < 4; i++)
for (j = 0; j < 256; j++)
s->stats[i][j]= 0;
}
- ff_huffyuv_alloc_temp(s);
+ if (ff_huffyuv_alloc_temp(s)) {
+ ff_huffyuv_common_end(s);
+ return AVERROR(ENOMEM);
+ }
s->picture_number=0;
@@ -337,6 +393,54 @@ static int encode_422_bitstream(HYuvContext *s, int offset, int count)
return 0;
}
+static int encode_plane_bitstream(HYuvContext *s, int count, int plane)
+{
+ int i;
+
+ if (s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb) >> 3) < 4 * count) {
+ av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n");
+ return -1;
+ }
+
+#define LOAD2\
+ int y0 = s->temp[0][2 * i];\
+ int y1 = s->temp[0][2 * i + 1];
+#define STAT2\
+ s->stats[plane][y0]++;\
+ s->stats[plane][y1]++;
+#define WRITE2\
+ put_bits(&s->pb, s->len[plane][y0], s->bits[plane][y0]);\
+ put_bits(&s->pb, s->len[plane][y1], s->bits[plane][y1]);
+
+ count /= 2;
+
+ if (s->flags & CODEC_FLAG_PASS1) {
+ for (i = 0; i < count; i++) {
+ LOAD2;
+ STAT2;
+ }
+ }
+ if (s->avctx->flags2 & CODEC_FLAG2_NO_OUTPUT)
+ return 0;
+
+ if (s->context) {
+ for (i = 0; i < count; i++) {
+ LOAD2;
+ STAT2;
+ WRITE2;
+ }
+ } else {
+ for (i = 0; i < count; i++) {
+ LOAD2;
+ WRITE2;
+ }
+ }
+#undef LOAD2
+#undef STAT2
+#undef WRITE2
+ return 0;
+}
+
static int encode_gray_bitstream(HYuvContext *s, int count)
{
int i;
@@ -394,8 +498,8 @@ static inline int encode_bgra_bitstream(HYuvContext *s, int count, int planes)
#define LOAD_GBRA \
int g = s->temp[0][planes == 3 ? 3 * i + 1 : 4 * i + G]; \
- int b = s->temp[0][planes == 3 ? 3 * i + 2 : 4 * i + B] - g & 0xFF; \
- int r = s->temp[0][planes == 3 ? 3 * i + 0 : 4 * i + R] - g & 0xFF; \
+ int b =(s->temp[0][planes == 3 ? 3 * i + 2 : 4 * i + B] - g) & 0xFF;\
+ int r =(s->temp[0][planes == 3 ? 3 * i + 0 : 4 * i + R] - g) & 0xFF;\
int a = s->temp[0][planes * i + A];
#define STAT_BGRA \
@@ -446,21 +550,18 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame * const p = pict;
int i, j, size = 0, ret;
- if (!pkt->data &&
- (ret = av_new_packet(pkt, width * height * 3 * 4 + FF_MIN_BUFFER_SIZE)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error allocating output packet.\n");
+ if ((ret = ff_alloc_packet2(avctx, pkt, width * height * 3 * 4 + FF_MIN_BUFFER_SIZE)) < 0)
return ret;
- }
if (s->context) {
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 4; i++) {
ff_huff_gen_len_table(s->len[i], s->stats[i]);
if (ff_huffyuv_generate_bits_table(s->bits[i], s->len[i]) < 0)
return -1;
size += store_table(s, s->len[i], &pkt->data[size]);
}
- for (i = 0; i < 3; i++)
+ for (i = 0; i < 4; i++)
for (j = 0; j < 256; j++)
s->stats[i][j] >>= 1;
}
@@ -629,6 +730,59 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
encode_bgra_bitstream(s, width, 3);
}
+ } else if (s->version > 2) {
+ int plane;
+ for (plane = 0; plane < 1 + 2*s->chroma + s->alpha; plane++) {
+ int left, y;
+ int w = width;
+ int h = height;
+ int fake_stride = fake_ystride;
+
+ if (s->chroma && (plane == 1 || plane == 2)) {
+ w >>= s->chroma_h_shift;
+ h >>= s->chroma_v_shift;
+ fake_stride = plane == 1 ? fake_ustride : fake_vstride;
+ }
+
+ left = sub_left_prediction(s, s->temp[0], p->data[plane], w , 0);
+
+ encode_plane_bitstream(s, w, plane);
+
+ if (s->predictor==MEDIAN) {
+ int lefttop;
+ y = 1;
+ if (s->interlaced) {
+ left = sub_left_prediction(s, s->temp[0], p->data[plane] + p->linesize[plane], w , left);
+
+ encode_plane_bitstream(s, w, plane);
+ y++;
+ }
+
+ lefttop = p->data[plane][0];
+
+ for (; y < h; y++) {
+ uint8_t *dst = p->data[plane] + p->linesize[plane] * y;
+
+ s->dsp.sub_hfyu_median_prediction(s->temp[0], dst - fake_stride, dst, w , &left, &lefttop);
+
+ encode_plane_bitstream(s, w, plane);
+ }
+ } else {
+ for (y = 1; y < h; y++) {
+ uint8_t *dst = p->data[plane] + p->linesize[plane] * y;
+
+ if (s->predictor == PLANE && s->interlaced < y) {
+ s->dsp.diff_bytes(s->temp[1], dst, dst - fake_stride, w);
+
+ left = sub_left_prediction(s, s->temp[0], s->temp[1], w , left);
+ } else {
+ left = sub_left_prediction(s, s->temp[0], dst, w , left);
+ }
+
+ encode_plane_bitstream(s, w, plane);
+ }
+ }
+ }
} else {
av_log(avctx, AV_LOG_ERROR, "Format not supported!\n");
}
@@ -643,7 +797,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
int j;
char *p = avctx->stats_out;
char *end = p + 1024*30;
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 4; i++) {
for (j = 0; j < 256; j++) {
snprintf(p, end-p, "%"PRIu64" ", s->stats[i][j]);
p += strlen(p);
@@ -710,7 +864,14 @@ AVCodec ff_ffvhuff_encoder = {
.encode2 = encode_frame,
.close = encode_end,
.pix_fmts = (const enum AVPixelFormat[]){
- AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_RGB24,
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P,
+ AV_PIX_FMT_GBRP,
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
+ AV_PIX_FMT_GBRAP,
+ AV_PIX_FMT_GRAY8A,
+ AV_PIX_FMT_RGB24,
AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE
},
};