X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Futvideo.c;h=a45f13fa54e6c03d0ba2f2fe309dc4d93e4f4e5d;hb=dd3ca3ea15392da8636c06764e2da31e6ca700f0;hp=6fb384a4e46843c62959c72d79fc67f821f9032b;hpb=8e2bab5d4bddb4029503c0f90623854948ddb3c5;p=ffmpeg diff --git a/libavcodec/utvideo.c b/libavcodec/utvideo.c index 6fb384a4e46..a45f13fa54e 100644 --- a/libavcodec/utvideo.c +++ b/libavcodec/utvideo.c @@ -31,6 +31,7 @@ #include "bytestream.h" #include "get_bits.h" #include "dsputil.h" +#include "thread.h" enum { PRED_NONE = 0, @@ -282,6 +283,77 @@ static void restore_median(uint8_t *src, int step, int stride, } } +/* UtVideo interlaced mode treats every two lines as a single one, + * so restoring function should take care of possible padding between + * two parts of the same "line". + */ +static void restore_median_il(uint8_t *src, int step, int stride, + int width, int height, int slices, int rmode) +{ + int i, j, slice; + int A, B, C; + uint8_t *bsrc; + int slice_start, slice_height; + const int cmask = ~(rmode ? 3 : 1); + const int stride2 = stride << 1; + + for (slice = 0; slice < slices; slice++) { + slice_start = ((slice * height) / slices) & cmask; + slice_height = ((((slice + 1) * height) / slices) & cmask) - slice_start; + slice_height >>= 1; + + bsrc = src + slice_start * stride; + + // first line - left neighbour prediction + bsrc[0] += 0x80; + A = bsrc[0]; + for (i = step; i < width * step; i += step) { + bsrc[i] += A; + A = bsrc[i]; + } + for (i = 0; i < width * step; i += step) { + bsrc[stride + i] += A; + A = bsrc[stride + i]; + } + bsrc += stride2; + if (slice_height == 1) + continue; + // second line - first element has top predition, the rest uses median + C = bsrc[-stride2]; + bsrc[0] += C; + A = bsrc[0]; + for (i = step; i < width * step; i += step) { + B = bsrc[i - stride2]; + bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C)); + C = B; + A = bsrc[i]; + } + for (i = 0; i < width * step; i += step) { + B = bsrc[i - stride]; + bsrc[stride + i] += mid_pred(A, B, (uint8_t)(A + B - C)); + C = B; + A = bsrc[stride + i]; + } + bsrc += stride2; + // the rest of lines use continuous median prediction + for (j = 2; j < slice_height; j++) { + for (i = 0; i < width * step; i += step) { + B = bsrc[i - stride2]; + bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C)); + C = B; + A = bsrc[i]; + } + for (i = 0; i < width * step; i += step) { + B = bsrc[i - stride]; + bsrc[i + stride] += mid_pred(A, B, (uint8_t)(A + B - C)); + C = B; + A = bsrc[i + stride]; + } + bsrc += stride2; + } + } +} + static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *avpkt) { const uint8_t *buf = avpkt->data; @@ -295,15 +367,17 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPac int ret; if (c->pic.data[0]) - avctx->release_buffer(avctx, &c->pic); + ff_thread_release_buffer(avctx, &c->pic); c->pic.reference = 3; c->pic.buffer_hints = FF_BUFFER_HINTS_VALID; - if ((ret = avctx->get_buffer(avctx, &c->pic)) < 0) { + if ((ret = ff_thread_get_buffer(avctx, &c->pic)) < 0) { av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); return ret; } + ff_thread_finish_setup(avctx); + /* parse plane structure to retrieve frame flags and validate slice offsets */ ptr = buf; for (i = 0; i < c->planes; i++) { @@ -381,10 +455,18 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPac c->frame_pred == PRED_LEFT); if (ret) return ret; - if (c->frame_pred == PRED_MEDIAN) - restore_median(c->pic.data[i], 1, c->pic.linesize[i], - avctx->width >> !!i, avctx->height >> !!i, - c->slices, !i); + if (c->frame_pred == PRED_MEDIAN) { + if (!c->interlaced) { + restore_median(c->pic.data[i], 1, c->pic.linesize[i], + avctx->width >> !!i, avctx->height >> !!i, + c->slices, !i); + } else { + restore_median_il(c->pic.data[i], 1, c->pic.linesize[i], + avctx->width >> !!i, + avctx->height >> !!i, + c->slices, !i); + } + } } break; case PIX_FMT_YUV422P: @@ -395,9 +477,17 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPac c->frame_pred == PRED_LEFT); if (ret) return ret; - if (c->frame_pred == PRED_MEDIAN) - restore_median(c->pic.data[i], 1, c->pic.linesize[i], - avctx->width >> !!i, avctx->height, c->slices, 0); + if (c->frame_pred == PRED_MEDIAN) { + if (!c->interlaced) { + restore_median(c->pic.data[i], 1, c->pic.linesize[i], + avctx->width >> !!i, avctx->height, + c->slices, 0); + } else { + restore_median_il(c->pic.data[i], 1, c->pic.linesize[i], + avctx->width >> !!i, avctx->height, + c->slices, 0); + } + } } break; } @@ -470,7 +560,7 @@ static av_cold int decode_end(AVCodecContext *avctx) UtvideoContext * const c = avctx->priv_data; if (c->pic.data[0]) - avctx->release_buffer(avctx, &c->pic); + ff_thread_release_buffer(avctx, &c->pic); av_freep(&c->slice_bits); @@ -485,7 +575,7 @@ AVCodec ff_utvideo_decoder = { .init = decode_init, .close = decode_end, .decode = decode_frame, - .capabilities = CODEC_CAP_DR1, + .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS, .long_name = NULL_IF_CONFIG_SMALL("Ut Video"), };