PR #25142 opened by rnissl URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25142 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25142.patch
libgpujpeg encodes CUDA frames to JPEG through CESNET GPUJPEG. On the same 106 frames it is faster than mjpeg_nvjpeg and, at the highest quality that stays under the CPU JPEG size, also closer to that size. 106 frames, 7680x3840, chroma 4:2:0. The CPU reference is mjpeg -qscale:v 2: 291564015 bytes, wall time 25.638 s. | encoder | quality | bytes | share of mjpeg | wall time | | --- | ---: | ---: | ---: | ---: | | mjpeg | qscale 2 | 291564015 | 100% | 25.638 s | | mjpeg_nvjpeg | 83 | 245574607 | 84.2% | 24.138 s | | mjpeg_nvjpeg | 87 | 279686107 | 95.9% | 23.979 s | | libgpujpeg | 84 | 287545054 | 98.6% | 16.773 s | 87 is the highest nvJPEG quality that stays under the CPU sum. 88 crosses it at 296610157 bytes, and the wall time stays about 24 s. 84 is the highest GPUJPEG quality under that sum. 85 crosses it at 293380648 bytes, and the wall time stays about 16.8 s. Quality 84 is therefore both the closer file size and the shorter run: 16.773 s against 23.979 s. User CPU time is about 9 s for either GPU encoder. The CPU encoder's user time is 111.406 s; its wall time is shorter because several cores overlap. Input is CUDA yuv444p, full-range BT.601. The encoder does not convert. 4:4:4 passes linesize minus width as width_padding and does not pack the planes. 4:2:0 uses the library color kernel, which ignores that padding, so linesize must equal the width. Build with --enable-libgpujpeg and --enable-nonfree. ffnvcodec is required. COPYING is BSD 2-Clause. The DCT source carries the NVIDIA 1993-2010 EULA, and a shared build links the CUDA runtime, so the FFmpeg binary is unredistributable. That finding is comment 71750 on #24727. This request does not change mjpeg_nvjpeg. Head a6e4ab15e0 on master 2fd864c2e9. libavcodec minor goes from 20 to 21, so it will conflict with #24727 on version.h. ## Test plan - [ ] CI on this pull request - [ ] configure with --enable-libgpujpeg and --enable-nonfree - [ ] encode a CUDA yuv444p frame to 4:4:4 and, when linesize equals the width, to 4:2:0 From a6e4ab15e0b2cfff20af741acc24f64bcf31f778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reinhard=20Ni=C3=9Fl?= <[email protected]> Date: Sat, 17 Oct 2026 08:31:14 +0200 Subject: [PATCH] avcodec: add a CUDA JPEG encoder through libgpujpeg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CESNET GPUJPEG encodes CUDA yuv444p in place. 4:4:4 passes the frame stride as width_padding. 4:2:0 needs linesize equal to the width, because that path ignores the padding. The library COPYING file is BSD 2-Clause, but the DCT source carries an NVIDIA EULA and the build links the CUDA runtime, so the encoder depends on the nonfree switch. On 106 frames of 7680x3840 4:2:0, the largest output that stays under the CPU mjpeg -qscale:v 2 sum is quality 84: 287545054 bytes in 16.773 s. mjpeg_nvjpeg reaches quality 87 at 279686107 bytes in 23.979 s before it crosses that sum. The GPUJPEG result is both closer to the CPU size and faster. Co-authored-by: Cursor <[email protected]> Signed-off-by: Reinhard Nißl <[email protected]> --- Changelog | 1 + configure | 4 + doc/encoders.texi | 28 +++ doc/general_contents.texi | 8 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/libgpujpegenc.c | 376 +++++++++++++++++++++++++++++++++++++ libavcodec/version.h | 2 +- 8 files changed, 420 insertions(+), 1 deletion(-) create mode 100644 libavcodec/libgpujpegenc.c diff --git a/Changelog b/Changelog index 32e7c8bfe7..29180b6e4c 100644 --- a/Changelog +++ b/Changelog @@ -2,6 +2,7 @@ Entries are sorted chronologically from oldest to youngest within each release, releases are sorted from youngest to oldest. version <next>: +- JPEG encoding via libgpujpeg - ASTC image encoding and decoding via libastcenc, with .astc and KTX 1.0 muxers and demuxers - extensively improved AAC encoder - APV Vulkan encoder diff --git a/configure b/configure index c97ddb186f..6a3438c24c 100755 --- a/configure +++ b/configure @@ -240,6 +240,7 @@ External library support: --enable-libfribidi enable libfribidi, improves drawtext filter [no] --enable-libharfbuzz enable libharfbuzz, needed for drawtext filter [no] --enable-libgme enable Game Music Emu via libgme [no] + --enable-libgpujpeg enable JPEG encoding via GPUJPEG [no] --enable-libgsm enable GSM de/encoding via libgsm [no] --enable-libiec61883 enable iec61883 via libiec61883 [no] --enable-libilbc enable iLBC de/encoding via libilbc [no] @@ -2033,6 +2034,7 @@ EXTERNAL_LIBRARY_NONFREE_LIST=" decklink libfdk_aac libfdk_xhe_aac + libgpujpeg libmpeghdec " @@ -3811,6 +3813,7 @@ libfdk_aac_encoder_select="audio_frame_queue" libfdk_xhe_aac_encoder_deps="libfdk_xhe_aac" libfdk_xhe_aac_encoder_select="audio_frame_queue" libgme_demuxer_deps="libgme" +libgpujpeg_encoder_deps="libgpujpeg ffnvcodec" libgsm_decoder_deps="libgsm" libgsm_encoder_deps="libgsm" libgsm_ms_decoder_deps="libgsm" @@ -7254,6 +7257,7 @@ enabled libfribidi && require_pkg_config libfribidi fribidi fribidi.h fri enabled libharfbuzz && require_pkg_config libharfbuzz harfbuzz hb.h hb_buffer_create enabled libgme && { check_pkg_config libgme libgme gme/gme.h gme_new_emu || require libgme gme/gme.h gme_new_emu -lgme -lstdc++; } +enabled libgpujpeg && require_pkg_config libgpujpeg libgpujpeg libgpujpeg/gpujpeg_encoder.h gpujpeg_encoder_create enabled libgsm && { for gsm_hdr in "gsm.h" "gsm/gsm.h"; do check_lib libgsm "${gsm_hdr}" gsm_create -lgsm && break; done || die "ERROR: libgsm not found"; } diff --git a/doc/encoders.texi b/doc/encoders.texi index 2c173ac916..82280546cc 100644 --- a/doc/encoders.texi +++ b/doc/encoders.texi @@ -1347,6 +1347,34 @@ a value of 3 produces a quantization table of all ones. @end table +@anchor{libgpujpeg} +@section libgpujpeg + +JPEG encoder through CESNET GPUJPEG. It encodes CUDA frames in place. +The input software format is @code{yuv444p}, full-range BT.601. + +Build it with @code{--enable-libgpujpeg} and @code{--enable-nonfree}. +GPUJPEG's COPYING file is BSD 2-Clause. The DCT implementation in the +library carries an NVIDIA EULA notice, and the library links the CUDA +runtime, so the FFmpeg binary is unredistributable. +@code{ffnvcodec} is required and is autodetected. + +The three planes must follow one another in one allocation. +Row padding is passed through as @code{width_padding} and needs no extra +copy for 4:4:4 output. 4:2:0 output uses the library color kernel, which +ignores that padding, so it requires @code{linesize} equal to the width. + +@subsection Options + +@table @option +@item quality +JPEG quality from 0 to 100. The default is 75. + +@item chroma +Output subsampling. @code{444} is the default. @code{420} requires a frame +whose line stride equals its width. +@end table + @anchor{wavpackenc} @section wavpack diff --git a/doc/general_contents.texi b/doc/general_contents.texi index 7032f140c6..fce6520090 100644 --- a/doc/general_contents.texi +++ b/doc/general_contents.texi @@ -365,6 +365,14 @@ constrained baseline profile and CABAC.) Using it is mostly useful for testing and for taking advantage of Cisco's patent portfolio license (@url{http://www.openh264.org/BINARY_LICENSE.txt}). +@section GPUJPEG + +FFmpeg can use the CESNET GPUJPEG library to encode CUDA frames to JPEG. +The library's COPYING file is BSD 2-Clause. Its DCT source also carries an +NVIDIA EULA notice, and the build links the CUDA runtime, so the resulting +binary is nonfree. Pass @code{--enable-libgpujpeg} and @code{--enable-nonfree} +to @file{./configure}. + @section OpenJPEG FFmpeg can use the OpenJPEG libraries for decoding/encoding J2K videos. Go to diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 249b0fe0b8..53131910b3 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1195,6 +1195,7 @@ OBJS-$(CONFIG_LIBDAVS2_DECODER) += libdavs2.o OBJS-$(CONFIG_LIBFDK_AAC_DECODER) += libfdk-aacdec.o OBJS-$(CONFIG_LIBFDK_AAC_ENCODER) += libfdk-aacenc.o OBJS-$(CONFIG_LIBFDK_XHE_AAC_ENCODER) += libfdk-xhe-aacenc.o +OBJS-$(CONFIG_LIBGPUJPEG_ENCODER) += libgpujpegenc.o OBJS-$(CONFIG_LIBGSM_DECODER) += libgsmdec.o OBJS-$(CONFIG_LIBGSM_ENCODER) += libgsmenc.o OBJS-$(CONFIG_LIBGSM_MS_DECODER) += libgsmdec.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index c344cb539e..b10ff71a57 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -786,6 +786,7 @@ extern const FFCodec ff_libdavs2_decoder; extern const FFCodec ff_libfdk_aac_encoder; extern const FFCodec ff_libfdk_aac_decoder; extern const FFCodec ff_libfdk_xhe_aac_encoder; +extern const FFCodec ff_libgpujpeg_encoder; extern const FFCodec ff_libgsm_encoder; extern const FFCodec ff_libgsm_decoder; extern const FFCodec ff_libgsm_ms_encoder; diff --git a/libavcodec/libgpujpegenc.c b/libavcodec/libgpujpegenc.c new file mode 100644 index 0000000000..90296455ab --- /dev/null +++ b/libavcodec/libgpujpegenc.c @@ -0,0 +1,376 @@ +/* + * JPEG encoder through CESNET GPUJPEG. + * + * Copyright (c) 2026 Reinhard Nißl + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include <libgpujpeg/gpujpeg_encoder.h> + +#include "libavutil/common.h" +#include "libavutil/cuda_check.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_cuda_internal.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "libavutil/rational.h" + +#include "avcodec.h" +#include "codec_internal.h" +#include "encode.h" +#include "hwconfig.h" + +#define CHECK_CU(x) FF_CUDA_CHECK_DL(avctx, s->hwctx->internal->cuda_dl, x) + +enum { + GPUJPEG_CHROMA_444 = 0, + GPUJPEG_CHROMA_420 = 1, +}; + +typedef struct GPUJPEGEncContext { + const AVClass *class; + + int quality; + int chroma; + + struct gpujpeg_encoder *encoder; + AVCUDADeviceContext *hwctx; + enum AVPixelFormat sw_format; + int csp_warned; +} GPUJPEGEncContext; + +static const AVCodecHWConfigInternal *const gpujpeg_hw_configs[] = { + HW_CONFIG_ENCODER_FRAMES(CUDA, CUDA), + HW_CONFIG_ENCODER_DEVICE(NONE, CUDA), + NULL +}; + +/** + * GPUJPEG writes square pixels. Store a non-square SAR in the JFIF APP0 + * density fields with units 0, which means an aspect ratio. + */ +static void gpujpeg_write_sar(AVCodecContext *avctx, uint8_t *data, int size) +{ + AVRational sar = avctx->sample_aspect_ratio; + int i; + + if (sar.num <= 0 || sar.den <= 0) + return; + if (sar.num > 65535 || sar.den > 65535) { + if (!av_reduce(&sar.num, &sar.den, avctx->sample_aspect_ratio.num, + avctx->sample_aspect_ratio.den, 65535)) + av_log(avctx, AV_LOG_WARNING, + "Cannot store exact sample aspect ratio %d:%d\n", + avctx->sample_aspect_ratio.num, + avctx->sample_aspect_ratio.den); + if (!sar.num) + sar = (AVRational) { 1, 65535 }; + else if (!sar.den) + sar = (AVRational) { 65535, 1 }; + } + if (size < 20 || data[0] != 0xff || data[1] != 0xd8) + goto missing; + i = 2; + while (i + 18 < size && data[i] == 0xff) { + int marker = data[i + 1]; + int len; + + if (marker == 0xd8 || marker == 0xd9 || (marker >= 0xd0 && marker <= 0xd7)) { + i += 2; + continue; + } + if (i + 4 > size) + break; + len = (data[i + 2] << 8) | data[i + 3]; + if (len < 2 || i + 2 + len > size) + break; + if (marker == 0xe0 && len >= 16 && !memcmp(data + i + 4, "JFIF\0", 5)) { + data[i + 11] = 0; + AV_WB16(data + i + 12, sar.num); + AV_WB16(data + i + 14, sar.den); + return; + } + i += 2 + len; + } +missing: + av_log(avctx, AV_LOG_WARNING, + "Sample aspect ratio %d:%d was not written; no JFIF APP0\n", + sar.num, sar.den); +} + +static void gpujpeg_warn_colorspace(AVCodecContext *avctx, const AVFrame *frame, + int *warned) +{ + if (*warned) + return; + if (frame->color_range && frame->color_range != AVCOL_RANGE_JPEG) { + av_log(avctx, AV_LOG_WARNING, + "JPEG stores full range; frame range is %s\n", + av_color_range_name(frame->color_range)); + *warned = 1; + } + if (frame->colorspace && frame->colorspace != AVCOL_SPC_BT470BG && + frame->colorspace != AVCOL_SPC_SMPTE170M) { + av_log(avctx, AV_LOG_WARNING, + "JPEG JFIF assumes BT.601; frame matrix is %s\n", + av_color_space_name(frame->colorspace)); + *warned = 1; + } +} + +static av_cold int gpujpeg_encode_init(AVCodecContext *avctx) +{ + GPUJPEGEncContext *s = avctx->priv_data; + AVHWFramesContext *frames_ctx; + CUcontext dummy; + int ret, pushed = 0; + + if (avctx->hw_frames_ctx) { + frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data; + if (frames_ctx->format != AV_PIX_FMT_CUDA) { + av_log(avctx, AV_LOG_ERROR, "hw_frames_ctx must be CUDA\n"); + return AVERROR(EINVAL); + } + s->hwctx = frames_ctx->device_ctx->hwctx; + s->sw_format = frames_ctx->sw_format; + } else if (avctx->hw_device_ctx) { + AVHWDeviceContext *dev = (AVHWDeviceContext *)avctx->hw_device_ctx->data; + + if (dev->type != AV_HWDEVICE_TYPE_CUDA) { + av_log(avctx, AV_LOG_ERROR, "hw_device_ctx must be CUDA\n"); + return AVERROR(EINVAL); + } + s->hwctx = dev->hwctx; + s->sw_format = AV_PIX_FMT_NONE; + } else { + av_log(avctx, AV_LOG_ERROR, "CUDA frames or device context required\n"); + return AVERROR(EINVAL); + } + + if (s->sw_format != AV_PIX_FMT_NONE && + s->sw_format != AV_PIX_FMT_YUV444P) { + av_log(avctx, AV_LOG_ERROR, "GPUJPEG needs CUDA yuv444p (got %s)\n", + av_get_pix_fmt_name(s->sw_format)); + return AVERROR(ENOSYS); + } + + ret = CHECK_CU(s->hwctx->internal->cuda_dl->cuCtxPushCurrent(s->hwctx->cuda_ctx)); + if (ret < 0) + return ret; + pushed = 1; + + s->encoder = gpujpeg_encoder_create((cudaStream_t)s->hwctx->stream); + if (!s->encoder) { + av_log(avctx, AV_LOG_ERROR, "gpujpeg_encoder_create failed\n"); + ret = AVERROR_EXTERNAL; + goto fail; + } + + ret = CHECK_CU(s->hwctx->internal->cuda_dl->cuCtxPopCurrent(&dummy)); + if (ret < 0) + goto fail; + return 0; + +fail: + if (pushed) + s->hwctx->internal->cuda_dl->cuCtxPopCurrent(&dummy); + return ret < 0 ? ret : AVERROR_EXTERNAL; +} + +static av_cold int gpujpeg_encode_close(AVCodecContext *avctx) +{ + GPUJPEGEncContext *s = avctx->priv_data; + CUcontext dummy; + + if (!s->encoder) + return 0; + + if (!s->hwctx || !s->hwctx->internal || !s->hwctx->internal->cuda_dl || + !s->hwctx->cuda_ctx || + s->hwctx->internal->cuda_dl->cuCtxPushCurrent(s->hwctx->cuda_ctx) != CUDA_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, + "Cannot make the GPUJPEG CUDA context current; encoder not destroyed\n"); + return AVERROR_EXTERNAL; + } + + gpujpeg_encoder_destroy(s->encoder); + s->encoder = NULL; + s->hwctx->internal->cuda_dl->cuCtxPopCurrent(&dummy); + return 0; +} + +static int gpujpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, + const AVFrame *frame, int *got_packet) +{ + GPUJPEGEncContext *s = avctx->priv_data; + struct gpujpeg_parameters param; + struct gpujpeg_image_parameters ip; + struct gpujpeg_encoder_input input; + CUcontext dummy; + uint8_t *jpg = NULL; + size_t len = 0; + ptrdiff_t pitch; + int ret, pushed = 0; + enum AVPixelFormat sw; + + if (!frame) + return 0; + if (!frame->hw_frames_ctx) { + av_log(avctx, AV_LOG_ERROR, "CUDA frame required\n"); + return AVERROR(EINVAL); + } + + { + AVHWFramesContext *fc = (AVHWFramesContext *)frame->hw_frames_ctx->data; + + sw = fc->sw_format; + if (!s->hwctx) + s->hwctx = fc->device_ctx->hwctx; + if (s->sw_format == AV_PIX_FMT_NONE) + s->sw_format = sw; + } + if (sw != AV_PIX_FMT_YUV444P) { + av_log(avctx, AV_LOG_ERROR, "Unsupported CUDA sw_format %s\n", + av_get_pix_fmt_name(sw)); + return AVERROR(ENOSYS); + } + if (!frame->data[0] || !frame->data[1] || !frame->data[2] || + frame->width <= 0 || frame->height <= 0) { + av_log(avctx, AV_LOG_ERROR, "Incomplete CUDA frame\n"); + return AVERROR(EINVAL); + } + + pitch = frame->linesize[0]; + if (pitch < frame->width || + frame->linesize[1] != pitch || frame->linesize[2] != pitch) { + av_log(avctx, AV_LOG_ERROR, + "GPUJPEG needs equal plane strides of at least the width\n"); + return AVERROR(EINVAL); + } + if ((uintptr_t)frame->data[1] != (uintptr_t)frame->data[0] + (uintptr_t)pitch * frame->height || + (uintptr_t)frame->data[2] != (uintptr_t)frame->data[1] + (uintptr_t)pitch * frame->height) { + av_log(avctx, AV_LOG_ERROR, + "GPUJPEG needs Y, Cb and Cr packed one after another\n"); + return AVERROR(EINVAL); + } + if (s->chroma != GPUJPEG_CHROMA_444 && pitch != frame->width) { + av_log(avctx, AV_LOG_ERROR, + "4:2:0 output needs linesize equal to the width; " + "this frame has linesize %d\n", frame->linesize[0]); + return AVERROR(EINVAL); + } + + gpujpeg_warn_colorspace(avctx, frame, &s->csp_warned); + + ret = CHECK_CU(s->hwctx->internal->cuda_dl->cuCtxPushCurrent(s->hwctx->cuda_ctx)); + if (ret < 0) + return ret; + pushed = 1; + + param = gpujpeg_default_parameters(); + param.quality = s->quality; + param.verbose = GPUJPEG_LL_QUIET; + if (s->chroma == GPUJPEG_CHROMA_420) + gpujpeg_parameters_chroma_subsampling(¶m, GPUJPEG_SUBSAMPLING_420); + + ip = gpujpeg_default_image_parameters(); + ip.width = frame->width; + ip.height = frame->height; + ip.color_space = GPUJPEG_YCBCR_JPEG; + ip.pixel_format = GPUJPEG_444_U8_P0P1P2; + ip.width_padding = (int)(pitch - frame->width); + + gpujpeg_encoder_input_set_gpu_image(&input, frame->data[0]); + if (gpujpeg_encoder_encode(s->encoder, ¶m, &ip, &input, &jpg, &len)) { + av_log(avctx, AV_LOG_ERROR, "gpujpeg_encoder_encode failed\n"); + ret = AVERROR_EXTERNAL; + goto fail; + } + if (!jpg || !len || len > INT_MAX) { + av_log(avctx, AV_LOG_ERROR, "GPUJPEG returned no packet\n"); + ret = AVERROR_EXTERNAL; + goto fail; + } + + ret = ff_get_encode_buffer(avctx, pkt, (int)len, 0); + if (ret < 0) + goto fail; + memcpy(pkt->data, jpg, len); + + ret = CHECK_CU(s->hwctx->internal->cuda_dl->cuCtxPopCurrent(&dummy)); + if (ret < 0) + goto fail; + pushed = 0; + + gpujpeg_write_sar(avctx, pkt->data, pkt->size); + pkt->flags |= AV_PKT_FLAG_KEY; + *got_packet = 1; + return 0; + +fail: + if (pushed) + s->hwctx->internal->cuda_dl->cuCtxPopCurrent(&dummy); + return ret < 0 ? ret : AVERROR_EXTERNAL; +} + +#define OFFSET(x) offsetof(GPUJPEGEncContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "quality", "JPEG quality 0-100", OFFSET(quality), AV_OPT_TYPE_INT, + { .i64 = 75 }, 0, 100, VE }, + { "chroma", "output chroma subsampling", OFFSET(chroma), AV_OPT_TYPE_INT, + { .i64 = GPUJPEG_CHROMA_444 }, 0, 1, VE, .unit = "chroma" }, + { "444", "4:4:4", 0, AV_OPT_TYPE_CONST, { .i64 = GPUJPEG_CHROMA_444 }, 0, 0, VE, .unit = "chroma" }, + { "420", "4:2:0, requires linesize equal to the width", 0, AV_OPT_TYPE_CONST, + { .i64 = GPUJPEG_CHROMA_420 }, 0, 0, VE, .unit = "chroma" }, + { NULL }, +}; + +static const AVClass gpujpeg_class = { + .class_name = "libgpujpeg", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const FFCodec ff_libgpujpeg_encoder = { + .p.name = "libgpujpeg", + CODEC_LONG_NAME("GPUJPEG encoder"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_MJPEG, + .priv_data_size = sizeof(GPUJPEGEncContext), + .init = gpujpeg_encode_init, + FF_CODEC_ENCODE_CB(gpujpeg_encode_frame), + .close = gpujpeg_encode_close, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_HARDWARE | + AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, + CODEC_PIXFMTS(AV_PIX_FMT_CUDA), + .p.priv_class = &gpujpeg_class, + .p.wrapper_name = "gpujpeg", + .hw_configs = gpujpeg_hw_configs, + .color_ranges = AVCOL_RANGE_JPEG, +}; diff --git a/libavcodec/version.h b/libavcodec/version.h index d0980e28de..da6f3a84ac 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,7 +29,7 @@ #include "version_major.h" -#define LIBAVCODEC_VERSION_MINOR 20 +#define LIBAVCODEC_VERSION_MINOR 21 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
