#include "internal.h"
#include "thread.h"
#include "utvideo.h"
+#include "vlc.h"
static int build_huff10(const uint8_t *src, VLC *vlc, int *fsym)
{
return AVERROR_INVALIDDATA;
}
+static int compute_cmask(int plane_no, int interlaced, int pix_fmt)
+{
+ const int is_luma = (pix_fmt == AV_PIX_FMT_YUV420P) && !plane_no;
+
+ if (interlaced)
+ return ~(1 + 2 * is_luma);
+
+ return ~is_luma;
+}
+
static int decode_plane(UtvideoContext *c, int plane_no,
uint8_t *dst, int step, ptrdiff_t stride,
int width, int height,
VLC vlc;
BitstreamContext bc;
int prev, fsym;
- const int cmask = ~(!plane_no && c->avctx->pix_fmt == AV_PIX_FMT_YUV420P);
+ const int cmask = compute_cmask(plane_no, c->interlaced, c->avctx->pix_fmt);
if (build_huff(src, &vlc, &fsym)) {
av_log(c->avctx, AV_LOG_ERROR, "Cannot build Huffman codes\n");
}
}
-static void restore_median(uint8_t *src, int step, ptrdiff_t stride,
- int width, int height, int slices, int rmode)
+static void restore_median_planar(UtvideoContext *c, uint8_t *src,
+ ptrdiff_t 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;
+
+ for (slice = 0; slice < slices; slice++) {
+ slice_start = ((slice * height) / slices) & cmask;
+ slice_height = ((((slice + 1) * height) / slices) & cmask) -
+ slice_start;
+
+ if (!slice_height)
+ continue;
+ bsrc = src + slice_start * stride;
+
+ // first line - left neighbour prediction
+ bsrc[0] += 0x80;
+ c->hdspdec.add_hfyu_left_pred(bsrc, bsrc, width, 0);
+ bsrc += stride;
+ if (slice_height <= 1)
+ continue;
+ // second line - first element has top prediction, the rest uses median
+ C = bsrc[-stride];
+ bsrc[0] += C;
+ A = bsrc[0];
+ for (i = 1; i < width; i++) {
+ B = bsrc[i - stride];
+ bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C));
+ C = B;
+ A = bsrc[i];
+ }
+ bsrc += stride;
+ // the rest of lines use continuous median prediction
+ for (j = 2; j < slice_height; j++) {
+ c->hdspdec.add_hfyu_median_pred(bsrc, bsrc - stride,
+ bsrc, width, &A, &B);
+ bsrc += 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_planar_il(UtvideoContext *c, uint8_t *src,
+ ptrdiff_t 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;
+ if (!slice_height)
+ continue;
+
+ bsrc = src + slice_start * stride;
+
+ // first line - left neighbour prediction
+ bsrc[0] += 0x80;
+ A = c->hdspdec.add_hfyu_left_pred(bsrc, bsrc, width, 0);
+ c->hdspdec.add_hfyu_left_pred(bsrc + stride, bsrc + stride, width, A);
+ bsrc += stride2;
+ if (slice_height <= 1)
+ continue;
+ // second line - first element has top prediction, the rest uses median
+ C = bsrc[-stride2];
+ bsrc[0] += C;
+ A = bsrc[0];
+ for (i = 1; i < width; i++) {
+ B = bsrc[i - stride2];
+ bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C));
+ C = B;
+ A = bsrc[i];
+ }
+ c->hdspdec.add_hfyu_median_pred(bsrc + stride, bsrc - stride,
+ bsrc + stride, width, &A, &B);
+ bsrc += stride2;
+ // the rest of lines use continuous median prediction
+ for (j = 2; j < slice_height; j++) {
+ c->hdspdec.add_hfyu_median_pred(bsrc, bsrc - stride2,
+ bsrc, width, &A, &B);
+ c->hdspdec.add_hfyu_median_pred(bsrc + stride, bsrc - stride,
+ bsrc + stride, width, &A, &B);
+ bsrc += stride2;
+ }
+ }
+}
+
+static void restore_median_packed(uint8_t *src, int step, ptrdiff_t stride,
+ int width, int height,
+ int slices, int rmode)
{
int i, j, slice;
int A, B, C;
* 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, ptrdiff_t stride,
- int width, int height, int slices, int rmode)
+static void restore_median_packed_il(uint8_t *src, int step, ptrdiff_t stride,
+ int width, int height,
+ int slices, int rmode)
{
int i, j, slice;
int A, B, C;
}
}
+static void restore_gradient_planar(UtvideoContext *c, uint8_t *src, ptrdiff_t 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;
+
+ for (slice = 0; slice < slices; slice++) {
+ slice_start = ((slice * height) / slices) & cmask;
+ slice_height = ((((slice + 1) * height) / slices) & cmask) -
+ slice_start;
+
+ if (!slice_height)
+ continue;
+ bsrc = src + slice_start * stride;
+
+ // first line - left neighbour prediction
+ bsrc[0] += 0x80;
+ c->hdspdec.add_hfyu_left_pred(bsrc, bsrc, width, 0);
+ bsrc += stride;
+ if (slice_height <= 1)
+ continue;
+ for (j = 1; j < slice_height; j++) {
+ // second line - first element has top prediction, the rest uses gradient
+ bsrc[0] = (bsrc[0] + bsrc[-stride]) & 0xFF;
+ for (i = 1; i < width; i++) {
+ A = bsrc[i - stride];
+ B = bsrc[i - (stride + 1)];
+ C = bsrc[i - 1];
+ bsrc[i] = (A - B + C + bsrc[i]) & 0xFF;
+ }
+ bsrc += stride;
+ }
+ }
+}
+
+static void restore_gradient_planar_il(UtvideoContext *c, uint8_t *src, ptrdiff_t 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 ptrdiff_t 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;
+ if (!slice_height)
+ continue;
+
+ bsrc = src + slice_start * stride;
+
+ // first line - left neighbour prediction
+ bsrc[0] += 0x80;
+ A = c->hdspdec.add_hfyu_left_pred(bsrc, bsrc, width, 0);
+ c->hdspdec.add_hfyu_left_pred(bsrc + stride, bsrc + stride, width, A);
+ bsrc += stride2;
+ if (slice_height <= 1)
+ continue;
+ for (j = 1; j < slice_height; j++) {
+ // second line - first element has top prediction, the rest uses gradient
+ bsrc[0] = (bsrc[0] + bsrc[-stride2]) & 0xFF;
+ for (i = 1; i < width; i++) {
+ A = bsrc[i - stride2];
+ B = bsrc[i - (stride2 + 1)];
+ C = bsrc[i - 1];
+ bsrc[i] = (A - B + C + bsrc[i]) & 0xFF;
+ }
+ A = bsrc[-stride];
+ B = bsrc[-(1 + stride + stride - width)];
+ C = bsrc[width - 1];
+ bsrc[stride] = (A - B + C + bsrc[stride]) & 0xFF;
+ for (i = 1; i < width; i++) {
+ A = bsrc[i - stride];
+ B = bsrc[i - (1 + stride)];
+ C = bsrc[i - 1 + stride];
+ bsrc[i + stride] = (A - B + C + bsrc[i + stride]) & 0xFF;
+ }
+ bsrc += stride2;
+ }
+ }
+}
+
+static void restore_gradient_packed(uint8_t *src, int step, ptrdiff_t 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;
+
+ for (slice = 0; slice < slices; slice++) {
+ slice_start = ((slice * height) / slices) & cmask;
+ slice_height = ((((slice + 1) * height) / slices) & cmask) -
+ slice_start;
+
+ if (!slice_height)
+ continue;
+ 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];
+ }
+ bsrc += stride;
+ if (slice_height <= 1)
+ continue;
+ for (j = 1; j < slice_height; j++) {
+ // second line - first element has top prediction, the rest uses gradient
+ C = bsrc[-stride];
+ bsrc[0] += C;
+ for (i = step; i < width * step; i += step) {
+ A = bsrc[i - stride];
+ B = bsrc[i - (stride + step)];
+ C = bsrc[i - step];
+ bsrc[i] = (A - B + C + bsrc[i]) & 0xFF;
+ }
+ bsrc += stride;
+ }
+ }
+}
+
+static void restore_gradient_packed_il(uint8_t *src, int step, ptrdiff_t 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 ptrdiff_t 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;
+ if (!slice_height)
+ continue;
+
+ 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;
+ for (j = 1; j < slice_height; j++) {
+ // second line - first element has top prediction, the rest uses gradient
+ C = bsrc[-stride2];
+ bsrc[0] += C;
+ for (i = step; i < width * step; i += step) {
+ A = bsrc[i - stride2];
+ B = bsrc[i - (stride2 + step)];
+ C = bsrc[i - step];
+ bsrc[i] = (A - B + C + bsrc[i]) & 0xFF;
+ }
+ A = bsrc[-stride];
+ B = bsrc[-(step + stride + stride - width * step)];
+ C = bsrc[width * step - step];
+ bsrc[stride] = (A - B + C + bsrc[stride]) & 0xFF;
+ for (i = step; i < width * step; i += step) {
+ A = bsrc[i - stride];
+ B = bsrc[i - (step + stride)];
+ C = bsrc[i - step + stride];
+ bsrc[i + stride] = (A - B + C + bsrc[i + stride]) & 0xFF;
+ }
+ bsrc += stride2;
+ }
+ }
+}
+
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVPacket *avpkt)
{
c->frame_pred = (c->frame_info >> 8) & 3;
- if (c->frame_pred == PRED_GRADIENT) {
- avpriv_request_sample(avctx, "Frame with gradient prediction");
- return AVERROR_PATCHWELCOME;
- }
-
av_fast_malloc(&c->slice_bits, &c->slice_bits_size,
max_slice_size + AV_INPUT_BUFFER_PADDING_SIZE);
return ret;
if (c->frame_pred == PRED_MEDIAN) {
if (!c->interlaced) {
- restore_median(frame.f->data[0] + ff_ut_rgb_order[i],
- c->planes, frame.f->linesize[0], avctx->width,
- avctx->height, c->slices, 0);
+ restore_median_packed(frame.f->data[0] + ff_ut_rgb_order[i],
+ c->planes, frame.f->linesize[0], avctx->width,
+ avctx->height, c->slices, 0);
+ } else {
+ restore_median_packed_il(frame.f->data[0] + ff_ut_rgb_order[i],
+ c->planes, frame.f->linesize[0],
+ avctx->width, avctx->height, c->slices,
+ 0);
+ }
+ } else if (c->frame_pred == PRED_GRADIENT) {
+ if (!c->interlaced) {
+ restore_gradient_packed(frame.f->data[0] + ff_ut_rgb_order[i],
+ c->planes, frame.f->linesize[0],
+ avctx->width, avctx->height,
+ c->slices, 0);
} else {
- restore_median_il(frame.f->data[0] + ff_ut_rgb_order[i],
- c->planes, frame.f->linesize[0],
- avctx->width, avctx->height, c->slices,
- 0);
+ restore_gradient_packed_il(frame.f->data[0] + ff_ut_rgb_order[i],
+ c->planes, frame.f->linesize[0],
+ avctx->width, avctx->height,
+ c->slices, 0);
}
}
}
return ret;
if (c->frame_pred == PRED_MEDIAN) {
if (!c->interlaced) {
- restore_median(frame.f->data[i], 1, frame.f->linesize[i],
- avctx->width >> !!i, avctx->height >> !!i,
- c->slices, !i);
+ restore_median_planar(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width >> !!i, avctx->height >> !!i,
+ c->slices, !i);
+ } else {
+ restore_median_planar_il(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width >> !!i,
+ avctx->height >> !!i,
+ c->slices, !i);
+ }
+ } else if (c->frame_pred == PRED_GRADIENT) {
+ if (!c->interlaced) {
+ restore_gradient_planar(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width >> !!i,
+ avctx->height >> !!i,
+ c->slices, !i);
} else {
- restore_median_il(frame.f->data[i], 1, frame.f->linesize[i],
- avctx->width >> !!i,
- avctx->height >> !!i,
- c->slices, !i);
+ restore_gradient_planar_il(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width >> !!i,
+ avctx->height >> !!i,
+ c->slices, !i);
}
}
}
return ret;
if (c->frame_pred == PRED_MEDIAN) {
if (!c->interlaced) {
- restore_median(frame.f->data[i], 1, frame.f->linesize[i],
- avctx->width >> !!i, avctx->height,
- c->slices, 0);
+ restore_median_planar(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width >> !!i, avctx->height,
+ c->slices, 0);
} else {
- restore_median_il(frame.f->data[i], 1, frame.f->linesize[i],
- avctx->width >> !!i, avctx->height,
- c->slices, 0);
+ restore_median_planar_il(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width >> !!i, avctx->height,
+ c->slices, 0);
+ }
+ } else if (c->frame_pred == PRED_GRADIENT) {
+ if (!c->interlaced) {
+ restore_gradient_planar(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width >> !!i, avctx->height,
+ c->slices, 0);
+ } else {
+ restore_gradient_planar_il(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width >> !!i, avctx->height,
+ c->slices, 0);
}
}
}
return ret;
if (c->frame_pred == PRED_MEDIAN) {
if (!c->interlaced) {
- restore_median(frame.f->data[i], 1, frame.f->linesize[i],
- avctx->width, avctx->height,
- c->slices, 0);
+ restore_median_planar(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width, avctx->height,
+ c->slices, 0);
+ } else {
+ restore_median_planar_il(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width, avctx->height,
+ c->slices, 0);
+ }
+ } else if (c->frame_pred == PRED_GRADIENT) {
+ if (!c->interlaced) {
+ restore_gradient_planar(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width, avctx->height,
+ c->slices, 0);
} else {
- restore_median_il(frame.f->data[i], 1, frame.f->linesize[i],
- avctx->width, avctx->height,
- c->slices, 0);
+ restore_gradient_planar_il(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width, avctx->height,
+ c->slices, 0);
}
}
}
c->avctx = avctx;
ff_bswapdsp_init(&c->bdsp);
+ ff_huffyuvdsp_init(&c->hdspdec);
if (avctx->extradata_size >= 16) {
av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n",