Merge remote-tracking branch 'qatar/master'
authorMichael Niedermayer <michaelni@gmx.at>
Fri, 17 Aug 2012 15:06:07 +0000 (17:06 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Fri, 17 Aug 2012 15:06:52 +0000 (17:06 +0200)
* qatar/master:
  libvpxenc: use the default bitrate if not set
  utvideo: Rename utvideo.c to utvideodec.c
  doc: Fix syntax errors in sample Emacs config
  mjpegdec: more meaningful return values
  configure: clean up Altivec detection
  getopt: Remove an unnecessary define
  rtmp: Use int instead of ssize_t
  getopt: Add missing includes
  rtmp: Add support for receiving incoming streams
  Add missing includes for code relying on external libraries

Conflicts:
libavcodec/libopenjpegenc.c
libavcodec/libvpxenc.c
libavcodec/mjpegdec.c
libavformat/version.h

Merged-by: Michael Niedermayer <michaelni@gmx.at>
16 files changed:
1  2 
compat/getopt.c
configure
doc/developer.texi
doc/protocols.texi
libavcodec/Makefile
libavcodec/libopenjpegdec.c
libavcodec/libopenjpegenc.c
libavcodec/libschroedinger.c
libavcodec/libschroedingerdec.c
libavcodec/libxavs.c
libavcodec/mjpegdec.c
libavcodec/utvideodec.c
libavfilter/vf_frei0r.c
libavfilter/vf_libopencv.c
libavformat/rtmpproto.c
libavformat/version.h

diff --cc compat/getopt.c
Simple merge
diff --cc configure
Simple merge
@@@ -201,11 -232,11 +201,11 @@@ autocmd InsertEnter * match ForbiddenWh
  
  For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}:
  @example
 -(c-add-style "libav"
 +(c-add-style "ffmpeg"
               '("k&r"
                 (c-basic-offset . 4)
-                (indent-tabs-mode nil)
-                (show-trailing-whitespace t)
+                (indent-tabs-mode nil)
+                (show-trailing-whitespace t)
                 (c-offsets-alist
                  (statement-cont . (c-lineup-assignments +)))
                 )
Simple merge
@@@ -431,13 -377,9 +431,13 @@@ OBJS-$(CONFIG_TTA_DECODER)             
  OBJS-$(CONFIG_TWINVQ_DECODER)          += twinvq.o celp_math.o
  OBJS-$(CONFIG_TXD_DECODER)             += txd.o s3tc.o
  OBJS-$(CONFIG_ULTI_DECODER)            += ulti.o
- OBJS-$(CONFIG_UTVIDEO_DECODER)         += utvideo.o
+ OBJS-$(CONFIG_UTVIDEO_DECODER)         += utvideodec.o
  OBJS-$(CONFIG_V210_DECODER)            += v210dec.o
  OBJS-$(CONFIG_V210_ENCODER)            += v210enc.o
 +OBJS-$(CONFIG_V308_DECODER)            += v308dec.o
 +OBJS-$(CONFIG_V308_ENCODER)            += v308enc.o
 +OBJS-$(CONFIG_V408_DECODER)            += v408dec.o
 +OBJS-$(CONFIG_V408_ENCODER)            += v408enc.o
  OBJS-$(CONFIG_V410_DECODER)            += v410dec.o
  OBJS-$(CONFIG_V410_ENCODER)            += v410enc.o
  OBJS-$(CONFIG_V210X_DECODER)           += v210x.o
Simple merge
@@@ -27,7 -27,7 +27,8 @@@
  #define  OPJ_STATIC
  #include <openjpeg.h>
  
 +#include "libavutil/avassert.h"
+ #include "libavutil/common.h"
  #include "libavutil/imgutils.h"
  #include "libavutil/intreadwrite.h"
  #include "libavutil/opt.h"
Simple merge
Simple merge
Simple merge
@@@ -247,16 -242,11 +248,17 @@@ int ff_mjpeg_decode_sof(MJpegDecodeCont
      if (nb_components <= 0 ||
          nb_components > MAX_COMPONENTS)
          return -1;
 +    if (s->interlaced && (s->bottom_field == !s->interlace_polarity)) {
 +        if (nb_components != s->nb_components) {
 +            av_log(s->avctx, AV_LOG_ERROR, "nb_components changing in interlaced picture\n");
 +            return AVERROR_INVALIDDATA;
 +        }
 +    }
      if (s->ls && !(s->bits <= 8 || nb_components == 1)) {
-         av_log(s->avctx, AV_LOG_ERROR,
-                "only <= 8 bits/component or 16-bit gray accepted for JPEG-LS\n");
-         return -1;
+         av_log_missing_feature(s->avctx,
+                                "only <= 8 bits/component or "
+                                "16-bit gray accepted for JPEG-LS\n", 0);
+         return AVERROR_PATCHWELCOME;
      }
      s->nb_components = nb_components;
      s->h_max         = 1;
              s->h_max = s->h_count[i];
          if (s->v_count[i] > s->v_max)
              s->v_max = s->v_count[i];
 +        if (!s->h_count[i] || !s->v_count[i]) {
 +            av_log(s->avctx, AV_LOG_ERROR, "h/v_count is 0\n");
 +            return -1;
 +        }
          s->quant_index[i] = get_bits(&s->gb, 8);
          if (s->quant_index[i] >= 4)
-             return -1;
+             return AVERROR_INVALIDDATA;
          av_log(s->avctx, AV_LOG_DEBUG, "component %d %d:%d id: %d quant:%d\n",
                 i, s->h_count[i], s->v_count[i],
                 s->component_id[i], s->quant_index[i]);
      }
  
      if (s->ls && (s->h_max > 1 || s->v_max > 1)) {
-         av_log(s->avctx, AV_LOG_ERROR,
-                "Subsampling in JPEG-LS is not supported.\n");
-         return -1;
+         av_log_missing_feature(s->avctx,
+                                "Subsampling in JPEG-LS is not supported.\n", 0);
+         return AVERROR_PATCHWELCOME;
      }
  
 -    if (s->v_max == 1 && s->h_max == 1 && s->lossless == 1)
 +    if (s->v_max == 1 && s->h_max == 1 && s->lossless==1 && nb_components==3)
          s->rgb = 1;
  
      /* if different size, realloc/alloc picture */
          break;
      default:
          av_log(s->avctx, AV_LOG_ERROR, "Unhandled pixel format 0x%x\n", pix_fmt_id);
-         return -1;
+         return AVERROR_PATCHWELCOME;
      }
 +    if ((s->upscale_h || s->upscale_v) && s->avctx->lowres) {
 +        av_log(s->avctx, AV_LOG_ERROR, "lowres not supported for weird subsampling\n");
 +        return AVERROR_PATCHWELCOME;
 +    }
      if (s->ls) {
 +        s->upscale_h = s->upscale_v = 0;
          if (s->nb_components > 1)
              s->avctx->pix_fmt = PIX_FMT_RGB24;
          else if (s->bits <= 8)
@@@ -1124,12 -974,18 +1126,12 @@@ static int mjpeg_decode_scan_progressiv
                  if (ret < 0) {
                      av_log(s->avctx, AV_LOG_ERROR,
                             "error y=%d x=%d\n", mb_y, mb_x);
-                     return -1;
+                     return AVERROR_INVALIDDATA;
                  }
 -            }
  
              if (last_scan) {
 -                if (copy_mb) {
 -                    copy_block8(ptr, reference_data + block_offset,
 -                                linesize, linesize, 8);
 -                } else {
                      s->dsp.idct_put(ptr, linesize, *block);
 -                    ptr += 8;
 -                }
 +                    ptr += 8 >> s->avctx->lowres;
              }
          }
      }
