FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/lcevcdec.c
Date: 2025-06-01 09:29:47
Exec Total Coverage
Lines: 4 22 18.2%
Functions: 1 4 25.0%
Branches: 0 4 0.0%

Line Branch Exec Source
1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "config_components.h"
20
21 #include "libavutil/avassert.h"
22 #include "libavutil/frame.h"
23 #include "libavutil/imgutils.h"
24 #include "libavutil/log.h"
25 #include "libavutil/mem.h"
26 #include "libavutil/refstruct.h"
27
28 #include "decode.h"
29 #include "lcevcdec.h"
30
31 #if CONFIG_LIBLCEVC_DEC
32 static LCEVC_ColorFormat map_format(int format)
33 {
34 switch (format) {
35 case AV_PIX_FMT_YUV420P:
36 return LCEVC_I420_8;
37 case AV_PIX_FMT_YUV420P10:
38 return LCEVC_I420_10_LE;
39 case AV_PIX_FMT_NV12:
40 return LCEVC_NV12_8;
41 case AV_PIX_FMT_NV21:
42 return LCEVC_NV21_8;
43 case AV_PIX_FMT_GRAY8:
44 return LCEVC_GRAY_8;
45 }
46
47 return LCEVC_ColorFormat_Unknown;
48 }
49
50 static int alloc_base_frame(void *logctx, FFLCEVCContext *lcevc,
51 const AVFrame *frame, LCEVC_PictureHandle *picture)
52 {
53 LCEVC_PictureDesc desc;
54 LCEVC_ColorFormat fmt = map_format(frame->format);
55 LCEVC_PictureLockHandle lock;
56 uint8_t *data[4] = { NULL };
57 int linesizes[4] = { 0 };
58 uint32_t planes;
59 LCEVC_ReturnCode res;
60
61 res = LCEVC_DefaultPictureDesc(&desc, fmt, frame->width, frame->height);
62 if (res != LCEVC_Success)
63 return AVERROR_EXTERNAL;
64
65 desc.cropTop = frame->crop_top;
66 desc.cropBottom = frame->crop_bottom;
67 desc.cropLeft = frame->crop_left;
68 desc.cropRight = frame->crop_right;
69 desc.sampleAspectRatioNum = frame->sample_aspect_ratio.num;
70 desc.sampleAspectRatioDen = frame->sample_aspect_ratio.den;
71
72 /* Allocate LCEVC Picture */
73 res = LCEVC_AllocPicture(lcevc->decoder, &desc, picture);
74 if (res != LCEVC_Success) {
75 return AVERROR_EXTERNAL;
76 }
77 res = LCEVC_LockPicture(lcevc->decoder, *picture, LCEVC_Access_Write, &lock);
78 if (res != LCEVC_Success)
79 return AVERROR_EXTERNAL;
80
81 res = LCEVC_GetPicturePlaneCount(lcevc->decoder, *picture, &planes);
82 if (res != LCEVC_Success)
83 return AVERROR_EXTERNAL;
84
85 for (unsigned i = 0; i < planes; i++) {
86 LCEVC_PicturePlaneDesc plane;
87
88 res = LCEVC_GetPictureLockPlaneDesc(lcevc->decoder, lock, i, &plane);
89 if (res != LCEVC_Success)
90 return AVERROR_EXTERNAL;
91
92 data[i] = plane.firstSample;
93 linesizes[i] = plane.rowByteStride;
94 }
95
96 av_image_copy2(data, linesizes, frame->data, frame->linesize,
97 frame->format, frame->width, frame->height);
98
99 res = LCEVC_UnlockPicture(lcevc->decoder, lock);
100 if (res != LCEVC_Success)
101 return AVERROR_EXTERNAL;
102
103 return 0;
104 }
105
106 static int alloc_enhanced_frame(void *logctx, FFLCEVCFrame *frame_ctx,
107 LCEVC_PictureHandle *picture)
108 {
109 FFLCEVCContext *lcevc = frame_ctx->lcevc;
110 LCEVC_PictureDesc desc ;
111 LCEVC_ColorFormat fmt = map_format(frame_ctx->frame->format);
112 LCEVC_PicturePlaneDesc planes[4] = { 0 };
113 LCEVC_ReturnCode res;
114
115 res = LCEVC_DefaultPictureDesc(&desc, fmt, frame_ctx->frame->width, frame_ctx->frame->height);
116 if (res != LCEVC_Success)
117 return AVERROR_EXTERNAL;
118
119 /* Set plane description */
120 for (int i = 0; i < 4; i++) {
121 planes[i].firstSample = frame_ctx->frame->data[i];
122 planes[i].rowByteStride = frame_ctx->frame->linesize[i];
123 }
124
125 /* Allocate LCEVC Picture */
126 res = LCEVC_AllocPictureExternal(lcevc->decoder, &desc, NULL, planes, picture);
127 if (res != LCEVC_Success) {
128 return AVERROR_EXTERNAL;
129 }
130 return 0;
131 }
132
133 static int lcevc_send_frame(void *logctx, FFLCEVCFrame *frame_ctx, const AVFrame *in)
134 {
135 FFLCEVCContext *lcevc = frame_ctx->lcevc;
136 const AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_LCEVC);
137 LCEVC_PictureHandle picture;
138 LCEVC_ReturnCode res;
139 int ret = 0;
140
141 if (!sd)
142 return 1;
143
144 res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, 0, sd->data, sd->size);
145 if (res != LCEVC_Success)
146 return AVERROR_EXTERNAL;
147
148 ret = alloc_base_frame(logctx, lcevc, in, &picture);
149 if (ret < 0)
150 return ret;
151
152 res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, NULL);
153 if (res != LCEVC_Success)
154 return AVERROR_EXTERNAL;
155
156 memset(&picture, 0, sizeof(picture));
157 ret = alloc_enhanced_frame(logctx, frame_ctx, &picture);
158 if (ret < 0)
159 return ret;
160
161 res = LCEVC_SendDecoderPicture(lcevc->decoder, picture);
162 if (res != LCEVC_Success)
163 return AVERROR_EXTERNAL;
164
165 return 0;
166 }
167
168 static int generate_output(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out)
169 {
170 FFLCEVCContext *lcevc = frame_ctx->lcevc;
171 LCEVC_PictureDesc desc;
172 LCEVC_DecodeInformation info;
173 LCEVC_PictureHandle picture;
174 LCEVC_ReturnCode res;
175
176 res = LCEVC_ReceiveDecoderPicture(lcevc->decoder, &picture, &info);
177 if (res != LCEVC_Success)
178 return AVERROR_EXTERNAL;
179
180 res = LCEVC_GetPictureDesc(lcevc->decoder, picture, &desc);
181 if (res != LCEVC_Success)
182 return AVERROR_EXTERNAL;
183
184 out->crop_top = desc.cropTop;
185 out->crop_bottom = desc.cropBottom;
186 out->crop_left = desc.cropLeft;
187 out->crop_right = desc.cropRight;
188 out->sample_aspect_ratio.num = desc.sampleAspectRatioNum;
189 out->sample_aspect_ratio.den = desc.sampleAspectRatioDen;
190
191 av_frame_copy_props(frame_ctx->frame, out);
192 av_frame_unref(out);
193 av_frame_move_ref(out, frame_ctx->frame);
194
195 out->width = desc.width + out->crop_left + out->crop_right;
196 out->height = desc.height + out->crop_top + out->crop_bottom;
197
198 res = LCEVC_FreePicture(lcevc->decoder, picture);
199 if (res != LCEVC_Success)
200 return AVERROR_EXTERNAL;
201
202 return 0;
203 }
204
205 static int lcevc_receive_frame(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out)
206 {
207 FFLCEVCContext *lcevc = frame_ctx->lcevc;
208 LCEVC_PictureHandle picture;
209 LCEVC_ReturnCode res;
210 int ret;
211
212 ret = generate_output(logctx, frame_ctx, out);
213 if (ret < 0)
214 return ret;
215
216 while (1) {
217 res = LCEVC_ReceiveDecoderBase (lcevc->decoder, &picture);
218 if (res != LCEVC_Success && res != LCEVC_Again)
219 return AVERROR_EXTERNAL;
220
221 if (res == LCEVC_Again)
222 break;
223
224 res = LCEVC_FreePicture(lcevc->decoder, picture);
225 if (res != LCEVC_Success)
226 return AVERROR_EXTERNAL;
227 }
228
229 return 0;
230 }
231
232 static void event_callback(LCEVC_DecoderHandle dec, LCEVC_Event event,
233 LCEVC_PictureHandle pic, const LCEVC_DecodeInformation *info,
234 const uint8_t *data, uint32_t size, void *logctx)
235 {
236 switch (event) {
237 case LCEVC_Log:
238 av_log(logctx, AV_LOG_INFO, "%s\n", data);
239 break;
240 default:
241 break;
242 }
243 }
244
245 static void lcevc_free(AVRefStructOpaque unused, void *obj)
246 {
247 FFLCEVCContext *lcevc = obj;
248 if (lcevc->initialized)
249 LCEVC_DestroyDecoder(lcevc->decoder);
250 memset(lcevc, 0, sizeof(*lcevc));
251 }
252 #endif
253
254 static int lcevc_init(FFLCEVCContext *lcevc, void *logctx)
255 {
256 #if CONFIG_LIBLCEVC_DEC
257 LCEVC_AccelContextHandle dummy = { 0 };
258 const int32_t event = LCEVC_Log;
259
260 if (LCEVC_CreateDecoder(&lcevc->decoder, dummy) != LCEVC_Success) {
261 av_log(logctx, AV_LOG_ERROR, "Failed to create LCEVC decoder\n");
262 return AVERROR_EXTERNAL;
263 }
264
265 LCEVC_ConfigureDecoderInt(lcevc->decoder, "log_level", 4);
266 LCEVC_ConfigureDecoderIntArray(lcevc->decoder, "events", 1, &event);
267 LCEVC_SetDecoderEventCallback(lcevc->decoder, event_callback, logctx);
268
269 if (LCEVC_InitializeDecoder(lcevc->decoder) != LCEVC_Success) {
270 av_log(logctx, AV_LOG_ERROR, "Failed to initialize LCEVC decoder\n");
271 LCEVC_DestroyDecoder(lcevc->decoder);
272 return AVERROR_EXTERNAL;
273 }
274
275 #endif
276 lcevc->initialized = 1;
277
278 return 0;
279 }
280
281 int ff_lcevc_process(void *logctx, AVFrame *frame)
282 {
283 FrameDecodeData *fdd = frame->private_ref;
284 FFLCEVCFrame *frame_ctx = fdd->post_process_opaque;
285 FFLCEVCContext *lcevc = frame_ctx->lcevc;
286 int ret;
287
288 if (!lcevc->initialized) {
289 ret = lcevc_init(lcevc, logctx);
290 if (ret < 0)
291 return ret;
292 }
293
294 #if CONFIG_LIBLCEVC_DEC
295 av_assert0(frame_ctx->frame);
296
297
298 ret = lcevc_send_frame(logctx, frame_ctx, frame);
299 if (ret)
300 return ret < 0 ? ret : 0;
301
302 lcevc_receive_frame(logctx, frame_ctx, frame);
303 if (ret < 0)
304 return ret;
305
306 av_frame_remove_side_data(frame, AV_FRAME_DATA_LCEVC);
307 #endif
308
309 return 0;
310 }
311
312 15470 int ff_lcevc_alloc(FFLCEVCContext **plcevc)
313 {
314 15470 FFLCEVCContext *lcevc = NULL;
315 #if CONFIG_LIBLCEVC_DEC
316 lcevc = av_refstruct_alloc_ext(sizeof(*lcevc), 0, NULL, lcevc_free);
317 if (!lcevc)
318 return AVERROR(ENOMEM);
319 #endif
320 15470 *plcevc = lcevc;
321 15470 return 0;
322 }
323
324 void ff_lcevc_unref(void *opaque)
325 {
326 FFLCEVCFrame *lcevc = opaque;
327 av_refstruct_unref(&lcevc->lcevc);
328 av_frame_free(&lcevc->frame);
329 av_free(opaque);
330 }
331