Coverage Report

Created: 2026-02-14 06:59

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.14M
{
33
3.14M
    MPVPicture *pic = obj;
34
35
3.14M
    av_frame_unref(pic->f);
36
3.14M
    ff_thread_progress_reset(&pic->progress);
37
38
3.14M
    av_refstruct_unref(&pic->hwaccel_picture_private);
39
40
3.14M
    av_refstruct_unref(&pic->mbskip_table);
41
3.14M
    av_refstruct_unref(&pic->qscale_table_base);
42
3.14M
    av_refstruct_unref(&pic->mb_type_base);
43
44
9.43M
    for (int i = 0; i < 2; i++) {
45
6.29M
        av_refstruct_unref(&pic->motion_val_base[i]);
46
6.29M
        av_refstruct_unref(&pic->ref_index[i]);
47
48
6.29M
        pic->motion_val[i] = NULL;
49
6.29M
    }
50
51
3.14M
    pic->mb_type                = NULL;
52
3.14M
    pic->qscale_table           = NULL;
53
54
3.14M
    pic->mb_stride =
55
3.14M
    pic->mb_width  =
56
3.14M
    pic->mb_height = 0;
57
58
3.14M
    pic->dummy                  = 0;
59
3.14M
    pic->field_picture          = 0;
60
3.14M
    pic->b_frame_score          = 0;
61
3.14M
    pic->reference              = 0;
62
3.14M
    pic->shared                 = 0;
63
3.14M
    pic->display_picture_number = 0;
64
3.14M
    pic->coded_picture_number   = 0;
65
3.14M
}
66
67
static int av_cold mpv_pic_init(AVRefStructOpaque opaque, void *obj)
68
222k
{
69
222k
    MPVPicture *pic = obj;
70
222k
    int ret, init_progress = (uintptr_t)opaque.nc;
71
72
222k
    ret = ff_thread_progress_init(&pic->progress, init_progress);
73
222k
    if (ret < 0)
74
0
        return ret;
75
76
222k
    pic->f = av_frame_alloc();
77
222k
    if (!pic->f)
78
0
        return AVERROR(ENOMEM);
79
222k
    return 0;
80
222k
}
81
82
static void av_cold mpv_pic_free(AVRefStructOpaque unused, void *obj)
83
222k
{
84
222k
    MPVPicture *pic = obj;
85
86
222k
    ff_thread_progress_destroy(&pic->progress);
87
222k
    av_frame_free(&pic->f);
88
222k
}
89
90
av_cold AVRefStructPool *ff_mpv_alloc_pic_pool(int init_progress)
91
126k
{
92
126k
    return av_refstruct_pool_alloc_ext(sizeof(MPVPicture),
93
126k
                                       AV_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR,
94
126k
                                       (void*)(uintptr_t)init_progress,
95
126k
                                       mpv_pic_init, mpv_pic_reset, mpv_pic_free, NULL);
96
126k
}
97
98
void ff_mpv_unref_picture(MPVWorkPicture *pic)
99
8.33M
{
100
8.33M
    av_refstruct_unref(&pic->ptr);
101
8.33M
    memset(pic, 0, sizeof(*pic));
102
8.33M
}
103
104
static void set_workpic_from_pic(MPVWorkPicture *wpic, const MPVPicture *pic)
105
7.38M
{
106
29.5M
    for (int i = 0; i < MPV_MAX_PLANES; i++) {
107
22.1M
        wpic->data[i]     = pic->f->data[i];
108
22.1M
        wpic->linesize[i] = pic->f->linesize[i];
109
22.1M
    }
110
7.38M
    wpic->qscale_table = pic->qscale_table;
111
7.38M
    wpic->mb_type      = pic->mb_type;
112
7.38M
    wpic->mbskip_table = pic->mbskip_table;
113
114
22.1M
    for (int i = 0; i < 2; i++) {
115
14.7M
        wpic->motion_val[i] = pic->motion_val[i];
116
14.7M
        wpic->ref_index[i]  = pic->ref_index[i];
117
14.7M
    }
118
7.38M
    wpic->reference  = pic->reference;
119
7.38M
}
120
121
void ff_mpv_replace_picture(MPVWorkPicture *dst, const MPVWorkPicture *src)
122
13.1k
{
123
13.1k
    av_assert1(dst != src);
124
13.1k
    av_refstruct_replace(&dst->ptr, src->ptr);
125
13.1k
    memcpy(dst, src, sizeof(*dst));
126
13.1k
}
127
128
void ff_mpv_workpic_from_pic(MPVWorkPicture *wpic, MPVPicture *pic)
129
4.94M
{
130
4.94M
    av_refstruct_replace(&wpic->ptr, pic);
131
4.94M
    if (!pic) {
132
672k
        memset(wpic, 0, sizeof(*wpic));
133
672k
        return;
134
672k
    }
135
4.27M
    set_workpic_from_pic(wpic, pic);
136
4.27M
}
137
138
int ff_mpv_framesize_alloc(AVCodecContext *avctx,
139
                           ScratchpadContext *sc, int linesize)
