]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/mpegvideo.c
avfilter/vf_psnr: remove unnecessary check
[ffmpeg] / libavcodec / mpegvideo.c
index 60ed716865ba26a3f74bbefcd0f56f963b6507a7..5de0719f831440795f100e0be564b1148bb2e604 100644 (file)
@@ -32,6 +32,8 @@
 #include "libavutil/imgutils.h"
 #include "libavutil/internal.h"
 #include "libavutil/motion_vector.h"
+#include "libavutil/video_enc_params.h"
+
 #include "avcodec.h"
 #include "blockdsp.h"
 #include "h264chroma.h"
@@ -364,13 +366,6 @@ static int init_duplicate_context(MpegEncContext *s)
     if (s->mb_height & 1)
         yc_size += 2*s->b8_stride + 2*s->mb_stride;
 
-    s->sc.edge_emu_buffer =
-    s->me.scratchpad   =
-    s->me.temp         =
-    s->sc.rd_scratchpad   =
-    s->sc.b_scratchpad    =
-    s->sc.obmc_scratchpad = NULL;
-
     if (s->encoding) {
         if (!FF_ALLOCZ_TYPED_ARRAY(s->me.map,       ME_MAP_SIZE) ||
             !FF_ALLOCZ_TYPED_ARRAY(s->me.score_map, ME_MAP_SIZE))
@@ -411,6 +406,35 @@ static int init_duplicate_context(MpegEncContext *s)
     return 0;
 }
 
+/**
+ * Initialize an MpegEncContext's thread contexts. Presumes that
+ * slice_context_count is already set and that all the fields
+ * that are freed/reset in free_duplicate_context() are NULL.
+ */
+static int init_duplicate_contexts(MpegEncContext *s)
+{
+    int nb_slices = s->slice_context_count, ret;
+
+    /* We initialize the copies before the original so that
+     * fields allocated in init_duplicate_context are NULL after
+     * copying. This prevents double-frees upon allocation error. */
+    for (int i = 1; i < nb_slices; i++) {
+        s->thread_context[i] = av_memdup(s, sizeof(MpegEncContext));
+        if (!s->thread_context[i])
+            return AVERROR(ENOMEM);
+        if ((ret = init_duplicate_context(s->thread_context[i])) < 0)
+            return ret;
+        s->thread_context[i]->start_mb_y =
+            (s->mb_height * (i    ) + nb_slices / 2) / nb_slices;
+        s->thread_context[i]->end_mb_y   =
+            (s->mb_height * (i + 1) + nb_slices / 2) / nb_slices;
+    }
+    s->start_mb_y = 0;
+    s->end_mb_y   = nb_slices > 1 ? (s->mb_height + nb_slices / 2) / nb_slices
+                                  : s->mb_height;
+    return init_duplicate_context(s);
+}
+
 static void free_duplicate_context(MpegEncContext *s)
 {
     if (!s)
@@ -433,6 +457,15 @@ static void free_duplicate_context(MpegEncContext *s)
     s->block = NULL;
 }
 
