* [FFmpeg-devel] [PATCH] lavc/videotoolboxenc: add mjpeg (PR #20360)
@ 2025-08-28 8:55 wangbin via ffmpeg-devel
0 siblings, 0 replies; only message in thread
From: wangbin via ffmpeg-devel @ 2025-08-28 8:55 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: wangbin
PR #20360 opened by wangbin
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20360
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20360.patch
>From 3a08d1b2c4c6ab01f0e29da1c43d15b9c75f7f68 Mon Sep 17 00:00:00 2001
From: wangbin <wbsecg1@gmail.com>
Date: Thu, 28 Aug 2025 16:45:10 +0800
Subject: [PATCH] lavc/videotoolboxenc: add mjpeg
---
Changelog | 2 +-
libavcodec/allcodecs.c | 1 +
libavcodec/videotoolboxenc.c | 66 +++++++++++++++++++++++++++++++++---
3 files changed, 64 insertions(+), 5 deletions(-)
diff --git a/Changelog b/Changelog
index 96d616991d..53c87e5a29 100644
--- a/Changelog
+++ b/Changelog
@@ -4,7 +4,7 @@ releases are sorted from youngest to oldest.
version <next>:
- ffprobe -codec option
- EXIF Metadata Parsing
-
+- VideoToolbox MJPEG encoder
version 8.0:
- Whisper filter
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index f5ec2e01e8..c3010580ab 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -890,6 +890,7 @@ extern const FFCodec ff_mjpeg_cuvid_decoder;
extern const FFCodec ff_mjpeg_qsv_encoder;
extern const FFCodec ff_mjpeg_qsv_decoder;
extern const FFCodec ff_mjpeg_vaapi_encoder;
+extern const FFCodec ff_mjpeg_videotoolbox_encoder;
extern const FFCodec ff_mp3_mediacodec_decoder;
extern const FFCodec ff_mp3_mf_encoder;
extern const FFCodec ff_mpeg1_cuvid_decoder;
diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c
index b748ecda61..6abcb8158b 100644
--- a/libavcodec/videotoolboxenc.c
+++ b/libavcodec/videotoolboxenc.c
@@ -289,6 +289,8 @@ typedef struct VTEncContext {
int power_efficient;
int max_ref_frames;
int spatialaq;
+
+ int quality;
} VTEncContext;
static void vtenc_free_buf_node(BufNode *info)
@@ -523,6 +525,7 @@ static CMVideoCodecType get_cm_codec_type(AVCodecContext *avctx,
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt == AV_PIX_FMT_VIDEOTOOLBOX ? avctx->sw_pix_fmt : avctx->pix_fmt);
switch (avctx->codec_id) {
+ case AV_CODEC_ID_MJPEG: return kCMVideoCodecType_JPEG;
case AV_CODEC_ID_H264: return kCMVideoCodecType_H264;
case AV_CODEC_ID_HEVC:
if (desc && (desc->flags & AV_PIX_FMT_FLAG_ALPHA) && alpha_quality > 0.0) {
@@ -1195,6 +1198,9 @@ static int vtenc_create_encoder(AVCodecContext *avctx,
int64_t one_second_value = 0;
void *nums[2];
+ if (vtctx->quality)
+ quality = vtctx->quality;
+
int status = VTCompressionSessionCreate(kCFAllocatorDefault,
avctx->width,
avctx->height,
@@ -1247,7 +1253,7 @@ static int vtenc_create_encoder(AVCodecContext *avctx,
return AVERROR_EXTERNAL;
}
- if (avctx->flags & AV_CODEC_FLAG_QSCALE) {
+ if (avctx->flags & AV_CODEC_FLAG_QSCALE || avctx->codec_id == AV_CODEC_ID_MJPEG) {
quality = quality >= 100 ? 1.0 : quality / 100;
quality_num = CFNumberCreate(kCFAllocatorDefault,
kCFNumberFloat32Type,
@@ -1258,7 +1264,7 @@ static int vtenc_create_encoder(AVCodecContext *avctx,
kVTCompressionPropertyKey_Quality,
quality_num);
CFRelease(quality_num);
- } else if (avctx->codec_id != AV_CODEC_ID_PRORES) {
+ } else if (avctx->codec_id != AV_CODEC_ID_PRORES && avctx->codec_id != AV_CODEC_ID_MJPEG) {
bit_rate_num = CFNumberCreate(kCFAllocatorDefault,
kCFNumberSInt32Type,
&bit_rate);
@@ -1374,7 +1380,7 @@ static int vtenc_create_encoder(AVCodecContext *avctx,
}
}
- if (avctx->gop_size > 0 && avctx->codec_id != AV_CODEC_ID_PRORES) {
+ if (avctx->gop_size > 0 && avctx->codec_id != AV_CODEC_ID_PRORES && avctx->codec_id != AV_CODEC_ID_MJPEG) {
CFNumberRef interval = CFNumberCreate(kCFAllocatorDefault,
kCFNumberIntType,
&avctx->gop_size);
@@ -1523,7 +1529,7 @@ static int vtenc_create_encoder(AVCodecContext *avctx,
}
}
- if (!vtctx->has_b_frames && avctx->codec_id != AV_CODEC_ID_PRORES) {
+ if (!vtctx->has_b_frames && avctx->codec_id != AV_CODEC_ID_PRORES && avctx->codec_id != AV_CODEC_ID_MJPEG) {
status = VTSessionSetProperty(vtctx->session,
kVTCompressionPropertyKey_AllowFrameReordering,
kCFBooleanFalse);
@@ -2901,6 +2907,24 @@ static const enum AVPixelFormat prores_pix_fmts[] = {
AV_PIX_FMT_NONE
};
+static const enum AVPixelFormat mjpeg_pix_fmts[] = {
+ AV_PIX_FMT_VIDEOTOOLBOX,
+ AV_PIX_FMT_NV12,
+ AV_PIX_FMT_NV16,
+ AV_PIX_FMT_NV24,
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_P010,
+ AV_PIX_FMT_P210,
+ AV_PIX_FMT_P216,
+ AV_PIX_FMT_P410,
+ AV_PIX_FMT_P416,
+ AV_PIX_FMT_UYVY422,
+ AV_PIX_FMT_AYUV,
+ AV_PIX_FMT_AYUV64,
+ AV_PIX_FMT_NONE
+};
+
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
#define COMMON_OPTIONS \
{ "allow_sw", "Allow software encoding", OFFSET(allow_sw), AV_OPT_TYPE_BOOL, \
@@ -3077,3 +3101,37 @@ const FFCodec ff_prores_videotoolbox_encoder = {
.p.wrapper_name = "videotoolbox",
.hw_configs = vt_encode_hw_configs,
};
+
+static const AVOption mjpeg_options[] = {
+ { "quality", "Quality", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, VE },
+
+ COMMON_OPTIONS
+ { NULL },
+};
+
+static const AVClass mjpeg_videotoolbox_class = {
+ .class_name = "mjpeg_videotoolbox",
+ .item_name = av_default_item_name,
+ .option = mjpeg_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+const FFCodec ff_mjpeg_videotoolbox_encoder = {
+ .p.name = "mjpeg_videotoolbox",
+ CODEC_LONG_NAME("VideoToolbox MJPEG Encoder"),
+ .p.type = AVMEDIA_TYPE_VIDEO,
+ .p.id = AV_CODEC_ID_MJPEG,
+ .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
+ AV_CODEC_CAP_HARDWARE,
+ .priv_data_size = sizeof(VTEncContext),
+ CODEC_PIXFMTS_ARRAY(mjpeg_pix_fmts),
+ .defaults = vt_defaults,
+ .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG,
+ .init = vtenc_init,
+ FF_CODEC_ENCODE_CB(vtenc_frame),
+ .close = vtenc_close,
+ .p.priv_class = &mjpeg_videotoolbox_class,
+ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
+ .p.wrapper_name = "videotoolbox",
+ .hw_configs = vt_encode_hw_configs,
+};
\ No newline at end of file
--
2.49.1
_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2025-08-28 8:55 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-08-28 8:55 [FFmpeg-devel] [PATCH] lavc/videotoolboxenc: add mjpeg (PR #20360) wangbin via ffmpeg-devel
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git