@@@ -1243,42 -1084,35 +1245,45 @@@ next_field
  //            for () {
  //            reset_ls_coding_parameters(s, 0);
  
-             if (ff_jpegls_decode_picture(s, predictor, point_transform, ilv) < 0)
-                 return -1;
+             if ((ret = ff_jpegls_decode_picture(s, predictor,
+                                                 point_transform, ilv)) < 0)
+                 return ret;
          } else {
              if (s->rgb) {
-                 if (ljpeg_decode_rgb_scan(s, nb_components, predictor, point_transform) < 0)
-                     return -1;
 -                if ((ret = ljpeg_decode_rgb_scan(s, predictor,
 -                                                 point_transform)) < 0)
++                if ((ret = ljpeg_decode_rgb_scan(s, nb_components, predictor, point_transform)) < 0)
+                     return ret;
              } else {
-                 if (ljpeg_decode_yuv_scan(s, predictor, point_transform) < 0)
-                     return -1;
 -                if ((ret = ljpeg_decode_yuv_scan(s, predictor,
 -                                                 point_transform)) < 0)
++                if ((ret = ljpeg_decode_yuv_scan(s, predictor, point_transform)) < 0)
+                     return ret;
              }
          }
      } else {
          if (s->progressive && predictor) {
-             if (mjpeg_decode_scan_progressive_ac(s, predictor, ilv, prev_shift,
-                                                  point_transform) < 0)
-                 return -1;
 +            av_assert0(s->picture_ptr == &s->picture);
 -                                                        point_transform,
 -                                                        mb_bitmask,
 -                                                        reference)) < 0)