140
3.13M
{
141
3.13M
#   define EMU_EDGE_HEIGHT (4 * 70)
142
3.13M
    int linesizeabs = FFABS(linesize);
143
3.13M
    int alloc_size = FFALIGN(linesizeabs + 64, 32);
144
145
3.13M
    if (linesizeabs <= sc->linesize)
146
2.84M
        return 0;
147
148
296k
    if (avctx->hwaccel)
149
0
        return 0;
150
151
296k
    if (linesizeabs < 24) {
152
20.7k
        av_log(avctx, AV_LOG_ERROR, "Image too small, temporary buffers cannot function\n");
153
20.7k
        return AVERROR_PATCHWELCOME;
154
20.7k
    }
155
156
275k
    if (av_image_check_size2(alloc_size, EMU_EDGE_HEIGHT, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx) < 0)
157
4.53k
        return AVERROR(ENOMEM);
158
159
271k
    av_freep(&sc->edge_emu_buffer);
160
271k
    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
271k
    if (!FF_ALLOCZ_TYPED_ARRAY(sc->edge_emu_buffer, alloc_size * EMU_EDGE_HEIGHT) ||
169
271k
        !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
271k
    sc->linesize = linesizeabs;
175
176
271k
    sc->obmc_scratchpad = sc->scratchpad_buf + 16;
177
178
271k
    return 0;
179
271k
}
180
181
int ff_mpv_pic_check_linesize(void *logctx, const AVFrame *f,
182
                              ptrdiff_t *linesizep, ptrdiff_t *uvlinesizep)
183
3.13M
{
184
3.13M
    ptrdiff_t linesize = *linesizep, uvlinesize = *uvlinesizep;
185
186
3.13M
    if ((linesize   &&   linesize != f->linesize[0]) ||
187
3.13M
        (uvlinesize && uvlinesize != f->linesize[1])) {
188
350
        av_log(logctx, AV_LOG_ERROR, "Stride change unsupported: "
189
350
               "linesize=%td/%d uvlinesize=%td/%d)\n",
190
350
               linesize,   f->linesize[0],
191
350
               uvlinesize, f->linesize[1]);
192
350
        return AVERROR_PATCHWELCOME;
193
350
    }
194
195
3.13M
    if (av_pix_fmt_count_planes(f->format) > 2 &&
196
3.13M
        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.13M
    *linesizep   = f->linesize[0];
201
3.13M
    *uvlinesizep = f->linesize[1];
202
203
3.13M
    return 0;
204
3.13M
}
205
206
static int alloc_picture_tables(BufferPoolContext *pools, MPVPicture *pic,
207
                                int mb_height)
208
3.11M
{
209
15.5M
#define GET_BUFFER(name, buf_suffix, idx_suffix) do { \
210
15.5M
    pic->name ## buf_suffix idx_suffix = av_refstruct_pool_get(pools->name ## _pool); \
211
15.5M
    if (!pic->name ## buf_suffix idx_suffix) \
212
15.5M
        return AVERROR(ENOMEM); \
213
15.5M
} while (0)
214
3.11M
    GET_BUFFER(qscale_table, _base,);
215
3.11M
    GET_BUFFER(mb_type, _base,);
216
3.11M
    if (pools->motion_val_pool) {
217
2.29M
        if (pools->mbskip_table_pool)
218
154k
            GET_BUFFER(mbskip_table,,);
219
6.88M
        for (int i = 0; i < 2; i++) {
220
4.58M
            GET_BUFFER(ref_index,, [i]);
221
4.58M
            GET_BUFFER(motion_val, _base, [i]);
222
4.58M
            pic->motion_val[i] = pic->motion_val_base[i] + 4;
223
4.58M
        }
224
2.29M
    }
225
3.11M
#undef GET_BUFFER
226
227
3.11M
    pic->mb_width  = pools->alloc_mb_width;
228
3.11M
    pic->mb_height = mb_height;
229
3.11M
    pic->mb_stride = pools->alloc_mb_stride;
230
231
3.11M
    pic->qscale_table = pic->qscale_table_base + 2 * pic->mb_stride + 1;
232
3.11M
    pic->mb_type      = pic->mb_type_base      + 2 * pic->mb_stride + 1;
233
234
3.11M
    return 0;
235
3.11M
}
236
237
int ff_mpv_alloc_pic_accessories(AVCodecContext *avctx, MPVWorkPicture *wpic,
238
                                 ScratchpadContext *sc,
239
                                 BufferPoolContext *pools, int mb_height)
240
3.13M
{
241
3.13M
    MPVPicture *pic = wpic->ptr;
242
3.13M
    int ret;
243
244
3.13M
    ret = ff_mpv_framesize_alloc(avctx, sc, pic->f->linesize[0]);
245
3.13M
    if (ret < 0)
246
25.2k
        goto fail;
247
248
3.11M
    ret = alloc_picture_tables(pools, pic, mb_height);
249
3.11M
    if (ret < 0)
250
0
        goto fail;
251
252
3.11M
    set_workpic_from_pic(wpic, pic);
253
254
3.11M
    return 0;
255
25.2k
fail:
256
25.2k
    av_log(avctx, AV_LOG_ERROR, "Error allocating picture accessories.\n");
257
25.2k
    return ret;
258
3.11M
}