[FFmpeg-cvslog] avcodec/ffv1enc: encode slice as raw PCM in 1.4 when the buffer is too small.
Michael Niedermayer
git at videolan.org
Mon Sep 9 20:27:19 CEST 2013
ffmpeg | branch: master | Michael Niedermayer <michaelni at gmx.at> | Mon Sep 9 20:08:42 2013 +0200| [3576b564ec4ffa98402b02b3a69171cefd103eb0] | committer: Michael Niedermayer
avcodec/ffv1enc: encode slice as raw PCM in 1.4 when the buffer is too small.
This limits the maximum size of encoded slices more tightly
Signed-off-by: Michael Niedermayer <michaelni at gmx.at>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=3576b564ec4ffa98402b02b3a69171cefd103eb0
---
libavcodec/ffv1enc.c | 64 ++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 52 insertions(+), 12 deletions(-)
diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c
index b68fab2..220b2a6 100644
--- a/libavcodec/ffv1enc.c
+++ b/libavcodec/ffv1enc.c
@@ -286,6 +286,18 @@ static av_always_inline int encode_line(FFV1Context *s, int w,
}
}
+ if (s->slice_coding_mode == 1) {
+ for (x = 0; x < w; x++) {
+ int i;
+ int v = sample[0][x];
+ for (i = bits-1; i>=0; i--) {
+ uint8_t state = 128;
+ put_rac(c, &state, (v>>i) & 1);
+ }
+ }
+ return 0;
+ }
+
for (x = 0; x < w; x++) {
int diff, context;
@@ -426,11 +438,13 @@ static int encode_rgb_frame(FFV1Context *s, uint8_t *src[3], int w, int h, int s
r = *((uint16_t*)(src[2] + x*2 + stride[2]*y));
}
- b -= g;
- r -= g;
- g += (b + r) >> 2;
- b += offset;
- r += offset;
+ if (s->slice_coding_mode != 1) {
+ b -= g;
+ r -= g;
+ g += (b + r) >> 2;
+ b += offset;
+ r += offset;
+ }
sample[0][0][x] = g;
sample[1][0][x] = b;
@@ -441,10 +455,10 @@ static int encode_rgb_frame(FFV1Context *s, uint8_t *src[3], int w, int h, int s
int ret;
sample[p][0][-1] = sample[p][1][0 ];
sample[p][1][ w] = sample[p][1][w-1];
- if (lbd)
+ if (lbd && s->slice_coding_mode == 0)
ret = encode_line(s, w, sample[p], (p + 1) / 2, 9);
else
- ret = encode_line(s, w, sample[p], (p + 1) / 2, bits + 1);
+ ret = encode_line(s, w, sample[p], (p + 1) / 2, bits + (s->slice_coding_mode != 1));
if (ret < 0)
return ret;
}
@@ -960,6 +974,12 @@ static void encode_slice_header(FFV1Context *f, FFV1Context *fs)
put_symbol(c, state, 1 + !f->picture.f->top_field_first, 0);
put_symbol(c, state, f->picture.f->sample_aspect_ratio.num, 0);
put_symbol(c, state, f->picture.f->sample_aspect_ratio.den, 0);
+ if (f->version > 3) {
+ put_rac(c, state, fs->slice_coding_mode == 1);
+ if (fs->slice_coding_mode == 1)
+ ffv1_clear_slice_state(f, fs);
+ put_symbol(c, state, fs->slice_coding_mode, 0);
+ }
}
static int encode_slice(AVCodecContext *c, void *arg)
@@ -972,7 +992,12 @@ static int encode_slice(AVCodecContext *c, void *arg)
int y = fs->slice_y;
AVFrame *const p = f->picture.f;
const int ps = av_pix_fmt_desc_get(c->pix_fmt)->comp[0].step_minus1 + 1;
+ int ret;
+ RangeCoder c_bak = fs->c;
+ fs->slice_coding_mode = 0;
+
+retry:
if (p->key_frame)
ffv1_clear_slice_state(f, fs);
if (f->version > 2) {
@@ -993,22 +1018,34 @@ static int encode_slice(AVCodecContext *c, void *arg)
const int cx = x >> f->chroma_h_shift;
const int cy = y >> f->chroma_v_shift;
- encode_plane(fs, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0);
+ ret = encode_plane(fs, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0);
if (f->chroma_planes) {
- encode_plane(fs, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1);
- encode_plane(fs, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1);
+ ret |= encode_plane(fs, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1);
+ ret |= encode_plane(fs, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1);
}
if (fs->transparency)
- encode_plane(fs, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], 2);
+ ret |= encode_plane(fs, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], 2);
} else {
uint8_t *planes[3] = {p->data[0] + ps*x + y*p->linesize[0],
p->data[1] + ps*x + y*p->linesize[1],
p->data[2] + ps*x + y*p->linesize[2]};
- encode_rgb_frame(fs, planes, width, height, p->linesize);
+ ret = encode_rgb_frame(fs, planes, width, height, p->linesize);
}
emms_c();
+ if (ret < 0) {
+ av_assert0(fs->slice_coding_mode == 0);
+ if (fs->version < 4 || !fs->ac) {
+ av_log(c, AV_LOG_ERROR, "Buffer too small\n");
+ return ret;
+ }
+ av_log(c, AV_LOG_DEBUG, "Coding slice as PCM\n");
+ fs->slice_coding_mode = 1;
+ fs->c = c_bak;
+ goto retry;
+ }
+
return 0;
}
@@ -1025,6 +1062,9 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
int64_t maxsize = FF_MIN_BUFFER_SIZE
+ avctx->width*avctx->height*35LL*4;
+ if (f->version > 3)
+ maxsize = FF_MIN_BUFFER_SIZE + avctx->width*avctx->height*3*4;
+
if ((ret = ff_alloc_packet2(avctx, pkt, maxsize)) < 0)
return ret;
More information about the ffmpeg-cvslog
mailing list