Coverage Report

Created: 2026-01-16 07:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/mpegpicture.c
Line
Count
Source
1
/*
2
 * Mpeg video formats-related picture management functions
3
 *
4
 * This file is part of FFmpeg.
5
 *
6
 * FFmpeg is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * FFmpeg is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with FFmpeg; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 */
20
21
#include "libavutil/avassert.h"
22
#include "libavutil/common.h"
23
#include "libavutil/mem.h"
24
#include "libavutil/pixdesc.h"
25
#include "libavutil/imgutils.h"
26
27
#include "avcodec.h"
28
#include "mpegpicture.h"
29
#include "libavutil/refstruct.h"
30
31
static void mpv_pic_reset(AVRefStructOpaque unused, void *obj)
32
3.25M
{
33
3.25M
    MPVPicture *pic = obj;
34
35
3.25M
    av_frame_unref(pic->f);
36
3.25M
    ff_thread_progress_reset(&pic->progress);
37
38
3.25M
    av_refstruct_unref(&pic->hwaccel_picture_private);
39
40
3.25M
    av_refstruct_unref(&pic->mbskip_table);
41
3.25M
    av_refstruct_unref(&pic->qscale_table_base);
42
3.25M
    av_refstruct_unref(&pic->mb_type_base);
43
44
9.77M
    for (int i = 0; i < 2; i++) {
45
6.51M
        av_refstruct_unref(&pic->motion_val_base[i]);
46
6.51M
        av_refstruct_unref(&pic->ref_index[i]);
47
48
6.51M
        pic->motion_val[i] = NULL;
49
6.51M
    }
50
51
3.25M
    pic->mb_type                = NULL;
52
3.25M
    pic->qscale_table           = NULL;
53
54
3.25M
    pic->mb_stride =
55
3.25M
    pic->mb_width  =
56
3.25M
    pic->mb_height = 0;
57
58
3.25M
    pic->dummy                  = 0;
59
3.25M
    pic->field_picture          = 0;
60
3.25M
    pic->b_frame_score          = 0;
61
3.25M
    pic->reference              = 0;
62
3.25M
    pic->shared                 = 0;
63
3.25M
    pic->display_picture_number = 0;
64
3.25M
    pic->coded_picture_number   = 0;
65
3.25M
}
66
67
static int av_cold mpv_pic_init(AVRefStructOpaque opaque, void *obj)
68
224k
{
69
224k
    MPVPicture *pic = obj;
70
224k
    int ret, init_progress = (uintptr_t)opaque.nc;
71
72
224k
    ret = ff_thread_progress_init(&pic->progress, init_progress);
73
224k
    if (ret < 0)
74
0
        return ret;
75
76
224k
    pic->f = av_frame_alloc();
77
224k
    if (!pic->f)
78
0
        return AVERROR(ENOMEM);
79
224k
    return 0;
80
224k
}
81
82
static void av_cold mpv_pic_free(AVRefStructOpaque unused, void *obj)
83
224k
{
84
224k
    MPVPicture *pic = obj;
85
86
224k
    ff_thread_progress_destroy(&pic->progress);
87
224k
    av_frame_free(&pic->f);
88
224k
}
89
90
av_cold AVRefStructPool *ff_mpv_alloc_pic_pool(int init_progress)
91
127k
{
92
127k
    return av_refstruct_pool_alloc_ext(sizeof(MPVPicture),
93
127k
                                       AV_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR,
94
127k
                                       (void*)(uintptr_t)init_progress,
95
127k
                                       mpv_pic_init, mpv_pic_reset, mpv_pic_free, NULL);
96
127k
}
97
98
void ff_mpv_unref_picture(MPVWorkPicture *pic)
99
8.36M
{
100
8.36M
    av_refstruct_unref(&pic->ptr);
101
8.36M
    memset(pic, 0, sizeof(*pic));
102
8.36M
}
103
104
static void set_workpic_from_pic(MPVWorkPicture *wpic, const MPVPicture *pic)
105
7.79M
{
106
31.1M
    for (int i = 0; i < MPV_MAX_PLANES; i++) {
107
23.3M
        wpic->data[i]     = pic->f->data[i];
108
23.3M
        wpic->linesize[i] = pic->f->linesize[i];
109
23.3M
    }
110
7.79M
    wpic->qscale_table = pic->qscale_table;
111
7.79M
    wpic->mb_type      = pic->mb_type;
112
7.79M
    wpic->mbskip_table = pic->mbskip_table;
113
114
23.3M
    for (int i = 0; i < 2; i++) {
115
15.5M
        wpic->motion_val[i] = pic->motion_val[i];
116
15.5M
        wpic->ref_index[i]  = pic->ref_index[i];
117
15.5M
    }
118
7.79M
    wpic->reference  = pic->reference;
119
7.79M
}
120
121
void ff_mpv_replace_picture(MPVWorkPicture *dst, const MPVWorkPicture *src)
122
13.6k
{
123
13.6k
    av_assert1(dst != src);
124
13.6k
    av_refstruct_replace(&dst->ptr, src->ptr);
125
13.6k
    memcpy(dst, src, sizeof(*dst));
126
13.6k
}
127
128
void ff_mpv_workpic_from_pic(MPVWorkPicture *wpic, MPVPicture *pic)
129
5.22M
{
130
5.22M
    av_refstruct_replace(&wpic->ptr, pic);
131
5.22M
    if (!pic) {
132
648k
        memset(wpic, 0, sizeof(*wpic));
133
648k
        return;
134
648k
    }
135
4.57M
    set_workpic_from_pic(wpic, pic);
136
4.57M
}
137
138
int ff_mpv_framesize_alloc(AVCodecContext *avctx,
139
                           ScratchpadContext *sc, int linesize)