+static void free_duplicate_contexts(MpegEncContext *s)
+{
+    for (int i = 1; i < s->slice_context_count; i++) {
+        free_duplicate_context(s->thread_context[i]);
+        av_freep(&s->thread_context[i]);
+    }
+    free_duplicate_context(s);
+}
+
 static void backup_duplicate_context(MpegEncContext *bak, MpegEncContext *src)
 {
 #define COPY(a) bak->a = src->a
@@ -522,7 +555,6 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst,
     }
 
     if (s->height != s1->height || s->width != s1->width || s->context_reinit) {
-        s->context_reinit = 0;
         s->height = s1->height;
         s->width  = s1->width;
         if ((ret = ff_mpv_common_frame_size_change(s)) < 0)
@@ -930,53 +962,42 @@ av_cold int ff_mpv_common_init(MpegEncContext *s)
     for (i = 0; i < MAX_PICTURE_COUNT; i++) {
         s->picture[i].f = av_frame_alloc();
         if (!s->picture[i].f)
-            return AVERROR(ENOMEM);
+            goto fail_nomem;
     }
 
     if (!(s->next_picture.f    = av_frame_alloc()) ||
         !(s->last_picture.f    = av_frame_alloc()) ||
         !(s->current_picture.f = av_frame_alloc()) ||
         !(s->new_picture.f     = av_frame_alloc()))
-        return AVERROR(ENOMEM);
+        goto fail_nomem;
 
     if ((ret = init_context_frame(s)))
-        return AVERROR(ENOMEM);
+        goto fail;
 
     s->parse_context.state = -1;
 
     s->context_initialized = 1;
     memset(s->thread_context, 0, sizeof(s->thread_context));
     s->thread_context[0]   = s;
+    s->slice_context_count = nb_slices;
 
 //     if (s->width && s->height) {
-    if (nb_slices > 1) {
-        for (i = 0; i < nb_slices; i++) {
-            if (i) {
-                s->thread_context[i] = av_memdup(s, sizeof(MpegEncContext));
-                if (!s->thread_context[i])
-                    return AVERROR(ENOMEM);
-            }
-            if ((ret = init_duplicate_context(s->thread_context[i])) < 0)
-                return ret;
-            s->thread_context[i]->start_mb_y =
-                (s->mb_height * (i) + nb_slices / 2) / nb_slices;
-            s->thread_context[i]->end_mb_y   =
-                (s->mb_height * (i + 1) + nb_slices / 2) / nb_slices;
-        }
-    } else {
-        if ((ret = init_duplicate_context(s)) < 0)
-            return ret;
-        s->start_mb_y = 0;
-        s->end_mb_y   = s->mb_height;
-    }
-    s->slice_context_count = nb_slices;
+    ret = init_duplicate_contexts(s);
+    if (ret < 0)
+        goto fail;
 //     }
 
     return 0;
+ fail_nomem:
+    ret = AVERROR(ENOMEM);
+ fail:
+    ff_mpv_common_end(s);
+    return ret;
 }
 
 /**
- * Frees and resets MpegEncContext fields depending on the resolution.
+ * Frees and resets MpegEncContext fields depending on the resolution
+ * as well as the slice thread contexts.
  * Is used during resolution changes to avoid a full reinitialization of the
  * codec.
  */
@@ -984,6 +1005,8 @@ static void free_context_frame(MpegEncContext *s)
 {
     int i, j, k;
 
+    free_duplicate_contexts(s);
+
     av_freep(&s->mb_type);
     av_freep(&s->p_mv_table_base);
     av_freep(&s->b_forw_mv_table_base);
@@ -1036,16 +1059,6 @@ int ff_mpv_common_frame_size_change(MpegEncContext *s)
     if (!s->context_initialized)
         return AVERROR(EINVAL);
 
-    if (s->slice_context_count > 1) {
-        for (i = 0; i < s->slice_context_count; i++) {
-            free_duplicate_context(s->thread_context[i]);
-        }
-        for (i = 1; i < s->slice_context_count; i++) {
-            av_freep(&s->thread_context[i]);
-        }
-    } else
-        free_duplicate_context(s);
-
     free_context_frame(s);
 
     if (s->picture)
@@ -1065,42 +1078,33 @@ int ff_mpv_common_frame_size_change(MpegEncContext *s)
 
     if ((s->width || s->height) &&
         (err = av_image_check_size(s->width, s->height, 0, s->avctx)) < 0)
-        return err;
+        goto fail;
+
+    /* set chroma shifts */
+    err = av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt,
+                                           &s->chroma_x_shift,
+                                           &s->chroma_y_shift);
+    if (err < 0)
+        goto fail;
 
     if ((err = init_context_frame(s)))
