[vlc-commits] [Git][videolan/vlc][master] 2 commits: codec/vt: share CVPX codec mapping

Steve Lhomme (@robUx4) gitlab at videolan.org
Fri Sep 4 06:53:34 UTC 2026



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
abbead4a by Jake Yorkovich at 2026-09-04T06:38:03+00:00
codec/vt: share CVPX codec mapping

- - - - -
afaa47d6 by Jake Yorkovich at 2026-09-04T06:38:03+00:00
vout/vsbd: match display mode to video

- - - - -


3 changed files:

- modules/codec/vt_utils.c
- modules/codec/vt_utils.h
- modules/video_output/apple/VLCSampleBufferDisplay.m


Changes:

=====================================
modules/codec/vt_utils.c
=====================================
@@ -221,30 +221,33 @@ cvpxpic_unmap(picture_t *mapped_pic)
     return hw_pic;
 }
 
-CVPixelBufferPoolRef
-cvpxpool_create(const video_format_t *fmt, unsigned count)
+OSType
+cvpx_map_vlc_chroma_to_cv_pixel_format(vlc_fourcc_t chroma)
 {
-    int cvpx_format;
-    switch (fmt->i_chroma)
+    switch (chroma)
     {
         case VLC_CODEC_CVPX_UYVY:
-            cvpx_format = kCVPixelFormatType_422YpCbCr8;
-            break;
+            return kCVPixelFormatType_422YpCbCr8;
         case VLC_CODEC_CVPX_NV12:
-            cvpx_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
-            break;
+            return kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
         case VLC_CODEC_CVPX_I420:
-            cvpx_format = kCVPixelFormatType_420YpCbCr8Planar;
-            break;
+            return kCVPixelFormatType_420YpCbCr8Planar;
         case VLC_CODEC_CVPX_BGRA:
-            cvpx_format = kCVPixelFormatType_32BGRA;
-            break;
+            return kCVPixelFormatType_32BGRA;
         case VLC_CODEC_CVPX_P010:
-            cvpx_format = 'x420'; /* kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange */
-            break;
+            return 'x420'; /* kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange */
         default:
-            return NULL;
+            return 0;
     }
+}
+
+CVPixelBufferPoolRef
+cvpxpool_create(const video_format_t *fmt, unsigned count)
+{
+    OSType cvpx_format =
+        cvpx_map_vlc_chroma_to_cv_pixel_format(fmt->i_chroma);
+    if (cvpx_format == 0)
+        return NULL;
 
     /* destination pixel buffer attributes */
     CFMutableDictionaryRef cvpx_attrs_dict = cfdict_create(5);


=====================================
modules/codec/vt_utils.h
=====================================
@@ -72,6 +72,14 @@ picture_t *cvpxpic_unmap(picture_t *mapped_pic);
  */
 CVPixelBufferPoolRef cvpxpool_create(const video_format_t *fmt, unsigned count);
 
+/**
+ * @brief Get a Core Video pixel format corresponding to a VLC CVPX chroma
+ *
+ * @param chroma one of the VLC_CODEC_CVPX_* chromas
+ * @return a Core Video pixel format or 0 if the chroma is not supported
+ */
+OSType cvpx_map_vlc_chroma_to_cv_pixel_format(vlc_fourcc_t chroma);
+
 /*
  * Get a cvpx buffer from a pool
  */


=====================================
modules/video_output/apple/VLCSampleBufferDisplay.m
=====================================
@@ -30,7 +30,6 @@
 #include <vlc_filter.h>
 #include <vlc_plugin.h>
 #include <vlc_vout_display.h>
-#include <vlc_atomic.h>
 #include <vlc_modules.h>
 
 #import "VLCDrawable.h"
@@ -636,6 +635,214 @@ shouldInheritContentsScale:(CGFloat)newScale
 
 #pragma mark -
 
+ at interface VLCDisplayCriteriaMatcher : NSObject
+- (instancetype)initWithWindow:(VLCView *)window;
+- (void)prepare;
+- (void)matchVideoFormat:(const video_format_t *)format;
+- (void)matchFormatDescription:(CMVideoFormatDescriptionRef)formatDescription;
+- (void)close;
+ at end
+
+#if TARGET_OS_TV || (defined(TARGET_OS_VISION) && TARGET_OS_VISION)
+API_AVAILABLE(tvos(17.0), visionos(1.0))
+ at interface VLCDisplayCriteriaMatcher ()
+ at property (nonatomic, weak) VLCView *window;
+ at property (nonatomic) AVDisplayManager *displayManager;
+ at property (nonatomic) float refreshRate;
+ at property (nonatomic, copy) NSString *matrix;
+ at property (nonatomic, copy) NSString *primaries;
+ at property (nonatomic, copy) NSString *transfer;
+ at property (nonatomic) BOOL installedDisplayCriteria;
+ at property (nonatomic) AVDisplayCriteria *pendingDisplayCriteria;
+ at end
+
+ at implementation VLCDisplayCriteriaMatcher
+
+- (instancetype)initWithWindow:(VLCView *)window
+{
+    self = [super init];
+    if (self)
+        _window = window;
+    return self;
+}
+
+- (void)installDisplayCriteria:(AVDisplayCriteria *)criteria
+    API_AVAILABLE(tvos(17.0), visionos(1.0))
+{
+    if (@available(tvOS 17.0, visionOS 1.0, *)) {
+        AVDisplayManager *displayManager = self.displayManager;
+        if (displayManager == nil) {
+            displayManager = self.window.window.avDisplayManager;
+            self.displayManager = displayManager;
+        }
+
+        if (criteria == nil)
+            return;
+
+        if (displayManager == nil) {
+            self.pendingDisplayCriteria = criteria;
+            return;
+        }
+
+        self.pendingDisplayCriteria = nil;
+        if (displayManager.isDisplayCriteriaMatchingEnabled) {
+            displayManager.preferredDisplayCriteria = criteria;
+            self.installedDisplayCriteria = YES;
+        }
+    }
+}
+
+- (void)prepare
+{
+    if (@available(tvOS 17.0, visionOS 1.0, *))
+        [self installDisplayCriteria:self.pendingDisplayCriteria];
+}
+
+- (void)matchFormatDescription:(CMVideoFormatDescriptionRef)formatDescription
+{
+    if (formatDescription == NULL)
+        return;
+
+    NSDictionary *extensions = (__bridge NSDictionary *)
+        CMFormatDescriptionGetExtensions(formatDescription);
+    NSString *matrix =
+        extensions[(__bridge NSString *)kCVImageBufferYCbCrMatrixKey];
+    NSString *primaries =
+        extensions[(__bridge NSString *)kCVImageBufferColorPrimariesKey];
+    NSString *transfer =
+        extensions[(__bridge NSString *)kCVImageBufferTransferFunctionKey];
+    if (matrix == nil || primaries == nil || transfer == nil)
+        return;
+
+    [self matchFormatDescription:formatDescription
+                     refreshRate:self.refreshRate
+                          matrix:matrix
+                       primaries:primaries
+                        transfer:transfer];
+}
+
+- (void)matchVideoFormat:(const video_format_t *)format
+{
+    if (format == NULL || format->i_visible_width == 0 ||
+        format->i_visible_height == 0 ||
+        format->i_frame_rate == 0 || format->i_frame_rate_base == 0)
+        return;
+
+    OSType pixelFormat =
+        cvpx_map_vlc_chroma_to_cv_pixel_format(format->i_chroma);
+    if (pixelFormat == 0)
+        return;
+
+    CFMutableDictionaryRef extensions = cfdict_create(3);
+    if (extensions == NULL)
+        return;
+
+    CFStringRef matrix = cvpx_map_YCbCrMatrix_from_vcs(format->space);
+    if (matrix != NULL)
+        CFDictionarySetValue(extensions, kCVImageBufferYCbCrMatrixKey, matrix);
+
+    CFStringRef primaries = cvpx_map_ColorPrimaries_from_vcp(format->primaries);
+    if (primaries != NULL)
+        CFDictionarySetValue(extensions, kCVImageBufferColorPrimariesKey,
+                             primaries);
+
+    CFStringRef transfer = cvpx_map_TransferFunction_from_vtf(format->transfer);
+    if (transfer != NULL)
+        CFDictionarySetValue(extensions, kCVImageBufferTransferFunctionKey,
+                             transfer);
+
+    CMVideoFormatDescriptionRef formatDescription = NULL;
+    OSStatus status = CMVideoFormatDescriptionCreate(
+        kCFAllocatorDefault, pixelFormat, format->i_visible_width,
+        format->i_visible_height, extensions, &formatDescription);
+    CFRelease(extensions);
+    if (status != noErr)
+        return;
+
+    [self matchFormatDescription:formatDescription
+                     refreshRate:(float)format->i_frame_rate /
+                                 (float)format->i_frame_rate_base
+                          matrix:(__bridge NSString *)matrix
+                       primaries:(__bridge NSString *)primaries
+                        transfer:(__bridge NSString *)transfer];
+    CFRelease(formatDescription);
+}
+
+- (void)matchFormatDescription:(CMVideoFormatDescriptionRef)formatDescription
+                    refreshRate:(float)refreshRate
+                         matrix:(NSString *)matrix
+                      primaries:(NSString *)primaries
+                       transfer:(NSString *)transfer
+{
+    if (@available(tvOS 17.0, visionOS 1.0, *)) {
+        if (refreshRate == 0.f || formatDescription == NULL)
+            return;
+
+        if (self.refreshRate == refreshRate &&
+            [self.matrix isEqualToString:matrix] &&
+            [self.primaries isEqualToString:primaries] &&
+            [self.transfer isEqualToString:transfer])
+            return;
+
+        AVDisplayCriteria *criteria =
+            [[AVDisplayCriteria alloc] initWithRefreshRate:refreshRate
+                                         formatDescription:formatDescription];
+        if (criteria == nil)
+            return;
+
+        self.refreshRate = refreshRate;
+        self.matrix = matrix;
+        self.primaries = primaries;
+        self.transfer = transfer;
+
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [self installDisplayCriteria:criteria];
+        });
+    }
+}
+
+- (void)close
+{
+    if (@available(tvOS 17.0, visionOS 1.0, *)) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            AVDisplayManager *displayManager = self.displayManager;
+            self.pendingDisplayCriteria = nil;
+            if (self.installedDisplayCriteria)
+                displayManager.preferredDisplayCriteria = nil;
+            self.installedDisplayCriteria = NO;
+        });
+    }
+}
+
+ at end
+
+#else
+
+ at implementation VLCDisplayCriteriaMatcher
+
+- (instancetype)initWithWindow:(VLCView *)window
+{
+    self = [super init];
+    VLC_UNUSED(window);
+    return nil;
+}
+
+- (void)matchVideoFormat:(const video_format_t *)format
+{
+    VLC_UNUSED(format);
+}
+
+- (void)prepare {}
+
+- (void)matchFormatDescription:(CMVideoFormatDescriptionRef)formatDescription
+{
+    VLC_UNUSED(formatDescription);
+}
+- (void)close {}
+
+ at end
+#endif
+
 @interface VLCSampleBufferDisplay: NSObject
 {
     @public
@@ -648,6 +855,7 @@ shouldInheritContentsScale:(CGFloat)newScale
     @property (nonatomic) VLCSampleBufferSubpictureView *spuView;
     @property (nonatomic) VLCSampleBufferSubpicture *subpicture;
     @property (nonatomic) id<VLCPixelBufferRotationContext> rotationContext;
+    @property (nonatomic) VLCDisplayCriteriaMatcher *displayModeMatcher;
 
     @property (nonatomic, readonly) pip_controller_t *pipcontroller;
 
@@ -694,6 +902,12 @@ shouldInheritContentsScale:(CGFloat)newScale
 
     _vd = vd;
 
+#if TARGET_OS_TV || (defined(TARGET_OS_VISION) && TARGET_OS_VISION)
+    if (@available(tvOS 17.0, visionOS 1.0, *))
+        _displayModeMatcher = [[VLCDisplayCriteriaMatcher alloc]
+            initWithWindow:window];
+#endif
+
     return self;
 }
 
