FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/lcevcdec.c
Date: 2025-01-20 09:27:23
Exec Total Coverage
Lines: 4 20 20.0%
Functions: 1 4 25.0%
Branches: 0 6 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, LCEVC_DecoderHandle decoder,
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(decoder, &desc, picture);
74 if (res != LCEVC_Success) {
75 return AVERROR_EXTERNAL;
76 }
77 res = LCEVC_LockPicture(decoder, *picture, LCEVC_Access_Write, &lock);
78 if (res != LCEVC_Success)
79 return AVERROR_EXTERNAL;
80
81 res = LCEVC_GetPicturePlaneCount(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(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(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, LCEVC_DecoderHandle decoder,
107 const AVFrame *frame, LCEVC_PictureHandle *picture)
108 {
109 LCEVC_PictureDesc desc ;
110 LCEVC_ColorFormat fmt = map_format(frame->format);
111 LCEVC_PicturePlaneDesc planes[4] = { 0 };
112 int width = frame->width * 2 / FFMAX(frame->sample_aspect_ratio.den, 1);
113 int height = frame->height * 2 / FFMAX(frame->sample_aspect_ratio.num, 1);
114 LCEVC_ReturnCode res;
115
116 res = LCEVC_DefaultPictureDesc(&desc, fmt, width, height);
117 if (res != LCEVC_Success)
118 return AVERROR_EXTERNAL;
119
120 /* Set plane description */
121 for (int i = 0; i < 4; i++) {
122 planes[i].firstSample = frame->data[i];
123 planes[i].rowByteStride = frame->linesize[i];
124 }
125
126 /* Allocate LCEVC Picture */
127 res = LCEVC_AllocPictureExternal(decoder, &desc, NULL, planes, picture);
128 if (res != LCEVC_Success) {
129 return AVERROR_EXTERNAL;
130 }
131 return 0;
132 }
133
134 static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *in)
135 {
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->decoder, 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, lcevc->decoder, in, &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, FFLCEVCContext *lcevc, AVFrame *out)
169 {
170 LCEVC_PictureDesc desc;
171 LCEVC_DecodeInformation info;
172 LCEVC_PictureHandle picture;
173 LCEVC_ReturnCode res;
174
175 res = LCEVC_ReceiveDecoderPicture(lcevc->decoder, &picture, &info);
176 if (res != LCEVC_Success)
177 return AVERROR_EXTERNAL;
178
179 res = LCEVC_GetPictureDesc(lcevc->decoder, picture, &desc);
180 if (res != LCEVC_Success)
181 return AVERROR_EXTERNAL;
182
183 out->crop_top = desc.cropTop;
184 out->crop_bottom = desc.cropBottom;
185 out->crop_left = desc.cropLeft;
186 out->crop_right = desc.cropRight;
187 out->sample_aspect_ratio.num = desc.sampleAspectRatioNum;
188 out->sample_aspect_ratio.den = desc.sampleAspectRatioDen;
189 out->width = desc.width + out->crop_left + out->crop_right;
190 out->height = desc.height + out->crop_top + out->crop_bottom;
191
192 res = LCEVC_FreePicture(lcevc->decoder, picture);
193 if (res != LCEVC_Success)
194 return AVERROR_EXTERNAL;
195
196 return 0;
197 }
198
199 static int lcevc_receive_frame(void *logctx, FFLCEVCContext *lcevc, AVFrame *out)
200 {
201 LCEVC_PictureHandle picture;
202 LCEVC_ReturnCode res;
203 int ret;
204
205 ret = generate_output(logctx, lcevc, out);
206 if (ret < 0)
207 return ret;
208
209 while (1) {
210 res = LCEVC_ReceiveDecoderBase (lcevc->decoder, &picture);
211 if (res != LCEVC_Success && res != LCEVC_Again)
212 return AVERROR_EXTERNAL;
213
214 if (res == LCEVC_Again)
215 break;
216
217 res = LCEVC_FreePicture(lcevc->decoder, picture);
218 if (res != LCEVC_Success)
219 return AVERROR_EXTERNAL;
220 }
221
222 return 0;
223 }
224
225 static void event_callback(LCEVC_DecoderHandle dec, LCEVC_Event event,
226 LCEVC_PictureHandle pic, const LCEVC_DecodeInformation *info,
227 const uint8_t *data, uint32_t size, void *logctx)
228 {
229 switch (event) {
230 case LCEVC_Log:
231 av_log(logctx, AV_LOG_INFO, "%s\n", data);
232 break;
233 default:
234 break;
235 }
236 }
237
238 static void lcevc_free(AVRefStructOpaque unused, void *obj)
239 {
240 FFLCEVCContext *lcevc = obj;
241 if (lcevc->initialized)
242 LCEVC_DestroyDecoder(lcevc->decoder);
243 memset(lcevc, 0, sizeof(*lcevc));
244 }
245 #endif
246
247 static int lcevc_init(FFLCEVCContext *lcevc, void *logctx)
248 {
249 #if CONFIG_LIBLCEVC_DEC
250 LCEVC_AccelContextHandle dummy = { 0 };
251 const int32_t event = LCEVC_Log;
252 #endif
253
254 if (lcevc->initialized)
255 return 0;
256
257 #if CONFIG_LIBLCEVC_DEC
258 if (LCEVC_CreateDecoder(&lcevc->decoder, dummy) != LCEVC_Success) {
259 av_log(logctx, AV_LOG_ERROR, "Failed to create LCEVC decoder\n");
260 return AVERROR_EXTERNAL;
261 }
262
263 LCEVC_ConfigureDecoderInt(lcevc->decoder, "log_level", 4);
264 LCEVC_ConfigureDecoderIntArray(lcevc->decoder, "events", 1, &event);
265 LCEVC_SetDecoderEventCallback(lcevc->decoder, event_callback, logctx);
266
267 if (LCEVC_InitializeDecoder(lcevc->decoder) != LCEVC_Success) {
268 av_log(logctx, AV_LOG_ERROR, "Failed to initialize LCEVC decoder\n");
269 LCEVC_DestroyDecoder(lcevc->decoder);
270 return AVERROR_EXTERNAL;
271 }
272
273 #endif
274 lcevc->initialized = 1;
275
276 return 0;
277 }
278
279 int ff_lcevc_process(void *logctx, AVFrame *frame)
280 {
281 FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data;
282 FFLCEVCContext *lcevc = fdd->post_process_opaque;
283 int ret;
284
285 if (!lcevc->initialized) {
286 ret = lcevc_init(lcevc, logctx);
287 if (ret < 0)
288 return ret;
289 }
290
291 #if CONFIG_LIBLCEVC_DEC
292 ret = lcevc_send_frame(logctx, lcevc, frame);
293 if (ret)
294 return ret < 0 ? ret : 0;
295
296 lcevc_receive_frame(logctx, lcevc, frame);
297 if (ret < 0)
298 return ret;
299
300 av_frame_remove_side_data(frame, AV_FRAME_DATA_LCEVC);
301 #endif
302
303 return 0;
304 }
305
306 15376 int ff_lcevc_alloc(FFLCEVCContext **plcevc)
307 {
308 15376 FFLCEVCContext *lcevc = NULL;
309 #if CONFIG_LIBLCEVC_DEC
310 lcevc = av_refstruct_alloc_ext(sizeof(*lcevc), 0, NULL, lcevc_free);
311 if (!lcevc)
312 return AVERROR(ENOMEM);
313 #endif
314 15376 *plcevc = lcevc;
315 15376 return 0;
316 }
317
318 void ff_lcevc_unref(void *opaque)
319 {
320 av_refstruct_unref(&opaque);
321 }
322