140
3.24M
{
141
3.24M
#   define EMU_EDGE_HEIGHT (4 * 70)
142
3.24M
    int linesizeabs = FFABS(linesize);
143
3.24M
    int alloc_size = FFALIGN(linesizeabs + 64, 32);
144
145
3.24M
    if (linesizeabs <= sc->linesize)
146
2.96M
        return 0;
147
148
283k
    if (avctx->hwaccel)
149
0
        return 0;
150
151
283k
    if (linesizeabs < 24) {
152
25.9k
        av_log(avctx, AV_LOG_ERROR, "Image too small, temporary buffers cannot function\n");
153
25.9k
        return AVERROR_PATCHWELCOME;
154
25.9k
    }
155
156
257k
    if (av_image_check_size2(alloc_size, EMU_EDGE_HEIGHT, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx) < 0)
157
4.54k
        return AVERROR(ENOMEM);
158
159
252k
    av_freep(&sc->edge_emu_buffer);
160
252k
    av_freep(&sc->scratchpad_buf);
161
162
    // edge emu needs blocksize + filter length - 1
163
    // (= 17x17 for  halfpel / 21x21 for H.264)
164
    // VC-1 computes luma and chroma simultaneously and needs 19X19 + 9x9
165
    // at uvlinesize. It supports only YUV420 so 24x24 is enough
166
    // linesize * interlaced * MBsize
167
    // we also use this buffer for encoding in encode_mb_internal() needig an additional 32 lines
168
252k
    if (!FF_ALLOCZ_TYPED_ARRAY(sc->edge_emu_buffer, alloc_size * EMU_EDGE_HEIGHT) ||
169
252k
        !FF_ALLOCZ_TYPED_ARRAY(sc->scratchpad_buf,  alloc_size * 4 * 16 * 2)) {
170
0
        sc->linesize = 0;
171
0
        av_freep(&sc->edge_emu_buffer);
172
0
        return AVERROR(ENOMEM);
173
0
    }
174
252k
    sc->linesize = linesizeabs;
175
176
252k
    sc->obmc_scratchpad = sc->scratchpad_buf + 16;
177
178
252k
    return 0;
179
252k
}
180
181
int ff_mpv_pic_check_linesize(void *logctx, const AVFrame *f,
182
                              ptrdiff_t *linesizep, ptrdiff_t *uvlinesizep)