@@ -746,6 +960,7 @@ shouldInheritContentsScale:(CGFloat)newScale
         spuView = [VLCSampleBufferSubpictureView new];
         [window addSubview:displayView];
         [window addSubview:spuView];
+        [sys.displayModeMatcher prepare];
 
         displayView.frame = [sys frameForPlace:&place];
         [spuView setFrame:[window bounds]];
@@ -811,6 +1026,7 @@ shouldInheritContentsScale:(CGFloat)newScale
 
 - (void)close {
     [[NSNotificationCenter defaultCenter] removeObserver:self];
+    [self.displayModeMatcher close];
 
     VLCSampleBufferDisplay *sys = self;
     dispatch_async(dispatch_get_main_queue(), ^{
@@ -928,6 +1144,8 @@ static void RenderPicture(vout_display_t *vd, picture_t *pic, vlc_tick_t date) {
         return;
     }
 
+    [sys.displayModeMatcher matchFormatDescription:formatDesc];
+
     vlc_tick_t now = vlc_tick_now();
     CFTimeInterval ca_now = CACurrentMediaTime();
     vlc_tick_t ca_now_ts = vlc_tick_from_sec(ca_now);
@@ -1175,6 +1393,10 @@ static int UpdateFormat(vout_display_t *vd, const video_format_t *fmt,
 
     DeleteCVPXConverter(sys->converter);
     sys->converter = converter;
+
+    const video_format_t *displayFormat =
+        converter != NULL ? &converter->fmt_out.video : fmt;
+    [sys.displayModeMatcher matchVideoFormat:displayFormat];
     return VLC_SUCCESS;
 }
 
@@ -1209,6 +1431,10 @@ static int Open (vout_display_t *vd,
 
         sys->converter = converter;
 
+        const video_format_t *displayFormat =
+            converter != NULL ? &converter->fmt_out.video : fmt;
+        [sys.displayModeMatcher matchVideoFormat:displayFormat];
+
         vd->sys = (__bridge_retained void*)sys;
 
         static const struct vlc_display_operations ops = {



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/b430d41044289865f0620fceaa03a65ef17f89a7...afaa47d6074e7c934c8704eedeb8424085016908

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/b430d41044289865f0620fceaa03a65ef17f89a7...afaa47d6074e7c934c8704eedeb8424085016908
You're receiving this email because of your account on code.videolan.org. Manage all notifications: https://code.videolan.org/-/profile/notifications | Help: https://code.videolan.org/help




More information about the vlc-commits mailing list