History

avcodec: add LCEVC decoding support via LCEVCdec

James Almer committed 2 years ago

Commit 660e7e61 parent 61473858 files · +439 −2Browse files

Showing the changes to libavcodec (7 of 8 files). Show all

Unified · Split

7 files
  1. libavcodec/Makefile +1 −0
  2. libavcodec/avcodec.c +2 −0
  3. libavcodec/avcodec_internal.h +4 −0
  4. libavcodec/decode.c +67 −1
  5. libavcodec/lcevcdec.c +319 −0
  6. libavcodec/lcevcdec.h +42 −0
  7. libavcodec/pthread_frame.c +3 −0
libavcodec/Makefile+1−0
@@ -46,6 +46,7 @@ OBJS = ac3_parser.o \ · 45 unmodified lines
4646 get_buffer.o \
4747 imgconvert.o \
4848 jni.o \
49+ lcevcdec.o \
4950 mathtables.o \
5051 mediacodec.o \
5152 mpeg12framerate.o \
libavcodec/avcodec.c+2−0
@@ -446,6 +446,8 @@ av_cold void ff_codec_close(AVCodecContext *avctx) · 445 unmodified lines
446446
447447 ff_refstruct_unref(&avci->pool);
448448 ff_refstruct_pool_uninit(&avci->progress_frame_pool);
449+ if (av_codec_is_decoder(avctx->codec))
450+ ff_decode_internal_uninit(avctx);
449451
450452 ff_hwaccel_uninit(avctx);
451453
libavcodec/avcodec_internal.h+4−0
@@ -68,6 +68,10 @@ void ff_decode_flush_buffers(struct AVCodecContext *avctx); · 67 unmodified lines
6868 void ff_encode_flush_buffers(struct AVCodecContext *avctx);
6969
7070 struct AVCodecInternal *ff_decode_internal_alloc(void);
71+void ff_decode_internal_sync(struct AVCodecContext *dst,
72+ const struct AVCodecContext *src);
73+void ff_decode_internal_uninit(struct AVCodecContext *avctx);
74+
7175 struct AVCodecInternal *ff_encode_internal_alloc(void);
7276
7377 void ff_codec_close(struct AVCodecContext *avctx);
libavcodec/decode.c+67−1
@@ -48,6 +48,7 @@ · 47 unmodified lines
4848 #include "hwaccel_internal.h"
4949 #include "hwconfig.h"
5050 #include "internal.h"
51+#include "lcevcdec.h"
5152 #include "packet_internal.h"
5253 #include "progressframe.h"
5354 #include "refstruct.h"
@@ -89,6 +90,11 @@ typedef struct DecodeContext { · 35 unmodified lines
8990 * (global or attached to packets) side data over bytestream.
9091 */
9192 uint64_t side_data_pref_mask;
93+
94+ FFLCEVCContext *lcevc;
95+ int lcevc_frame;
96+ int width;
97+ int height;
9298 } DecodeContext;
9399
94100 static DecodeContext *decode_ctx(AVCodecInternal *avci)
@@ -1597,6 +1603,40 @@ int ff_attach_decode_data(AVFrame *frame) · 1502 unmodified lines
15971603 return 0;
15981604 }
15991605
1606+static void update_frame_props(AVCodecContext *avctx, AVFrame *frame)
1607+{
1608+ AVCodecInternal *avci = avctx->internal;
1609+ DecodeContext *dc = decode_ctx(avci);
1610+
1611+ dc->lcevc_frame = dc->lcevc && avctx->codec_type == AVMEDIA_TYPE_VIDEO &&
1612+ av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC);
1613+
1614+ if (dc->lcevc_frame) {
1615+ dc->width = frame->width;
1616+ dc->height = frame->height;
1617+ frame->width = frame->width * 2 / FFMAX(frame->sample_aspect_ratio.den, 1);
1618+ frame->height = frame->height * 2 / FFMAX(frame->sample_aspect_ratio.num, 1);
1619+ }
1620+}
1621+
1622+static void attach_post_process_data(AVCodecContext *avctx, AVFrame *frame)
1623+{
1624+ AVCodecInternal *avci = avctx->internal;
1625+ DecodeContext *dc = decode_ctx(avci);
1626+
1627+ if (dc->lcevc_frame) {
1628+ FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data;
1629+
1630+ fdd->post_process_opaque = ff_refstruct_ref(dc->lcevc);
1631+ fdd->post_process_opaque_free = ff_lcevc_unref;
1632+ fdd->post_process = ff_lcevc_process;
1633+
1634+ frame->width = dc->width;
1635+ frame->height = dc->height;
1636+ }
1637+ dc->lcevc_frame = 0;
1638+}
1639+
16001640 int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
16011641 {
16021642 const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel);
@@ -1640,8 +1680,10 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) · 37 unmodified lines
16401680 ret = hwaccel->alloc_frame(avctx, frame);
16411681 goto end;
16421682 }
1643− } else
1683+ } else {
16441684 avctx->sw_pix_fmt = avctx->pix_fmt;
1685+ update_frame_props(avctx, frame);
1686+ }
16451687
16461688 ret = avctx->get_buffer2(avctx, frame, flags);
16471689 if (ret < 0)
@@ -1653,6 +1695,8 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) · 5 unmodified lines
16531695 if (ret < 0)
16541696 goto fail;
16551697
1698+ attach_post_process_data(avctx, frame);
1699+
16561700 end:
16571701 if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions &&
16581702 !(ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_EXPORTS_CROPPING)) {
@@ -1953,6 +1997,12 @@ int ff_decode_preinit(AVCodecContext *avctx) · 294 unmodified lines
19531997 if (ret < 0)
19541998 return ret;
19551999
2000+ if (!(avctx->export_side_data & AV_CODEC_EXPORT_DATA_ENHANCEMENTS)) {
2001+ ret = ff_lcevc_alloc(&dc->lcevc);
2002+ if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
2003+ return ret;
2004+ }
2005+
19562006 #if FF_API_DROPCHANGED
19572007 if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED)
19582008 av_log(avctx, AV_LOG_WARNING, "The dropchanged flag is deprecated.\n");
@@ -2187,3 +2237,19 @@ AVCodecInternal *ff_decode_internal_alloc(void) · 228 unmodified lines
21872237 {
21882238 return av_mallocz(sizeof(DecodeContext));
21892239 }
2240+
2241+void ff_decode_internal_sync(AVCodecContext *dst, const AVCodecContext *src)
2242+{
2243+ const DecodeContext *src_dc = decode_ctx(src->internal);
2244+ DecodeContext *dst_dc = decode_ctx(dst->internal);
2245+
2246+ ff_refstruct_replace(&dst_dc->lcevc, src_dc->lcevc);
2247+}
2248+
2249+void ff_decode_internal_uninit(AVCodecContext *avctx)
2250+{
2251+ AVCodecInternal *avci = avctx->internal;
2252+ DecodeContext *dc = decode_ctx(avci);
2253+
2254+ ff_refstruct_unref(&dc->lcevc);
2255+}
libavcodec/lcevcdec.c+319−0
@@ -0,0 +1,319 @@
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+int ff_lcevc_alloc(FFLCEVCContext **plcevc)
305+{
306+ 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+ *plcevc = lcevc;
313+ return 0;
314+}
315+
316+void ff_lcevc_unref(void *opaque)
317+{
318+ ff_refstruct_unref(&opaque);
319+}
libavcodec/lcevcdec.h+42−0
@@ -0,0 +1,42 @@
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+#ifndef AVCODEC_LCEVCDEC_H
20+#define AVCODEC_LCEVCDEC_H
21+
22+#include "config_components.h"
23+
24+#include <stdint.h>
25+#if CONFIG_LIBLCEVC_DEC
26+#include <LCEVC/lcevc_dec.h>
27+#else
28+typedef uintptr_t LCEVC_DecoderHandle;
29+#endif
30+#include "refstruct.h"
31+
32+typedef struct FFLCEVCContext {
33+ LCEVC_DecoderHandle decoder;
34+ int initialized;
35+} FFLCEVCContext;
36+
37+struct AVFrame;
38+
39+int ff_lcevc_alloc(FFLCEVCContext **plcevc);
40+int ff_lcevc_process(void *logctx, struct AVFrame *frame);
41+void ff_lcevc_unref(void *opaque);
42+#endif /* AVCODEC_LCEVCDEC_H */
libavcodec/pthread_frame.c+3−0
@@ -406,6 +406,7 @@ FF_ENABLE_DEPRECATION_WARNINGS · 405 unmodified lines
406406 dst->hwaccel_flags = src->hwaccel_flags;
407407
408408 ff_refstruct_replace(&dst->internal->pool, src->internal->pool);
409+ ff_decode_internal_sync(dst, src);
409410 }
410411
411412 if (for_user) {
@@ -782,6 +783,7 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) · 370 unmodified lines
782783 ff_refstruct_unref(&ctx->internal->pool);
783784 av_packet_free(&ctx->internal->in_pkt);
784785 av_packet_free(&ctx->internal->last_pkt_props);
786+ ff_decode_internal_uninit(ctx);
785787 av_freep(&ctx->internal);
786788 av_buffer_unref(&ctx->hw_frames_ctx);
787789 av_frame_side_data_free(&ctx->decoded_side_data,
@@ -845,6 +847,7 @@ static av_cold int init_thread(PerThreadContext *p, int *threads_to_free, · 57 unmodified lines
845847 copy->internal = ff_decode_internal_alloc();
846848 if (!copy->internal)
847849 return AVERROR(ENOMEM);
850+ ff_decode_internal_sync(copy, avctx);
848851 copy->internal->thread_ctx = p;
849852 copy->internal->progress_frame_pool = avctx->internal->progress_frame_pool;
850853

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t