Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [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