FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/lcevcdec.c
Date: 2024-10-04 17:46:48
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 "decode.h"
27 #include "lcevcdec.h"
28
29 #if CONFIG_LIBLCEVC_DEC
30 static LCEVC_ColorFormat map_format(int format)
31 {
32 switch (format) {
33 case AV_PIX_FMT_YUV420P:
34 return LCEVC_I420_8;
35 case AV_PIX_FMT_YUV420P10:
36 return LCEVC_I420_10_LE;
37 case AV_PIX_FMT_NV12:
38 return LCEVC_NV12_8;
39 case AV_PIX_FMT_NV21:
40 return LCEVC_NV21_8;
41 case AV_PIX_FMT_GRAY8:
42 return LCEVC_GRAY_8;
43 }
44
45 return LCEVC_ColorFormat_Unknown;
46 }
47
48 static int alloc_base_frame(void *logctx, LCEVC_DecoderHandle decoder,
49 const AVFrame *frame, LCEVC_PictureHandle *picture)
50 {
51 LCEVC_PictureDesc desc;
52 LCEVC_ColorFormat fmt = map_format(frame->format);
53 LCEVC_PictureLockHandle lock;
54 uint8_t *data[4] = { NULL };
55 int linesizes[4] = { 0 };
56 uint32_t planes;
57 LCEVC_ReturnCode res;
58
59 res = LCEVC_DefaultPictureDesc(&desc, fmt, frame->width, frame->height);
60 if (res != LCEVC_Success)
61 return AVERROR_EXTERNAL;
62
63 desc.cropTop = frame->crop_top;
64 desc.cropBottom = frame->crop_bottom;
65 desc.cropLeft = frame->crop_left;
66 desc.cropRight = frame->crop_right;
67 desc.sampleAspectRatioNum = frame->sample_aspect_ratio.num;
68 desc.sampleAspectRatioDen = frame->sample_aspect_ratio.den;
69
70 /* Allocate LCEVC Picture */
71 res = LCEVC_AllocPicture(decoder, &desc, picture);
72 if (res != LCEVC_Success) {
73 return AVERROR_EXTERNAL;
74 }
75 res = LCEVC_LockPicture(decoder, *picture, LCEVC_Access_Write, &lock);
76 if (res != LCEVC_Success)
77 return AVERROR_EXTERNAL;
78
79 res = LCEVC_GetPicturePlaneCount(decoder, *picture, &planes);
80 if (res != LCEVC_Success)
81 return AVERROR_EXTERNAL;
82
83 for (unsigned i = 0; i < planes; i++) {
84 LCEVC_PicturePlaneDesc plane;
85
86 res = LCEVC_GetPictureLockPlaneDesc(decoder, lock, i, &plane);
87 if (res != LCEVC_Success)
88 return AVERROR_EXTERNAL;
89
90 data[i] = plane.firstSample;
91 linesizes[i] = plane.rowByteStride;
92 }
93
94 av_image_copy2(data, linesizes, frame->data, frame->linesize,
95 frame->format, frame->width, frame->height);
96
97 res = LCEVC_UnlockPicture(decoder, lock);
98 if (res != LCEVC_Success)
99 return AVERROR_EXTERNAL;
100
101 return 0;
102 }
103
104 static int alloc_enhanced_frame(void *logctx, LCEVC_DecoderHandle decoder,
105 const AVFrame *frame, LCEVC_PictureHandle *picture)
106 {
107 LCEVC_PictureDesc desc ;
108 LCEVC_ColorFormat fmt = map_format(frame->format);
109 LCEVC_PicturePlaneDesc planes[4] = { 0 };
110 int width = frame->width * 2 / FFMAX(frame->sample_aspect_ratio.den, 1);
111 int height = frame->height * 2 / FFMAX(frame->sample_aspect_ratio.num, 1);
112 LCEVC_ReturnCode res;
113
114 res = LCEVC_DefaultPictureDesc(&desc, fmt, width, height);
115 if (res != LCEVC_Success)
116 return AVERROR_EXTERNAL;
117
118 /* Set plane description */
119 for (int i = 0; i < 4; i++) {
120 planes[i].firstSample = frame->data[i];
121 planes[i].rowByteStride = frame->linesize[i];
122 }
123
124 /* Allocate LCEVC Picture */
125 res = LCEVC_AllocPictureExternal(decoder, &desc, NULL, planes, picture);
126 if (res != LCEVC_Success) {
127 return AVERROR_EXTERNAL;
128 }
129 return 0;
130 }
131
132 static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *in)
133 {
134 const AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_LCEVC);
135 LCEVC_PictureHandle picture;
136 LCEVC_ReturnCode res;
137 int ret = 0;
138
139 if (!sd)
140 return 1;
141
142 res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, 0, sd->data, sd->size);
143 if (res != LCEVC_Success)
144 return AVERROR_EXTERNAL;
145
146 ret = alloc_base_frame(logctx, lcevc->decoder, in, &picture);
147 if (ret < 0)
148 return ret;
149
150 res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, NULL);
151 if (res != LCEVC_Success)
152 return AVERROR_EXTERNAL;
153
154 memset(&picture, 0, sizeof(picture));
155 ret = alloc_enhanced_frame(logctx, lcevc->decoder, in, &picture);
156 if (ret < 0)
157 return ret;
158
159 res = LCEVC_SendDecoderPicture(lcevc->decoder, picture);
160 if (res != LCEVC_Success)
161 return AVERROR_EXTERNAL;
162
163 return 0;
164 }
165
166 static int generate_output(void *logctx, FFLCEVCContext *lcevc, AVFrame *out)
167 {
168 LCEVC_PictureDesc desc;
169 LCEVC_DecodeInformation info;
170 LCEVC_PictureHandle picture;
171 LCEVC_ReturnCode res;
172
173 res = LCEVC_ReceiveDecoderPicture(lcevc->decoder, &picture, &info);
174 if (res != LCEVC_Success)
175 return AVERROR_EXTERNAL;
176
177 res = LCEVC_GetPictureDesc(lcevc->decoder, picture, &desc);
178 if (res != LCEVC_Success)
179 return AVERROR_EXTERNAL;
180
181 out->crop_top = desc.cropTop;
182 out->crop_bottom = desc.cropBottom;
183 out->crop_left = desc.cropLeft;
184 out->crop_right = desc.cropRight;
185 out->sample_aspect_ratio.num = desc.sampleAspectRatioNum;
186 out->sample_aspect_ratio.den = desc.sampleAspectRatioDen;
187 out->width = desc.width + out->crop_left + out->crop_right;
188 out->height = desc.height + out->crop_top + out->crop_bottom;
189
190 res = LCEVC_FreePicture(lcevc->decoder, picture);
191 if (res != LCEVC_Success)
192 return AVERROR_EXTERNAL;
193
194 return 0;
195 }
196
197 static int lcevc_receive_frame(void *logctx, FFLCEVCContext *lcevc, AVFrame *out)
198 {
199 LCEVC_PictureHandle picture;
200 LCEVC_ReturnCode res;
201 int ret;
202
203 ret = generate_output(logctx, lcevc, out);
204 if (ret < 0)
205 return ret;
206
207 while (1) {
208 res = LCEVC_ReceiveDecoderBase (lcevc->decoder, &picture);
209 if (res != LCEVC_Success && res != LCEVC_Again)
210 return AVERROR_EXTERNAL;
211
212 if (res == LCEVC_Again)
213 break;
214
215 res = LCEVC_FreePicture(lcevc->decoder, picture);
216 if (res != LCEVC_Success)
217 return AVERROR_EXTERNAL;
218 }
219
220 return 0;
221 }
222
223 static void event_callback(LCEVC_DecoderHandle dec, LCEVC_Event event,
224 LCEVC_PictureHandle pic, const LCEVC_DecodeInformation *info,
225 const uint8_t *data, uint32_t size, void *logctx)
226 {
227 switch (event) {
228 case LCEVC_Log:
229 av_log(logctx, AV_LOG_INFO, "%s\n", data);
230 break;
231 default:
232 break;
233 }
234 }
235
236 static void lcevc_free(FFRefStructOpaque unused, void *obj)
237 {
238 FFLCEVCContext *lcevc = obj;
239 if (lcevc->initialized)
240 LCEVC_DestroyDecoder(lcevc->decoder);
241 memset(lcevc, 0, sizeof(*lcevc));
242 }
243 #endif
244
245 static int lcevc_init(FFLCEVCContext *lcevc, void *logctx)
246 {
247 #if CONFIG_LIBLCEVC_DEC
248 LCEVC_AccelContextHandle dummy = { 0 };
249 const int32_t event = LCEVC_Log;
250 #endif
251
252 if (lcevc->initialized)
253 return 0;
254
255 #if CONFIG_LIBLCEVC_DEC
256 if (LCEVC_CreateDecoder(&lcevc->decoder, dummy) != LCEVC_Success) {
257 av_log(logctx, AV_LOG_ERROR, "Failed to create LCEVC decoder\n");
258 return AVERROR_EXTERNAL;
259 }
260
261 LCEVC_ConfigureDecoderInt(lcevc->decoder, "log_level", 4);
262 LCEVC_ConfigureDecoderIntArray(lcevc->decoder, "events", 1, &event);
263 LCEVC_SetDecoderEventCallback(lcevc->decoder, event_callback, logctx);
264
265 if (LCEVC_InitializeDecoder(lcevc->decoder) != LCEVC_Success) {
266 av_log(logctx, AV_LOG_ERROR, "Failed to initialize LCEVC decoder\n");
267 LCEVC_DestroyDecoder(lcevc->decoder);
268 return AVERROR_EXTERNAL;
269 }
270
271 #endif
272 lcevc->initialized = 1;
273
274 return 0;
275 }
276
277 int ff_lcevc_process(void *logctx, AVFrame *frame)
278 {
279 FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data;
280 FFLCEVCContext *lcevc = fdd->post_process_opaque;
281 int ret;
282
283 if (!lcevc->initialized) {
284 ret = lcevc_init(lcevc, logctx);
285 if (ret < 0)
286 return ret;
287 }
288
289 #if CONFIG_LIBLCEVC_DEC
290 ret = lcevc_send_frame(logctx, lcevc, frame);
291 if (ret)
292 return ret < 0 ? ret : 0;
293
294 lcevc_receive_frame(logctx, lcevc, frame);
295 if (ret < 0)
296 return ret;
297
298 av_frame_remove_side_data(frame, AV_FRAME_DATA_LCEVC);
299 #endif
300
301 return 0;
302 }
303
304 14662 int ff_lcevc_alloc(FFLCEVCContext **plcevc)
305 {
306 14662 FFLCEVCContext *lcevc = NULL;
307 #if CONFIG_LIBLCEVC_DEC
308 lcevc = ff_refstruct_alloc_ext(sizeof(*lcevc), 0, NULL, lcevc_free);
309 if (!lcevc)
310 return AVERROR(ENOMEM);
311 #endif
312 14662 *plcevc = lcevc;
313 14662 return 0;
314 }
315
316 void ff_lcevc_unref(void *opaque)
317 {
318 ff_refstruct_unref(&opaque);
319 }
320