183
3.25M
{
184
3.25M
    ptrdiff_t linesize = *linesizep, uvlinesize = *uvlinesizep;
185
186
3.25M
    if ((linesize   &&   linesize != f->linesize[0]) ||
187
3.24M
        (uvlinesize && uvlinesize != f->linesize[1])) {
188
354
        av_log(logctx, AV_LOG_ERROR, "Stride change unsupported: "
189
354
               "linesize=%td/%d uvlinesize=%td/%d)\n",
190
354
               linesize,   f->linesize[0],
191
354
               uvlinesize, f->linesize[1]);
192
354
        return AVERROR_PATCHWELCOME;
193
354
    }
194
195
3.24M
    if (av_pix_fmt_count_planes(f->format) > 2 &&
196
3.24M
        f->linesize[1] != f->linesize[2]) {
197
0
        av_log(logctx, AV_LOG_ERROR, "uv stride mismatch unsupported\n");
198
0
        return AVERROR_PATCHWELCOME;
199
0
    }
200
3.24M
    *linesizep   = f->linesize[0];
201
3.24M
    *uvlinesizep = f->linesize[1];
202
203
3.24M
    return 0;
204
3.24M
}
205
206
static int alloc_picture_tables(BufferPoolContext *pools, MPVPicture *pic,
207
                                int mb_height)
208
3.21M
{
209
16.2M
#define GET_BUFFER(name, buf_suffix, idx_suffix) do { \
210
16.2M
    pic->name ## buf_suffix idx_suffix = av_refstruct_pool_get(pools->name ## _pool); \
211
16.2M
    if (!pic->name ## buf_suffix idx_suffix) \
212
16.2M
        return AVERROR(ENOMEM); \
213
16.2M
} while (0)
214
3.21M
    GET_BUFFER(qscale_table, _base,);
215
3.21M
    GET_BUFFER(mb_type, _base,);
216
3.21M
    if (pools->motion_val_pool) {
217
2.40M
        if (pools->mbskip_table_pool)
218
191k
            GET_BUFFER(mbskip_table,,);
219
7.21M
        for (int i = 0; i < 2; i++) {
220
4.81M
            GET_BUFFER(ref_index,, [i]);
221
4.81M
            GET_BUFFER(motion_val, _base, [i]);
222
4.81M
            pic->motion_val[i] = pic->motion_val_base[i] + 4;
223
4.81M
        }
224
2.40M
    }
225
3.21M
#undef GET_BUFFER
226
227
3.21M
    pic->mb_width  = pools->alloc_mb_width;
228
3.21M
    pic->mb_height = mb_height;
229
3.21M
    pic->mb_stride = pools->alloc_mb_stride;
230
231
3.21M
    pic->qscale_table = pic->qscale_table_base + 2 * pic->mb_stride + 1;
232
3.21M
    pic->mb_type      = pic->mb_type_base      + 2 * pic->mb_stride + 1;
233
234
3.21M
    return 0;
235
3.21M
}
236
237
int ff_mpv_alloc_pic_accessories(AVCodecContext *avctx, MPVWorkPicture *wpic,
238
                                 ScratchpadContext *sc,
239
                                 BufferPoolContext *pools, int mb_height)
240
3.24M
{
241
3.24M
    MPVPicture *pic = wpic->ptr;
242
3.24M
    int ret;
243
244
3.24M
    ret = ff_mpv_framesize_alloc(avctx, sc, pic->f->linesize[0]);
245
3.24M
    if (ret < 0)
246
30.5k
        goto fail;
247
248
3.21M
    ret = alloc_picture_tables(pools, pic, mb_height);
249
3.21M
    if (ret < 0)
250
0
        goto fail;
251
252
3.21M
    set_workpic_from_pic(wpic, pic);
253
254
3.21M
    return 0;
255
30.5k
fail:
256
30.5k
    av_log(avctx, AV_LOG_ERROR, "Error allocating picture accessories.\n");
257
30.5k
    return ret;
258
3.21M
}