History

avcodec/evc_decoder: Provided support for EVC decoder

- Added EVC decoder wrapper - Changes in project configuration file and libavcodec Makefile - Added documentation for xevd wrapper

Dawid Kozinski committed 3 years ago

Commit cfe29471 parent c59a96f6 files · +579 −3Browse files

Unified · Split

6 files
  1. configure +4 −0
  2. doc/decoders.texi +24 −0
  3. doc/general_contents.texi +11 −3
  4. libavcodec/Makefile +1 −0
  5. libavcodec/allcodecs.c +1 −0
  6. libavcodec/libxevd.c +538 −0
configure+4−0
@@ -290,6 +290,7 @@ External library support: · 289 unmodified lines
290290 --enable-libx264 enable H.264 encoding via x264 [no]
291291 --enable-libx265 enable HEVC encoding via x265 [no]
292292 --enable-libxeve enable EVC encoding via libxeve [no]
293+ --enable-libxevd enable EVC decoding via libxevd [no]
293294 --enable-libxavs enable AVS encoding via xavs [no]
294295 --enable-libxavs2 enable AVS2 encoding via xavs2 [no]
295296 --enable-libxcb enable X11 grabbing using XCB [autodetect]
@@ -1902,6 +1903,7 @@ EXTERNAL_LIBRARY_LIST=" · 1606 unmodified lines
19021903 libvorbis
19031904 libvpx
19041905 libwebp
1906+ libxevd
19051907 libxeve
19061908 libxml2
19071909 libzimg
@@ -3460,6 +3462,7 @@ libx265_encoder_deps="libx265" · 1552 unmodified lines
34603462 libx265_encoder_select="atsc_a53"
34613463 libxavs_encoder_deps="libxavs"
34623464 libxavs2_encoder_deps="libxavs2"
3465+libxevd_decoder_deps="libxevd"
34633466 libxeve_encoder_deps="libxeve"
34643467 libxvid_encoder_deps="libxvid"
34653468 libzvbi_teletext_decoder_deps="libzvbi"
@@ -6875,6 +6878,7 @@ enabled libx265 && require_pkg_config libx265 x265 x265.h x265_api_get · 3409 unmodified lines
68756878 require_cpp_condition libx265 x265.h "X265_BUILD >= 89"
68766879 enabled libxavs && require libxavs "stdint.h xavs.h" xavs_encoder_encode "-lxavs $pthreads_extralibs $libm_extralibs"
68776880 enabled libxavs2 && require_pkg_config libxavs2 "xavs2 >= 1.3.0" "stdint.h xavs2.h" xavs2_api_get
6881+enabled libxevd && require_pkg_config libxevd "xevd >= 0.4.1" "xevd.h" xevd_decode
68786882 enabled libxeve && require_pkg_config libxeve "xeve >= 0.4.3" "xeve.h" xeve_encode
68796883 enabled libxvid && require libxvid xvid.h xvid_global -lxvidcore
68806884 enabled libzimg && require_pkg_config libzimg "zimg >= 2.7.0" zimg.h zimg_get_api_version
doc/decoders.texi+24−0
@@ -130,6 +130,30 @@ Set amount of frame threads to use during decoding. The default value is 0 (auto · 129 unmodified lines
130130
131131 @end table
132132
133+@section libxevd
134+
135+eXtra-fast Essential Video Decoder (XEVD) MPEG-5 EVC decoder wrapper.
136+
137+This decoder requires the presence of the libxevd headers and library
138+during configuration. You need to explicitly configure the build with
139+@option{--enable-libxevd}.
140+
141+The xevd project website is at @url{https://github.com/mpeg5/xevd}.
142+
143+@subsection Options
144+
145+The following options are supported by the libxevd wrapper.
146+The xevd-equivalent options or values are listed in parentheses for easy migration.
147+
148+To get a more accurate and extensive documentation of the libxevd options,
149+invoke the command @code{xevd_app --help} or consult the libxevd documentation.
150+
151+@table @option
152+@item threads (@emph{threads})
153+Force to use a specific number of threads
154+
155+@end table
156+
133157 @section QSV Decoders
134158
135159 The family of Intel QuickSync Video decoders (VC1, MPEG-2, H.264, HEVC,
doc/general_contents.texi+11−3
@@ -351,6 +351,14 @@ Go to @url{https://github.com/mpeg5/xeve} and follow the instructions for · 350 unmodified lines
351351 installing the XEVE library. Then pass @code{--enable-libxeve} to configure to
352352 enable it.
353353
354+@section eXtra-fast Essential Video Decoder (XEVD)
355+
356+FFmpeg can make use of the XEVD library for EVC video decoding.
357+
358+Go to @url{https://github.com/mpeg5/xevd} and follow the instructions for
359+installing the XEVD library. Then pass @code{--enable-libxevd} to configure to
360+enable it.
361+
354362 @section ZVBI
355363
356364 ZVBI is a VBI decoding library which can be used by FFmpeg to decode DVB
@@ -606,7 +614,7 @@ library: · 249 unmodified lines
606614 @item raw DTS @tab X @tab X
607615 @item raw DTS-HD @tab @tab X
608616 @item raw E-AC-3 @tab X @tab X
609−@item raw EVC @tab X @tab
617+@item raw EVC @tab X @tab X
610618 @item raw FLAC @tab X @tab X
611619 @item raw GSM @tab @tab X
612620 @item raw H.261 @tab X @tab X
@@ -953,8 +961,8 @@ following image formats are supported: · 340 unmodified lines
953961 @item Electronic Arts TQI video @tab @tab X
954962 @item Escape 124 @tab @tab X
955963 @item Escape 130 @tab @tab X
956−@item EVC / MPEG-5 Part 1 @tab E @tab
957− @tab encoding supported through external library libxeve
964+@item EVC / MPEG-5 Part 1 @tab E @tab E
965+ @tab encoding and decoding supported through external libraries libxeve and libxevd
958966 @item FFmpeg video codec #1 @tab X @tab X
959967 @tab lossless codec (fourcc: FFV1)
960968 @item Flash Screen Video v1 @tab X @tab X
libavcodec/Makefile+1−0
@@ -1149,6 +1149,7 @@ OBJS-$(CONFIG_LIBX264_ENCODER) += libx264.o · 1148 unmodified lines
11491149 OBJS-$(CONFIG_LIBX265_ENCODER) += libx265.o
11501150 OBJS-$(CONFIG_LIBXAVS_ENCODER) += libxavs.o
11511151 OBJS-$(CONFIG_LIBXAVS2_ENCODER) += libxavs2.o
1152+OBJS-$(CONFIG_LIBXEVD_DECODER) += libxevd.o
11521153 OBJS-$(CONFIG_LIBXEVE_ENCODER) += libxeve.o
11531154 OBJS-$(CONFIG_LIBXVID_ENCODER) += libxvid.o
11541155 OBJS-$(CONFIG_LIBZVBI_TELETEXT_DECODER) += libzvbi-teletextdec.o ass.o
libavcodec/allcodecs.c+1−0
@@ -822,6 +822,7 @@ extern LIBX264_CONST FFCodec ff_libx264_encoder; · 821 unmodified lines
822822 extern const FFCodec ff_libx264rgb_encoder;
823823 extern FFCodec ff_libx265_encoder;
824824 extern const FFCodec ff_libxeve_encoder;
825+extern const FFCodec ff_libxevd_decoder;
825826 extern const FFCodec ff_libxavs_encoder;
826827 extern const FFCodec ff_libxavs2_encoder;
827828 extern const FFCodec ff_libxvid_encoder;
libavcodec/libxevd.c+538−0
@@ -0,0 +1,538 @@
1+/*
2+ * libxevd decoder
3+ * EVC (MPEG-5 Essential Video Coding) decoding using XEVD MPEG-5 EVC decoder library
4+ *
5+ * Copyright (C) 2021 Dawid Kozinski <d.kozinski@samsung.com>
6+ *
7+ * This file is part of FFmpeg.
8+ *
9+ * FFmpeg is free software; you can redistribute it and/or
10+ * modify it under the terms of the GNU Lesser General Public
11+ * License as published by the Free Software Foundation; either
12+ * version 2.1 of the License, or (at your option) any later version.
13+ *
14+ * FFmpeg is distributed in the hope that it will be useful,
15+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+ * Lesser General Public License for more details.
18+ *
19+ * You should have received a copy of the GNU Lesser General Public
20+ * License along with FFmpeg; if not, write to the Free Software
21+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22+ */
23+
24+#include <float.h>
25+#include <stdlib.h>
26+
27+#include <xevd.h>
28+
29+#include "libavutil/internal.h"
30+#include "libavutil/common.h"
31+#include "libavutil/opt.h"
32+#include "libavutil/pixdesc.h"
33+#include "libavutil/pixfmt.h"
34+#include "libavutil/imgutils.h"
35+#include "libavutil/cpu.h"
36+
37+#include "avcodec.h"
38+#include "internal.h"
39+#include "packet_internal.h"
40+#include "codec_internal.h"
41+#include "profiles.h"
42+#include "decode.h"
43+
44+#define XEVD_PARAM_BAD_NAME -1
45+#define XEVD_PARAM_BAD_VALUE -2
46+
47+#define EVC_NAL_HEADER_SIZE 2 /* byte */
48+
49+/**
50+ * The structure stores all the states associated with the instance of Xeve MPEG-5 EVC decoder
51+ */
52+typedef struct XevdContext {
53+ const AVClass *class;
54+
55+ XEVD id; // XEVD instance identifier @see xevd.h
56+ XEVD_CDSC cdsc; // decoding parameters @see xevd.h
57+
58+ // If end of stream occurs it is required "flushing" (aka draining) the codec,
59+ // as the codec might buffer multiple frames or packets internally.
60+ int draining_mode; // The flag is set if codec enters draining mode.
61+
62+ AVPacket *pkt; // access unit (a set of NAL units that are consecutive in decoding order and containing exactly one encoded image)
63+} XevdContext;
64+
65+/**
66+ * The function populates the XEVD_CDSC structure.
67+ * XEVD_CDSC contains all decoder parameters that should be initialized before its use.
68+ *
69+ * @param[in] avctx codec context
70+ * @param[out] cdsc contains all decoder parameters that should be initialized before its use
71+ *
72+ */
73+static void get_conf(AVCodecContext *avctx, XEVD_CDSC *cdsc)
74+{
75+ int cpu_count = av_cpu_count();
76+
77+ /* clear XEVS_CDSC structure */
78+ memset(cdsc, 0, sizeof(XEVD_CDSC));
79+
80+ /* init XEVD_CDSC */
81+ if (avctx->thread_count <= 0)
82+ cdsc->threads = (cpu_count < XEVD_MAX_TASK_CNT) ? cpu_count : XEVD_MAX_TASK_CNT;
83+ else if (avctx->thread_count > XEVD_MAX_TASK_CNT)
84+ cdsc->threads = XEVD_MAX_TASK_CNT;
85+ else
86+ cdsc->threads = avctx->thread_count;
87+}
88+
89+/**
90+ * Read NAL unit length
91+ * @param bs input data (bitstream)
92+ * @return the length of NAL unit on success, 0 value on failure
93+ */
94+static uint32_t read_nal_unit_length(const uint8_t *bs, int bs_size, AVCodecContext *avctx)
95+{
96+ uint32_t len = 0;
97+ XEVD_INFO info;
98+ int ret;
99+
100+ if (bs_size == XEVD_NAL_UNIT_LENGTH_BYTE) {
101+ ret = xevd_info((void *)bs, XEVD_NAL_UNIT_LENGTH_BYTE, 1, &info);
102+ if (XEVD_FAILED(ret)) {
103+ av_log(avctx, AV_LOG_ERROR, "Cannot get bitstream information\n");
104+ return 0;
105+ }
106+ len = info.nalu_len;
107+ if (len == 0) {
108+ av_log(avctx, AV_LOG_ERROR, "Invalid bitstream size! [%d]\n", bs_size);
109+ return 0;
110+ }
111+ }
112+
113+ return len;
114+}
115+
116+/**
117+ * @param[in] xectx the structure that stores all the state associated with the instance of Xeve MPEG-5 EVC decoder
118+ * @param[out] avctx codec context
119+ * @return 0 on success, negative value on failure
120+ */
121+static int export_stream_params(const XevdContext *xectx, AVCodecContext *avctx)
122+{
123+ int ret;
124+ int size;
125+ int color_space;
126+
127+ avctx->pix_fmt = AV_PIX_FMT_YUV420P10;
128+
129+ size = 4;
130+ ret = xevd_config(xectx->id, XEVD_CFG_GET_CODED_WIDTH, &avctx->coded_width, &size);
131+ if (XEVD_FAILED(ret)) {
132+ av_log(avctx, AV_LOG_ERROR, "Failed to get coded_width\n");
133+ return AVERROR_EXTERNAL;
134+ }
135+
136+ ret = xevd_config(xectx->id, XEVD_CFG_GET_CODED_HEIGHT, &avctx->coded_height, &size);
137+ if (XEVD_FAILED(ret)) {
138+ av_log(avctx, AV_LOG_ERROR, "Failed to get coded_height\n");
139+ return AVERROR_EXTERNAL;
140+ }
141+
142+ ret = xevd_config(xectx->id, XEVD_CFG_GET_WIDTH, &avctx->width, &size);
143+ if (XEVD_FAILED(ret)) {
144+ av_log(avctx, AV_LOG_ERROR, "Failed to get width\n");
145+ return AVERROR_EXTERNAL;
146+ }
147+
148+ ret = xevd_config(xectx->id, XEVD_CFG_GET_HEIGHT, &avctx->height, &size);
149+ if (XEVD_FAILED(ret)) {
150+ av_log(avctx, AV_LOG_ERROR, "Failed to get height\n");
151+ return AVERROR_EXTERNAL;
152+ }
153+
154+ ret = xevd_config(xectx->id, XEVD_CFG_GET_COLOR_SPACE, &color_space, &size);
155+ if (XEVD_FAILED(ret)) {
156+ av_log(avctx, AV_LOG_ERROR, "Failed to get color_space\n");
157+ return AVERROR_EXTERNAL;
158+ }
159+ switch(color_space) {
160+ case XEVD_CS_YCBCR400_10LE:
161+ avctx->pix_fmt = AV_PIX_FMT_GRAY10LE;
162+ break;
163+ case XEVD_CS_YCBCR420_10LE:
164+ avctx->pix_fmt = AV_PIX_FMT_YUV420P10LE;
165+ break;
166+ case XEVD_CS_YCBCR422_10LE:
167+ avctx->pix_fmt = AV_PIX_FMT_YUV422P10LE;
168+ break;
169+ case XEVD_CS_YCBCR444_10LE:
170+ avctx->pix_fmt = AV_PIX_FMT_YUV444P10LE;
171+ break;
172+ default:
173+ av_log(avctx, AV_LOG_ERROR, "Unknown color space\n");
174+ avctx->pix_fmt = AV_PIX_FMT_NONE;
175+ return AVERROR_INVALIDDATA;
176+ }
177+
178+ // the function returns sps->num_reorder_pics
179+ ret = xevd_config(xectx->id, XEVD_CFG_GET_MAX_CODING_DELAY, &avctx->max_b_frames, &size);
180+ if (XEVD_FAILED(ret)) {
181+ av_log(avctx, AV_LOG_ERROR, "Failed to get max_coding_delay\n");
182+ return AVERROR_EXTERNAL;
183+ }
184+
185+ avctx->has_b_frames = (avctx->max_b_frames) ? 1 : 0;
186+
187+ return 0;
188+}
189+
190+/**
191+ * @brief Copy image in imgb to frame.
192+ *
193+ * @param avctx codec context
194+ * @param[in] imgb
195+ * @param[out] frame
196+ * @return 0 on success, negative value on failure
197+ */
198+static int libxevd_image_copy(struct AVCodecContext *avctx, XEVD_IMGB *imgb, struct AVFrame *frame)
199+{
200+ int ret;
201+ if (imgb->cs != XEVD_CS_YCBCR420_10LE) {
202+ av_log(avctx, AV_LOG_ERROR, "Not supported pixel format: %s\n", av_get_pix_fmt_name(avctx->pix_fmt));
203+ return AVERROR_INVALIDDATA;
204+ }
205+
206+ if (imgb->w[0] != avctx->width || imgb->h[0] != avctx->height) { // stream resolution changed
207+ if (ff_set_dimensions(avctx, imgb->w[0], imgb->h[0]) < 0) {
208+ av_log(avctx, AV_LOG_ERROR, "Cannot set new dimension\n");
209+ return AVERROR_INVALIDDATA;
210+ }
211+ }
212+
213+ if (ret = ff_get_buffer(avctx, frame, 0) < 0)
214+ return ret;
215+
216+ av_image_copy(frame->data, frame->linesize, (const uint8_t **)imgb->a,
217+ imgb->s, avctx->pix_fmt,
218+ imgb->w[0], imgb->h[0]);
219+
220+ return 0;
221+}
222+
223+/**
224+ * Initialize decoder
225+ * Create a decoder instance and allocate all the needed resources
226+ *
227+ * @param avctx codec context
228+ * @return 0 on success, negative error code on failure
229+ */
230+static av_cold int libxevd_init(AVCodecContext *avctx)
231+{
232+ XevdContext *xectx = avctx->priv_data;
233+ XEVD_CDSC *cdsc = &(xectx->cdsc);
234+
235+ /* read configurations and set values for created descriptor (XEVD_CDSC) */
236+ get_conf(avctx, cdsc);
237+
238+ /* create decoder */
239+ xectx->id = xevd_create(&(xectx->cdsc), NULL);
240+ if (xectx->id == NULL) {
241+ av_log(avctx, AV_LOG_ERROR, "Cannot create XEVD encoder\n");
242+ return AVERROR_EXTERNAL;
243+ }
244+
245+ xectx->draining_mode = 0;
246+ xectx->pkt = av_packet_alloc();
247+ if (!xectx->pkt) {
248+ av_log(avctx, AV_LOG_ERROR, "Cannot allocate memory for AVPacket\n");
249+ return AVERROR(ENOMEM);
250+ }
251+
252+ return 0;
253+}
254+
255+/**
256+ * Decode frame with decoupled packet/frame dataflow
257+ *
258+ * @param avctx codec context
259+ * @param[out] frame decoded frame
260+ *
261+ * @return 0 on success, negative error code on failure
262+ */
263+static int libxevd_receive_frame(AVCodecContext *avctx, AVFrame *frame)
264+{
265+ XevdContext *xectx = avctx->priv_data;
266+ AVPacket *pkt = xectx->pkt;
267+ XEVD_IMGB *imgb = NULL;
268+
269+ int xevd_ret = 0;
270+ int ret = 0;
271+
272+ // obtain access unit (input data) - a set of NAL units that are consecutive in decoding order and containing exactly one encoded image
273+ ret = ff_decode_get_packet(avctx, pkt);
274+ if (ret < 0 && ret != AVERROR_EOF) {
275+ av_packet_unref(pkt);
276+
277+ return ret;
278+ } else if(ret == AVERROR_EOF && xectx->draining_mode == 0) { // End of stream situations. Enter draining mode
279+
280+ xectx->draining_mode = 1;
281+ av_packet_unref(pkt);
282+ }
283+
284+ if (pkt->size > 0) {
285+ int bs_read_pos = 0;
286+ XEVD_STAT stat;
287+ XEVD_BITB bitb;
288+ int nalu_size;
289+ AVPacket* pkt_au;
290+ imgb = NULL;
291+
292+ pkt_au = av_packet_clone(pkt);
293+ if (!pkt_au) {
294+ av_log(avctx, AV_LOG_ERROR, "Cannot clone AVPacket\n");
295+ av_packet_unref(pkt);
296+ return AVERROR(ENOMEM);
297+ }
298+
299+ av_packet_unref(pkt);
300+
301+ // get all nal units from AU
302+ while(pkt_au->size > (bs_read_pos + XEVD_NAL_UNIT_LENGTH_BYTE)) {
303+ memset(&stat, 0, sizeof(XEVD_STAT));
304+
305+ nalu_size = read_nal_unit_length(pkt_au->data + bs_read_pos, XEVD_NAL_UNIT_LENGTH_BYTE, avctx);
306+ if (nalu_size == 0) {
307+ av_log(avctx, AV_LOG_ERROR, "Invalid bitstream\n");
308+ av_packet_free(&pkt_au);
309+ ret = AVERROR_INVALIDDATA;
310+
311+ return ret;
312+ }
313+ bs_read_pos += XEVD_NAL_UNIT_LENGTH_BYTE;
314+
315+ bitb.addr = pkt_au->data + bs_read_pos;
316+ bitb.ssize = nalu_size;
317+ bitb.pdata[0] = pkt_au;
318+ bitb.ts[XEVD_TS_DTS] = pkt_au->dts;
319+
320+ /* main decoding block */
321+ xevd_ret = xevd_decode(xectx->id, &bitb, &stat);
322+ if (XEVD_FAILED(xevd_ret)) {
323+ av_log(avctx, AV_LOG_ERROR, "Failed to decode bitstream\n");
324+ av_packet_free(&pkt_au);
325+
326+ return AVERROR_EXTERNAL;
327+ }
328+
329+ bs_read_pos += nalu_size;
330+
331+ if (stat.nalu_type == XEVD_NUT_SPS) { // EVC stream parameters changed
332+ if ((ret = export_stream_params(xectx, avctx)) != 0) {
333+ av_log(avctx, AV_LOG_ERROR, "Failed to export stream params\n");
334+ av_packet_free(&pkt_au);
335+
336+ return ret;
337+ }
338+ }
339+
340+ if (stat.read != nalu_size)
341+ av_log(avctx, AV_LOG_INFO, "Different reading of bitstream (in:%d, read:%d)\n,", nalu_size, stat.read);
342+
343+ // stat.fnum - has negative value if the decoded data is not frame
344+ if (stat.fnum >= 0) {
345+
346+ xevd_ret = xevd_pull(xectx->id, &imgb); // The function returns a valid image only if the return code is XEVD_OK
347+
348+ if (XEVD_FAILED(xevd_ret)) {
349+ av_log(avctx, AV_LOG_ERROR, "Failed to pull the decoded image (xevd error code: %d, frame#=%d)\n", xevd_ret, stat.fnum);
350+
351+ av_packet_free(&pkt_au);
352+
353+ return AVERROR_EXTERNAL;
354+ } else if (xevd_ret == XEVD_OK_FRM_DELAYED) {
355+ if(bs_read_pos == pkt_au->size) {
356+ return AVERROR(EAGAIN);
357+ }
358+ } else { // XEVD_OK
359+ if (!imgb) {
360+ if(bs_read_pos == pkt_au->size) {
361+ av_log(avctx, AV_LOG_ERROR, "Invalid decoded image data\n");
362+
363+ av_packet_free(&pkt_au);
364+ return AVERROR(EAGAIN);
365+ }
366+ } else {
367+ // got frame
368+ AVPacket* pkt_au_imgb = (AVPacket*)imgb->pdata[0];
369+ if(!pkt_au_imgb) {
370+ av_log(avctx, AV_LOG_ERROR, "Invalid data needed to fill frame properties\n");
371+
372+ av_packet_free(&pkt_au);
373+ av_frame_unref(frame);
374+
375+ imgb->release(imgb);
376+ imgb = NULL;
377+
378+ return AVERROR_INVALIDDATA;
379+ }
380+
381+ ret = libxevd_image_copy(avctx, imgb, frame);
382+ if(ret < 0) {
383+ av_log(avctx, AV_LOG_ERROR, "Image copying error\n");
384+
385+ av_packet_free(&pkt_au_imgb);
386+ av_frame_unref(frame);
387+
388+ imgb->release(imgb);
389+ imgb = NULL;
390+
391+ return ret;
392+ }
393+
394+ // use ff_decode_frame_props_from_pkt() to fill frame properties
395+ ret = ff_decode_frame_props_from_pkt(avctx, frame, pkt_au_imgb);
396+ if (ret < 0) {
397+ av_log(avctx, AV_LOG_ERROR, "ff_decode_frame_props_from_pkt error\n");
398+
399+ av_packet_free(&pkt_au_imgb);
400+ av_frame_unref(frame);
401+
402+ imgb->release(imgb);
403+ imgb = NULL;
404+
405+ return ret;
406+ }
407+
408+ frame->pkt_dts = imgb->ts[XEVD_TS_DTS];
409+ frame->pts = imgb->ts[XEVD_TS_PTS];
410+
411+ av_packet_free(&pkt_au_imgb);
412+
413+ // xevd_pull uses pool of objects of type XEVD_IMGB.
414+ // The pool size is equal MAX_PB_SIZE (26), so release object when it is no more needed
415+ imgb->release(imgb);
416+ imgb = NULL;
417+ }
418+ }
419+ }
420+ }
421+ } else { // decoder draining mode handling
422+
423+ xevd_ret = xevd_pull(xectx->id, &imgb);
424+
425+ if (xevd_ret == XEVD_ERR_UNEXPECTED) { // draining process completed
426+ av_log(avctx, AV_LOG_DEBUG, "Draining process completed\n");
427+
428+ return AVERROR_EOF;
429+ } else if (XEVD_FAILED(xevd_ret)) { // handle all other errors
430+ av_log(avctx, AV_LOG_ERROR, "Failed to pull the decoded image (xevd error code: %d)\n", xevd_ret);
431+
432+ return AVERROR_EXTERNAL;
433+ } else { // XEVD_OK
434+ AVPacket* pkt_au_imgb;
435+ if (!imgb) {
436+ av_log(avctx, AV_LOG_ERROR, "Invalid decoded image data\n");
437+
438+ return AVERROR_EXTERNAL;
439+ }
440+
441+ pkt_au_imgb = (AVPacket*)imgb->pdata[0];
442+ if(!pkt_au_imgb) {
443+ av_log(avctx, AV_LOG_ERROR, "Invalid data needed to fill frame properties\n");
444+
445+ imgb->release(imgb);
446+ imgb = NULL;
447+
448+ av_frame_unref(frame);
449+
450+ return AVERROR_INVALIDDATA;
451+ }
452+
453+ // got frame
454+ ret = libxevd_image_copy(avctx, imgb, frame);
455+ if(ret < 0) {
456+ av_packet_free(&pkt_au_imgb);
457+ av_frame_unref(frame);
458+
459+ imgb->release(imgb);
460+ imgb = NULL;
461+
462+ return ret;
463+ }
464+ // use ff_decode_frame_props_from_pkt() to fill frame properties
465+ ret = ff_decode_frame_props_from_pkt(avctx, frame, pkt_au_imgb);
466+ if (ret < 0) {
467+ av_log(avctx, AV_LOG_ERROR, "ff_decode_frame_props_from_pkt error\n");
468+
469+ av_packet_free(&pkt_au_imgb);
470+ av_frame_unref(frame);
471+
472+ imgb->release(imgb);
473+ imgb = NULL;
474+
475+ return ret;
476+ }
477+
478+ frame->pkt_dts = imgb->ts[XEVD_TS_DTS];
479+ frame->pts = imgb->ts[XEVD_TS_PTS];
480+
481+ av_packet_free(&pkt_au_imgb);
482+
483+ // xevd_pull uses pool of objects of type XEVD_IMGB.
484+ // The pool size is equal MAX_PB_SIZE (26), so release object when it is no more needed
485+ imgb->release(imgb);
486+ imgb = NULL;
487+
488+ return 0;
489+ }
490+ }
491+
492+ return ret;
493+}
494+
495+/**
496+ * Destroy decoder
497+ *
498+ * @param avctx codec context
499+ * @return 0 on success
500+ */
501+static av_cold int libxevd_close(AVCodecContext *avctx)
502+{
503+ XevdContext *xectx = avctx->priv_data;
504+ if (xectx->id) {
505+ xevd_delete(xectx->id);
506+ xectx->id = NULL;
507+ }
508+
509+ xectx->draining_mode = 0;
510+ av_packet_free(&xectx->pkt);
511+
512+ return 0;
513+}
514+
515+#define OFFSET(x) offsetof(XevdContext, x)
516+#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
517+
518+static const AVClass libxevd_class = {
519+ .class_name = "libxevd",
520+ .item_name = av_default_item_name,
521+ .version = LIBAVUTIL_VERSION_INT,
522+};
523+
524+const FFCodec ff_libxevd_decoder = {
525+ .p.name = "evc",
526+ .p.long_name = NULL_IF_CONFIG_SMALL("EVC / MPEG-5 Essential Video Coding (EVC)"),
527+ .p.type = AVMEDIA_TYPE_VIDEO,
528+ .p.id = AV_CODEC_ID_EVC,
529+ .init = libxevd_init,
530+ FF_CODEC_RECEIVE_FRAME_CB(libxevd_receive_frame),
531+ .close = libxevd_close,
532+ .priv_data_size = sizeof(XevdContext),
533+ .p.priv_class = &libxevd_class,
534+ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_AVOID_PROBING,
535+ .p.profiles = NULL_IF_CONFIG_SMALL(ff_evc_profiles),
536+ .p.wrapper_name = "libxevd",
537+ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_SETS_PKT_DTS | FF_CODEC_CAP_SETS_FRAME_PROPS
538+};

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