-        return err;
+        goto fail;
 
     memset(s->thread_context, 0, sizeof(s->thread_context));
     s->thread_context[0]   = s;
 
     if (s->width && s->height) {
-        int nb_slices = s->slice_context_count;
-        if (nb_slices > 1) {
-            for (i = 0; i < nb_slices; i++) {
-                if (i) {
-                    s->thread_context[i] = av_memdup(s, sizeof(MpegEncContext));
-                    if (!s->thread_context[i]) {
-                        return AVERROR(ENOMEM);
-                    }
-                }
-                if ((err = init_duplicate_context(s->thread_context[i])) < 0)
-                    return err;
-                s->thread_context[i]->start_mb_y =
-                    (s->mb_height * (i) + nb_slices / 2) / nb_slices;
-                s->thread_context[i]->end_mb_y   =
-                    (s->mb_height * (i + 1) + nb_slices / 2) / nb_slices;
-            }
-        } else {
-            err = init_duplicate_context(s);
-            if (err < 0)
-                return err;
-            s->start_mb_y = 0;
-            s->end_mb_y   = s->mb_height;
-        }
-        s->slice_context_count = nb_slices;
+        err = init_duplicate_contexts(s);
+        if (err < 0)
+            goto fail;
     }
+    s->context_reinit = 0;
 
     return 0;
+ fail:
+    free_context_frame(s);
+    s->context_reinit = 1;
+    return err;
 }
 
 /* init common structure for both encoder and decoder */
@@ -1111,15 +1115,9 @@ void ff_mpv_common_end(MpegEncContext *s)
     if (!s)
         return;
 
-    if (s->slice_context_count > 1) {
-        for (i = 0; i < s->slice_context_count; i++) {
-            free_duplicate_context(s->thread_context[i]);
-        }
-        for (i = 1; i < s->slice_context_count; i++) {
-            av_freep(&s->thread_context[i]);
-        }
+    free_context_frame(s);
+    if (s->slice_context_count > 1)
         s->slice_context_count = 1;
-    } else free_duplicate_context(s);
 
     av_freep(&s->parse_context.buffer);
     s->parse_context.buffer_size = 0;
@@ -1151,9 +1149,8 @@ void ff_mpv_common_end(MpegEncContext *s)
     ff_mpeg_unref_picture(s->avctx, &s->new_picture);
     av_frame_free(&s->new_picture.f);
 
-    free_context_frame(s);
-
     s->context_initialized      = 0;
+    s->context_reinit           = 0;
     s->last_picture_ptr         =
     s->next_picture_ptr         =
     s->current_picture_ptr      = NULL;
@@ -1422,14 +1419,33 @@ void ff_print_debug_info(MpegEncContext *s, Picture *p, AVFrame *pict)
 
 int ff_mpv_export_qp_table(MpegEncContext *s, AVFrame *f, Picture *p, int qp_type)
 {
-    AVBufferRef *ref = av_buffer_ref(p->qscale_table_buf);
-    int offset = 2*s->mb_stride + 1;
-    if(!ref)
+    AVVideoEncParams *par;
+    int mult = (qp_type == FF_QSCALE_TYPE_MPEG1) ? 2 : 1;
+    unsigned int nb_mb = p->alloc_mb_height * p->alloc_mb_width;
+    unsigned int x, y;
+
+    if (!(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_VIDEO_ENC_PARAMS))
+        return 0;
+
+    par = av_video_enc_params_create_side_data(f, AV_VIDEO_ENC_PARAMS_MPEG2, nb_mb);
+    if (!par)
         return AVERROR(ENOMEM);
-    av_assert0(ref->size >= offset + s->mb_stride * ((f->height+15)/16));
-    ref->size -= offset;
-    ref->data += offset;
-    return av_frame_set_qp_table(f, ref, s->mb_stride, qp_type);
+
+    for (y = 0; y < p->alloc_mb_height; y++)
+        for (x = 0; x < p->alloc_mb_width; x++) {
+            const unsigned int block_idx = y * p->alloc_mb_width + x;
+            const unsigned int     mb_xy = y * p->alloc_mb_stride + x;
+            AVVideoBlockParams *b = av_video_enc_params_block(par, block_idx);
+
+            b->src_x = x * 16;
+            b->src_y = y * 16;
+            b->w     = 16;
+            b->h     = 16;
+
+            b->delta_qp = p->qscale_table[mb_xy] * mult;
+        }
+
+    return 0;
 }
 
 static inline int hpel_motion_lowres(MpegEncContext *s,