+             if ((ret = mjpeg_decode_scan_progressive_ac(s, predictor,
+                                                         ilv, prev_shift,
++                                                        point_transform)) < 0)
+                 return ret;
          } else {
-             if (mjpeg_decode_scan(s, nb_components, prev_shift, point_transform,
-                                   mb_bitmask, reference) < 0)
-                 return -1;
+             if ((ret = mjpeg_decode_scan(s, nb_components,
+                                          prev_shift, point_transform,
+                                          mb_bitmask, reference)) < 0)
+                 return ret;
          }
      }
 +    if(s->interlaced && get_bits_left(&s->gb) > 32 && show_bits(&s->gb, 8) == 0xFF) {
 +        GetBitContext bak= s->gb;
 +        align_get_bits(&bak);
 +        if(show_bits(&bak, 16) == 0xFFD1) {
 +            av_log(s->avctx, AV_LOG_DEBUG, "AVRn ingterlaced picture\n");
 +            s->gb = bak;
 +            skip_bits(&s->gb, 16);
 +            s->bottom_field ^= 1;
 +
 +            goto next_field;
 +        }
 +    }
 +
      emms_c();
      return 0;
   out_of_range:
@@@ -1595,7 -1436,7 +1600,8 @@@ int ff_mjpeg_decode_frame(AVCodecContex
      const uint8_t *unescaped_buf_ptr;
      int unescaped_buf_size;
      int start_code;
 +    int i, index;
+     int ret = 0;
      AVFrame *picture = data;
  
      s->got_picture = 0; // picture from previous image can not be reused
                  s->lossless    = 1;
                  s->ls          = 1;
                  s->progressive = 0;
-                 if (ff_mjpeg_decode_sof(s) < 0)
-                     return -1;
+                 if ((ret = ff_mjpeg_decode_sof(s)) < 0)
+                     return ret;
                  break;
              case LSE:
-                 if (!CONFIG_JPEGLS_DECODER || ff_jpegls_decode_lse(s) < 0)
-                     return -1;
+                 if (!CONFIG_JPEGLS_DECODER ||
+                     (ret = ff_jpegls_decode_lse(s)) < 0)
+                     return ret;
                  break;
              case EOI:
 -                s->cur_scan = 0;
 -                if ((s->buggy_avid && !s->interlaced) || s->restart_interval)
 -                    break;
  eoi_parser:
 +                s->cur_scan = 0;
                  if (!s->got_picture) {
                      av_log(avctx, AV_LOG_WARNING,
                             "Found EOI before any SOF, ignoring\n");
  
                  goto the_end;
              case SOS:
-                 if (ff_mjpeg_decode_sos(s, NULL, NULL) < 0 &&
 -                if (!s->got_picture) {
 -                    av_log(avctx, AV_LOG_WARNING,
 -                           "Can not process SOS before SOF, skipping\n");
 -                    break;
 -                    }
+                 if ((ret = ff_mjpeg_decode_sos(s, NULL, NULL)) < 0 &&
                      (avctx->err_recognition & AV_EF_EXPLODE))
-                     return AVERROR_INVALIDDATA;
+                     return ret;
 -                /* buggy avid puts EOI every 10-20th frame */
 -                /* if restart period is over process EOI */
 -                if ((s->buggy_avid && !s->interlaced) || s->restart_interval)
 -                    goto eoi_parser;
                  break;
              case DRI:
                  mjpeg_decode_dri(s);
          goto eoi_parser;
      }
      av_log(avctx, AV_LOG_FATAL, "No JPEG data found in image\n");
-     return -1;
+     return AVERROR_INVALIDDATA;
  the_end:
 -    av_log(avctx, AV_LOG_DEBUG, "mjpeg decode frame unused %td bytes\n",
 +    if (s->upscale_h) {
 +        uint8_t *line = s->picture_ptr->data[s->upscale_h];
 +        av_assert0(avctx->pix_fmt == PIX_FMT_YUVJ444P ||
 +                   avctx->pix_fmt == PIX_FMT_YUV444P  ||
 +                   avctx->pix_fmt == PIX_FMT_YUVJ440P ||
 +                   avctx->pix_fmt == PIX_FMT_YUV440P);
 +        for (i = 0; i < s->chroma_height; i++) {
 +            for (index = s->width - 1; index; index--)
 +                line[index] = (line[index / 2] + line[(index + 1) / 2]) >> 1;
 +            line += s->linesize[s->upscale_h];
 +        }
 +    }
 +    if (s->upscale_v) {
 +        uint8_t *dst = &((uint8_t *)s->picture_ptr->data[s->upscale_v])[(s->height - 1) * s->linesize[s->upscale_v]];
 +        av_assert0(avctx->pix_fmt == PIX_FMT_YUVJ444P ||
 +                   avctx->pix_fmt == PIX_FMT_YUV444P  ||
 +                   avctx->pix_fmt == PIX_FMT_YUVJ422P ||
 +                   avctx->pix_fmt == PIX_FMT_YUV422P);
 +        for (i = s->height - 1; i; i--) {
 +            uint8_t *src1 = &((uint8_t *)s->picture_ptr->data[s->upscale_v])[i / 2 * s->linesize[s->upscale_v]];
 +            uint8_t *src2 = &((uint8_t *)s->picture_ptr->data[s->upscale_v])[(i + 1) / 2 * s->linesize[s->upscale_v]];
 +            if (src1 == src2) {
 +                memcpy(dst, src1, s->width);
 +            } else {
 +                for (index = 0; index < s->width; index++)
 +                    dst[index] = (src1[index] + src2[index]) >> 1;
 +            }
 +            dst -= s->linesize[s->upscale_v];
 +        }
 +    }
 +    av_log(avctx, AV_LOG_DEBUG, "decode frame unused %td bytes\n",
             buf_end - buf_ptr);
  //  return buf_end - buf_ptr;
      return buf_ptr - buf;
index 0000000,27980d8..ac1c5fe
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,591 +1,589 @@@
 - * This file is part of Libav.
+ /*
+  * Ut Video decoder
+  * Copyright (c) 2011 Konstantin Shishkov
+  *
 - * Libav is free software; you can redistribute it and/or
++ * This file is part of FFmpeg.
+  *
 - * Libav is distributed in the hope that it will be useful,
++ * 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.
+  *
 - * License along with Libav; if not, write to the Free Software
++ * 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
 -    c->pic.reference = 1;
++ * License along with FFmpeg; if not, write to the Free Software
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+  */
+ /**
+  * @file
+  * Ut Video decoder
+  */
+ #include <stdlib.h>
+ #include "libavutil/intreadwrite.h"
+ #include "avcodec.h"
+ #include "bytestream.h"
+ #include "get_bits.h"
+ #include "dsputil.h"
+ #include "thread.h"
+ enum {
+     PRED_NONE = 0,
+     PRED_LEFT,
+     PRED_GRADIENT,
+     PRED_MEDIAN,
+ };
+ typedef struct UtvideoContext {
+     AVCodecContext *avctx;
+     AVFrame pic;
+     DSPContext dsp;
+     uint32_t frame_info_size, flags, frame_info;
+     int planes;
+     int slices;
+     int compression;
+     int interlaced;
+     int frame_pred;
+     uint8_t *slice_bits;
+     int slice_bits_size;
+ } UtvideoContext;
+ typedef struct HuffEntry {
+     uint8_t sym;
+     uint8_t len;
+ } HuffEntry;
+ static int huff_cmp(const void *a, const void *b)
+ {
+     const HuffEntry *aa = a, *bb = b;
+     return (aa->len - bb->len)*256 + aa->sym - bb->sym;
+ }
+ static int build_huff(const uint8_t *src, VLC *vlc, int *fsym)
+ {
+     int i;
+     HuffEntry he[256];
+     int last;
+     uint32_t codes[256];
+     uint8_t bits[256];
+     uint8_t syms[256];
+     uint32_t code;
+     *fsym = -1;
+     for (i = 0; i < 256; i++) {
+         he[i].sym = i;
+         he[i].len = *src++;
+     }
+     qsort(he, 256, sizeof(*he), huff_cmp);
+     if (!he[0].len) {
+         *fsym = he[0].sym;
+         return 0;
+     }
+     if (he[0].len > 32)
+         return -1;
+     last = 255;
+     while (he[last].len == 255 && last)
+         last--;
+     code = 1;
+     for (i = last; i >= 0; i--) {
+         codes[i] = code >> (32 - he[i].len);
+         bits[i]  = he[i].len;
+         syms[i]  = he[i].sym;
+         code += 0x80000000u >> (he[i].len - 1);
+     }
+     return ff_init_vlc_sparse(vlc, FFMIN(he[last].len, 9), last + 1,
+                               bits,  sizeof(*bits),  sizeof(*bits),
+                               codes, sizeof(*codes), sizeof(*codes),
+                               syms,  sizeof(*syms),  sizeof(*syms), 0);
+ }
+ static int decode_plane(UtvideoContext *c, int plane_no,
+                         uint8_t *dst, int step, int stride,
+                         int width, int height,
+                         const uint8_t *src, int use_pred)
+ {
+     int i, j, slice, pix;
+     int sstart, send;
+     VLC vlc;
+     GetBitContext gb;
+     int prev, fsym;
+     const int cmask = ~(!plane_no && c->avctx->pix_fmt == PIX_FMT_YUV420P);
+     if (build_huff(src, &vlc, &fsym)) {
+         av_log(c->avctx, AV_LOG_ERROR, "Cannot build Huffman codes\n");
+         return AVERROR_INVALIDDATA;
+     }
+     if (fsym >= 0) { // build_huff reported a symbol to fill slices with
+         send = 0;
+         for (slice = 0; slice < c->slices; slice++) {
+             uint8_t *dest;
+             sstart = send;
+             send   = (height * (slice + 1) / c->slices) & cmask;
+             dest   = dst + sstart * stride;
+             prev = 0x80;
+             for (j = sstart; j < send; j++) {
+                 for (i = 0; i < width * step; i += step) {
+                     pix = fsym;
+                     if (use_pred) {
+                         prev += pix;
+                         pix   = prev;
+                     }
+                     dest[i] = pix;
+                 }
+                 dest += stride;
+             }
+         }
+         return 0;
+     }
+     src      += 256;
+     send = 0;
+     for (slice = 0; slice < c->slices; slice++) {
+         uint8_t *dest;
+         int slice_data_start, slice_data_end, slice_size;
+         sstart = send;
+         send   = (height * (slice + 1) / c->slices) & cmask;
+         dest   = dst + sstart * stride;
+         // slice offset and size validation was done earlier
+         slice_data_start = slice ? AV_RL32(src + slice * 4 - 4) : 0;
+         slice_data_end   = AV_RL32(src + slice * 4);
+         slice_size       = slice_data_end - slice_data_start;
+         if (!slice_size) {
+             for (j = sstart; j < send; j++) {
+                 for (i = 0; i < width * step; i += step)
+                     dest[i] = 0x80;
+                 dest += stride;
+             }
+             continue;
+         }
+         memcpy(c->slice_bits, src + slice_data_start + c->slices * 4,
+                slice_size);
+         memset(c->slice_bits + slice_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+         c->dsp.bswap_buf((uint32_t *) c->slice_bits, (uint32_t *) c->slice_bits,
+                          (slice_data_end - slice_data_start + 3) >> 2);
+         init_get_bits(&gb, c->slice_bits, slice_size * 8);
+         prev = 0x80;
+         for (j = sstart; j < send; j++) {
+             for (i = 0; i < width * step; i += step) {
+                 if (get_bits_left(&gb) <= 0) {
+                     av_log(c->avctx, AV_LOG_ERROR,
+                            "Slice decoding ran out of bits\n");
+                     goto fail;
+                 }
+                 pix = get_vlc2(&gb, vlc.table, vlc.bits, 4);
+                 if (pix < 0) {
+                     av_log(c->avctx, AV_LOG_ERROR, "Decoding error\n");
+                     goto fail;
+                 }
+                 if (use_pred) {
+                     prev += pix;
+                     pix   = prev;
+                 }
+                 dest[i] = pix;
+             }
+             dest += stride;
+         }
+         if (get_bits_left(&gb) > 32)
+             av_log(c->avctx, AV_LOG_WARNING,
+                    "%d bits left after decoding slice\n", get_bits_left(&gb));
+     }
+     ff_free_vlc(&vlc);
+     return 0;
+ fail:
+     ff_free_vlc(&vlc);
+     return AVERROR_INVALIDDATA;
+ }
+ static const int rgb_order[4] = { 1, 2, 0, 3 };
+ static void restore_rgb_planes(uint8_t *src, int step, int stride, int width,
+                                int height)
+ {
+     int i, j;
+     uint8_t r, g, b;
+     for (j = 0; j < height; j++) {
+         for (i = 0; i < width * step; i += step) {
+             r = src[i];
+             g = src[i + 1];
+             b = src[i + 2];
+             src[i]     = r + g - 0x80;
+             src[i + 2] = b + g - 0x80;
+         }
+         src += stride;
+     }
+ }
+ static void restore_median(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;
+     for (slice = 0; slice < slices; slice++) {
+         slice_start  = ((slice * height) / slices) & cmask;
+         slice_height = ((((slice + 1) * height) / slices) & cmask) -
+                        slice_start;
+         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;
+         // second line - first element has top prediction, the rest uses median
+         C        = bsrc[-stride];
+         bsrc[0] += C;
+         A        = bsrc[0];
+         for (i = step; i < width * step; i += step) {
+             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++) {
+             for (i = 0; i < width * step; i += step) {
+                 B        = bsrc[i - stride];
+                 bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C));
+                 C        = B;
+                 A        = bsrc[i];
+             }
+             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_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 prediction, 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;
+     int buf_size = avpkt->size;
+     UtvideoContext *c = avctx->priv_data;
+     int i, j;
+     const uint8_t *plane_start[5];
+     int plane_size, max_slice_size = 0, slice_start, slice_end, slice_size;
+     int ret;
+     GetByteContext gb;
+     if (c->pic.data[0])
+         ff_thread_release_buffer(avctx, &c->pic);
 -    ff_thread_finish_setup(avctx);
 -
++    c->pic.reference = 3;
+     c->pic.buffer_hints = FF_BUFFER_HINTS_VALID;
+     if ((ret = ff_thread_get_buffer(avctx, &c->pic)) < 0) {
+         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+         return ret;
+     }
+     /* parse plane structure to get frame flags and validate slice offsets */
+     bytestream2_init(&gb, buf, buf_size);
+     for (i = 0; i < c->planes; i++) {
+         plane_start[i] = gb.buffer;
+         if (bytestream2_get_bytes_left(&gb) < 256 + 4 * c->slices) {
+             av_log(avctx, AV_LOG_ERROR, "Insufficient data for a plane\n");
+             return AVERROR_INVALIDDATA;
+         }
+         bytestream2_skipu(&gb, 256);
+         slice_start = 0;
+         slice_end   = 0;
+         for (j = 0; j < c->slices; j++) {
+             slice_end   = bytestream2_get_le32u(&gb);
+             slice_size  = slice_end - slice_start;
+             if (slice_end <= 0 || slice_size <= 0 ||
+                 bytestream2_get_bytes_left(&gb) < slice_end) {
+                 av_log(avctx, AV_LOG_ERROR, "Incorrect slice size\n");
+                 return AVERROR_INVALIDDATA;
+             }
+             slice_start = slice_end;
+             max_slice_size = FFMAX(max_slice_size, slice_size);
+         }
+         plane_size = slice_end;
+         bytestream2_skipu(&gb, plane_size);
+     }
+     plane_start[c->planes] = gb.buffer;
+     if (bytestream2_get_bytes_left(&gb) < c->frame_info_size) {
+         av_log(avctx, AV_LOG_ERROR, "Not enough data for frame information\n");
+         return AVERROR_INVALIDDATA;
+     }
+     c->frame_info = bytestream2_get_le32u(&gb);
+     av_log(avctx, AV_LOG_DEBUG, "frame information flags %X\n", c->frame_info);
+     c->frame_pred = (c->frame_info >> 8) & 3;
+     if (c->frame_pred == PRED_GRADIENT) {
+         av_log_ask_for_sample(avctx, "Frame uses gradient prediction\n");
+         return AVERROR_PATCHWELCOME;
+     }
+     av_fast_malloc(&c->slice_bits, &c->slice_bits_size,
+                    max_slice_size + FF_INPUT_BUFFER_PADDING_SIZE);
+     if (!c->slice_bits) {
+         av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer\n");
+         return AVERROR(ENOMEM);
+     }
+     switch (c->avctx->pix_fmt) {
+     case PIX_FMT_RGB24:
+     case PIX_FMT_RGBA:
+         for (i = 0; i < c->planes; i++) {
+             ret = decode_plane(c, i, c->pic.data[0] + rgb_order[i], c->planes,
+                                c->pic.linesize[0], avctx->width, avctx->height,
+                                plane_start[i], c->frame_pred == PRED_LEFT);
+             if (ret)
+                 return ret;
+             if (c->frame_pred == PRED_MEDIAN) {
+                 if (!c->interlaced) {
+                     restore_median(c->pic.data[0] + rgb_order[i], c->planes,
+                                    c->pic.linesize[0], avctx->width,
+                                    avctx->height, c->slices, 0);
+                 } else {
+                     restore_median_il(c->pic.data[0] + rgb_order[i], c->planes,
+                                       c->pic.linesize[0], avctx->width,
+                                       avctx->height, c->slices, 0);
+                 }
+             }
+         }
+         restore_rgb_planes(c->pic.data[0], c->planes, c->pic.linesize[0],
+                            avctx->width, avctx->height);
+         break;
+     case PIX_FMT_YUV420P:
+         for (i = 0; i < 3; i++) {
+             ret = decode_plane(c, i, c->pic.data[i], 1, c->pic.linesize[i],
+                                avctx->width >> !!i, avctx->height >> !!i,
+                                plane_start[i], c->frame_pred == PRED_LEFT);
+             if (ret)
+                 return ret;
+             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:
+         for (i = 0; i < 3; i++) {
+             ret = decode_plane(c, i, c->pic.data[i], 1, c->pic.linesize[i],
+                                avctx->width >> !!i, avctx->height,
+                                plane_start[i], c->frame_pred == PRED_LEFT);
+             if (ret)
+                 return ret;
+             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;
+     }
+     c->pic.key_frame = 1;
+     c->pic.pict_type = AV_PICTURE_TYPE_I;
+     c->pic.interlaced_frame = !!c->interlaced;
+     *data_size = sizeof(AVFrame);
+     *(AVFrame*)data = c->pic;
+     /* always report that the buffer was completely consumed */
+     return buf_size;
+ }
+ static av_cold int decode_init(AVCodecContext *avctx)
+ {
+     UtvideoContext * const c = avctx->priv_data;
+     c->avctx = avctx;
+     ff_dsputil_init(&c->dsp, avctx);
+     if (avctx->extradata_size < 16) {
+         av_log(avctx, AV_LOG_ERROR,
+                "Insufficient extradata size %d, should be at least 16\n",
+                avctx->extradata_size);
+         return AVERROR_INVALIDDATA;
+     }
+     av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n",
+            avctx->extradata[3], avctx->extradata[2],
+            avctx->extradata[1], avctx->extradata[0]);
+     av_log(avctx, AV_LOG_DEBUG, "Original format %X\n",
+            AV_RB32(avctx->extradata + 4));
+     c->frame_info_size = AV_RL32(avctx->extradata + 8);
+     c->flags           = AV_RL32(avctx->extradata + 12);
+     if (c->frame_info_size != 4)
+         av_log_ask_for_sample(avctx, "Frame info is not 4 bytes\n");
+     av_log(avctx, AV_LOG_DEBUG, "Encoding parameters %08X\n", c->flags);
+     c->slices      = (c->flags >> 24) + 1;
+     c->compression = c->flags & 1;
+     c->interlaced  = c->flags & 0x800;
+     c->slice_bits_size = 0;
+     switch (avctx->codec_tag) {
+     case MKTAG('U', 'L', 'R', 'G'):
+         c->planes      = 3;
+         avctx->pix_fmt = PIX_FMT_RGB24;
+         break;
+     case MKTAG('U', 'L', 'R', 'A'):
+         c->planes      = 4;
+         avctx->pix_fmt = PIX_FMT_RGBA;
+         break;
+     case MKTAG('U', 'L', 'Y', '0'):
+         c->planes      = 3;
+         avctx->pix_fmt = PIX_FMT_YUV420P;
+         break;
+     case MKTAG('U', 'L', 'Y', '2'):
+         c->planes      = 3;
+         avctx->pix_fmt = PIX_FMT_YUV422P;
+         break;
+     default:
+         av_log(avctx, AV_LOG_ERROR, "Unknown Ut Video FOURCC provided (%08X)\n",
+                avctx->codec_tag);
+         return AVERROR_INVALIDDATA;
+     }
+     return 0;
+ }
+ static av_cold int decode_end(AVCodecContext *avctx)
+ {
+     UtvideoContext * const c = avctx->priv_data;
+     if (c->pic.data[0])
+         ff_thread_release_buffer(avctx, &c->pic);
+     av_freep(&c->slice_bits);
+     return 0;
+ }
+ AVCodec ff_utvideo_decoder = {
+     .name           = "utvideo",
+     .type           = AVMEDIA_TYPE_VIDEO,
+     .id             = AV_CODEC_ID_UTVIDEO,
+     .priv_data_size = sizeof(UtvideoContext),
+     .init           = decode_init,
+     .close          = decode_end,
+     .decode         = decode_frame,
+     .capabilities   = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS,
+     .long_name      = NULL_IF_CONFIG_SMALL("Ut Video"),
+ };
Simple merge
Simple merge
Simple merge
@@@ -30,8 -30,8 +30,8 @@@
  #include "libavutil/avutil.h"
  
  #define LIBAVFORMAT_VERSION_MAJOR 54
- #define LIBAVFORMAT_VERSION_MINOR 24
- #define LIBAVFORMAT_VERSION_MICRO 101
 -#define LIBAVFORMAT_VERSION_MINOR 14
 -#define LIBAVFORMAT_VERSION_MICRO  0
++#define LIBAVFORMAT_VERSION_MINOR 25
++#define LIBAVFORMAT_VERSION_MICRO 100
  
  #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
                                                 LIBAVFORMAT_VERSION_MINOR, \