Coverage Report

Created: 2024-09-06 07:53

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