FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/mpegpicture.c
Date: 2025-10-10 03:51:19
Exec Total Coverage
Lines: 115 135 85.2%
Functions: 12 12 100.0%
Branches: 38 56 67.9%

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