diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2013-09-09 20:08:42 +0200 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2013-09-09 20:20:21 +0200 |
commit | 3576b564ec4ffa98402b02b3a69171cefd103eb0 (patch) | |
tree | 6ba26379d42547732c492378d023c1c36f1349b9 | |
parent | 8393b80b7d94783520b591208a369f4aae81da40 (diff) | |
download | ffmpeg-3576b564ec4ffa98402b02b3a69171cefd103eb0.tar.gz |
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@gmx.at>
-rw-r--r-- | libavcodec/ffv1enc.c | 64 |
1 files changed, 52 insertions, 12 deletions
diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c index b68fab21d8..220b2a6230 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; |