[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