From 59bdac1569304cd2112154b51fa5d25df61569cf Mon Sep 17 00:00:00 2001 From: Paul Mc Galey Date: Thu, 16 Sep 2021 00:35:01 +0100 Subject: [PATCH] vlc-video: Fix video rotation and aspect ratio Fixes #5250 and #3843. Gets dimensions, aspect ratio and orientation/rotation from source video track. --- plugins/vlc-video/vlc-video-plugin.c | 6 ++- plugins/vlc-video/vlc-video-plugin.h | 6 +++ plugins/vlc-video/vlc-video-source.c | 75 +++++++++++++++++++++++----- 3 files changed, 73 insertions(+), 14 deletions(-) diff --git a/plugins/vlc-video/vlc-video-plugin.c b/plugins/vlc-video/vlc-video-plugin.c index efc77dfe6..5956ba7ab 100644 --- a/plugins/vlc-video/vlc-video-plugin.c +++ b/plugins/vlc-video/vlc-video-plugin.c @@ -24,8 +24,10 @@ LIBVLC_MEDIA_NEW_PATH libvlc_media_new_path_; LIBVLC_MEDIA_NEW_LOCATION libvlc_media_new_location_; LIBVLC_MEDIA_ADD_OPTION libvlc_media_add_option_; LIBVLC_MEDIA_RELEASE libvlc_media_release_; -LIBVLC_MEDIA_RELEASE libvlc_media_retain_; +LIBVLC_MEDIA_RETAIN libvlc_media_retain_; LIBVLC_MEDIA_GET_META libvlc_media_get_meta_; +LIBVLC_MEDIA_TRACKS_GET libvlc_media_tracks_get_; +LIBVLC_MEDIA_TRACKS_RELEASE libvlc_media_tracks_release_; /* libvlc media player */ LIBVLC_MEDIA_PLAYER_NEW libvlc_media_player_new_; @@ -104,6 +106,8 @@ static bool load_vlc_funcs(void) LOAD_VLC_FUNC(libvlc_media_release); LOAD_VLC_FUNC(libvlc_media_retain); LOAD_VLC_FUNC(libvlc_media_get_meta); + LOAD_VLC_FUNC(libvlc_media_tracks_get); + LOAD_VLC_FUNC(libvlc_media_tracks_release); /* libvlc media player */ LOAD_VLC_FUNC(libvlc_media_player_new); diff --git a/plugins/vlc-video/vlc-video-plugin.h b/plugins/vlc-video/vlc-video-plugin.h index 32bf7f4e5..79d875e6b 100644 --- a/plugins/vlc-video/vlc-video-plugin.h +++ b/plugins/vlc-video/vlc-video-plugin.h @@ -38,6 +38,10 @@ typedef void (*LIBVLC_MEDIA_RETAIN)(libvlc_media_t *p_md); typedef void (*LIBVLC_MEDIA_RELEASE)(libvlc_media_t *p_md); typedef char *(*LIBVLC_MEDIA_GET_META)(libvlc_media_t *p_md, libvlc_meta_t e_meta); +typedef unsigned (*LIBVLC_MEDIA_TRACKS_GET)(libvlc_media_t *p_md, + libvlc_media_track_t ***pp_es); +typedef void (*LIBVLC_MEDIA_TRACKS_RELEASE)(libvlc_media_track_t **p_tracks, + unsigned i_count); /* libvlc media player */ typedef libvlc_media_player_t *(*LIBVLC_MEDIA_PLAYER_NEW)( @@ -125,6 +129,8 @@ extern LIBVLC_MEDIA_ADD_OPTION libvlc_media_add_option_; extern LIBVLC_MEDIA_RELEASE libvlc_media_release_; extern LIBVLC_MEDIA_RETAIN libvlc_media_retain_; extern LIBVLC_MEDIA_GET_META libvlc_media_get_meta_; +extern LIBVLC_MEDIA_TRACKS_GET libvlc_media_tracks_get_; +extern LIBVLC_MEDIA_TRACKS_RELEASE libvlc_media_tracks_release_; /* libvlc media player */ extern LIBVLC_MEDIA_PLAYER_NEW libvlc_media_player_new_; diff --git a/plugins/vlc-video/vlc-video-source.c b/plugins/vlc-video/vlc-video-source.c index a59be7be5..0c302bfb4 100644 --- a/plugins/vlc-video/vlc-video-source.c +++ b/plugins/vlc-video/vlc-video-source.c @@ -382,6 +382,62 @@ static void vlcs_video_display(void *data, void *picture) UNUSED_PARAMETER(picture); } +static void calculate_display_size(struct vlc_source *c, unsigned *width, + unsigned *height) +{ + libvlc_media_t *media = libvlc_media_player_get_media_(c->media_player); + + if (!media) + return; + + libvlc_media_track_t **tracks; + + unsigned count = libvlc_media_tracks_get_(media, &tracks); + + if (count > 0) { + for (unsigned i = 0; i < count; i++) { + libvlc_media_track_t *track = tracks[i]; + + if (track->i_type != libvlc_track_video) + continue; + + int display_width = track->video->i_width; + int display_height = track->video->i_height; + + if (display_width == 0 || display_height == 0) + continue; + + /* Adjust for Sample Aspect Ratio (SAR) */ + if (track->video->i_sar_num > 0 && + track->video->i_sar_den > 0) { + display_width = display_width * + track->video->i_sar_num / + track->video->i_sar_den; + } + + switch (track->video->i_orientation) { + case libvlc_video_orient_left_top: + case libvlc_video_orient_left_bottom: + case libvlc_video_orient_right_top: + case libvlc_video_orient_right_bottom: + /* orientation swaps height and width */ + *width = display_height; + *height = display_width; + break; + default: + /* height and width not swapped */ + *width = display_width; + *height = display_height; + break; + } + } + + libvlc_media_tracks_release_(tracks, count); + } + + libvlc_media_release_(media); +} + static unsigned vlcs_video_format(void **p_data, char *chroma, unsigned *width, unsigned *height, unsigned *pitches, unsigned *lines) @@ -396,19 +452,12 @@ static unsigned vlcs_video_format(void **p_data, char *chroma, unsigned *width, new_format = convert_vlc_video_format(chroma, &new_range); - /* This is used because VLC will by default try to use a different - * scaling than what the file uses (probably for optimization reasons). - * For example, if the file is 1920x1080, it will try to render it by - * 1920x1088, which isn't what we want. Calling libvlc_video_get_size - * gets the actual video file's size, and thus fixes the problem. - * However this doesn't work with URLs, so if it returns a 0 value, it - * shouldn't be used. */ - libvlc_video_get_size_(c->media_player, 0, &new_width, &new_height); - - if (new_width && new_height) { - *width = new_width; - *height = new_height; - } + /* The width and height passed from VLC are the buffer size rather than + * the correct video display size, and may be the next multiple of 32 + * up from the original dimension, e.g. 1080 would become 1088. VLC 4.0 + * will pass the correct display size in *(width+1) and *(height+1) but + * for now we need to calculate it ourselves. */ + calculate_display_size(c, width, height); /* don't allocate a new frame if format/width/height hasn't changed */ if (c->frame.format != new_format || c->frame.width != *width ||