Compare commits

...

5 commits

Author SHA1 Message Date
Mark Nauwelaerts ed1e2281e4 Merge branch 'dvdspu_sub_rect' into 'main'
dvdspu: use multiple minimal sized PGS overlay rectangles

See merge request gstreamer/gstreamer!6413
2024-04-27 18:28:52 +00:00
Nirbheek Chauhan d7eeb62f38 meson: Fix Python library searching on Windows
Neither LIBDIR nor LIBPL are set with the native windows Python
(unlike MSYS2), so we need to use `prefix` which takes us to the
rootdir of the Python installation.

The name is also different: it's python312.dll, not python3.12.dll.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6734>
2024-04-27 01:30:21 +00:00
Nirbheek Chauhan 753aeccde7 meson: Fix Python library name fetching on Windows
`python.get_variable('FOO', [])` becomes `python.get_variable('FOO')`
due to how Meson treats empty arrays in arguments, which breaks the
fallback feature of get_variable().

So we need to actually check whether the variable exists before trying
to fetch it.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6734>
2024-04-27 01:30:21 +00:00
Tim-Philipp Müller 7074849c5c exif: add debug category
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6741>
2024-04-27 00:19:30 +00:00
Mark Nauwelaerts eda3effc45 dvdspu: use multiple minimal sized PGS overlay rectangles
... rather than possibly 1 large at full video size
2024-04-13 15:26:37 +02:00
5 changed files with 158 additions and 89 deletions

View file

@ -951,8 +951,9 @@ gstspu_render_composition (GstDVDSpu * dvdspu)
GstVideoFormat format;
GstVideoFrame frame;
GstVideoOverlayRectangle *rectangle;
GstVideoOverlayComposition *composition;
GstVideoOverlayComposition *composition = NULL;
GstVideoRectangle win;
gint rect_count, rect_index;
gint spu_w, spu_h;
gsize size;
@ -960,78 +961,88 @@ gstspu_render_composition (GstDVDSpu * dvdspu)
switch (dvdspu->spu_input_type) {
case SPU_INPUT_TYPE_PGS:
gstspu_pgs_get_render_geometry (dvdspu, &spu_w, &spu_h, &win);
gstspu_pgs_get_render_geometry (dvdspu, &spu_w, &spu_h, &rect_count);
break;
case SPU_INPUT_TYPE_VOBSUB:
gstspu_vobsub_get_render_geometry (dvdspu, &spu_w, &spu_h, &win);
rect_count = 1;
break;
default:
return NULL;
}
if (win.w <= 0 || win.h <= 0 || spu_w <= 0 || spu_h <= 0) {
GST_DEBUG_OBJECT (dvdspu, "skip render of empty window");
return NULL;
for (rect_index = 0; rect_index < rect_count; ++rect_index) {
if (dvdspu->spu_input_type == SPU_INPUT_TYPE_PGS)
gstspu_pgs_get_render_geometry_n (dvdspu, rect_index, &win);
if (win.w <= 0 || win.h <= 0 || spu_w <= 0 || spu_h <= 0) {
GST_DEBUG_OBJECT (dvdspu, "skip render of empty window");
continue;
}
gst_video_info_init (&overlay_info);
gst_video_info_set_format (&overlay_info, format, win.w, win.h);
size = GST_VIDEO_INFO_SIZE (&overlay_info);
buffer = gst_buffer_new_and_alloc (size);
if (!buffer) {
GST_WARNING_OBJECT (dvdspu, "failed to allocate overlay buffer");
continue;
}
gst_buffer_add_video_meta (buffer, GST_VIDEO_FRAME_FLAG_NONE,
format, win.w, win.h);
if (!gst_video_frame_map (&frame, &overlay_info, buffer, GST_MAP_READWRITE))
goto map_failed;
memset (GST_VIDEO_FRAME_PLANE_DATA (&frame, 0), 0,
GST_VIDEO_FRAME_PLANE_STRIDE (&frame, 0) *
GST_VIDEO_FRAME_HEIGHT (&frame));
switch (dvdspu->spu_input_type) {
case SPU_INPUT_TYPE_VOBSUB:
gstspu_vobsub_render (dvdspu, &frame);
break;
case SPU_INPUT_TYPE_PGS:
gstspu_pgs_render (dvdspu, &frame);
break;
default:
break;
}
gst_video_frame_unmap (&frame);
GST_DEBUG_OBJECT (dvdspu, "Overlay rendered for video size %dx%d, "
"spu display size %dx%d, window geometry %dx%d+%d%+d",
GST_VIDEO_INFO_WIDTH (&dvdspu->spu_state.info),
GST_VIDEO_INFO_HEIGHT (&dvdspu->spu_state.info),
spu_w, spu_h, win.w, win.h, win.x, win.y);
if (gstspu_fit_overlay_rectangle (dvdspu, &win, spu_w, spu_h,
dvdspu->spu_input_type == SPU_INPUT_TYPE_PGS))
GST_DEBUG_OBJECT (dvdspu, "Adjusted window to fit video: %dx%d%+d%+d",
win.w, win.h, win.x, win.y);
rectangle = gst_video_overlay_rectangle_new_raw (buffer, win.x, win.y,
win.w, win.h, GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
gst_buffer_unref (buffer);
if (!composition) {
composition = gst_video_overlay_composition_new (rectangle);
} else {
gst_video_overlay_composition_add_rectangle (composition, rectangle);
}
gst_video_overlay_rectangle_unref (rectangle);
}
gst_video_info_init (&overlay_info);
gst_video_info_set_format (&overlay_info, format, win.w, win.h);
size = GST_VIDEO_INFO_SIZE (&overlay_info);
buffer = gst_buffer_new_and_alloc (size);
if (!buffer) {
GST_WARNING_OBJECT (dvdspu, "failed to allocate overlay buffer");
return NULL;
}
gst_buffer_add_video_meta (buffer, GST_VIDEO_FRAME_FLAG_NONE,
format, win.w, win.h);
if (!gst_video_frame_map (&frame, &overlay_info, buffer, GST_MAP_READWRITE))
goto map_failed;
memset (GST_VIDEO_FRAME_PLANE_DATA (&frame, 0), 0,
GST_VIDEO_FRAME_PLANE_STRIDE (&frame, 0) *
GST_VIDEO_FRAME_HEIGHT (&frame));
switch (dvdspu->spu_input_type) {
case SPU_INPUT_TYPE_VOBSUB:
gstspu_vobsub_render (dvdspu, &frame);
break;
case SPU_INPUT_TYPE_PGS:
gstspu_pgs_render (dvdspu, &frame);
break;
default:
break;
}
gst_video_frame_unmap (&frame);
GST_DEBUG_OBJECT (dvdspu, "Overlay rendered for video size %dx%d, "
"spu display size %dx%d, window geometry %dx%d+%d%+d",
GST_VIDEO_INFO_WIDTH (&dvdspu->spu_state.info),
GST_VIDEO_INFO_HEIGHT (&dvdspu->spu_state.info),
spu_w, spu_h, win.w, win.h, win.x, win.y);
if (gstspu_fit_overlay_rectangle (dvdspu, &win, spu_w, spu_h,
dvdspu->spu_input_type == SPU_INPUT_TYPE_PGS))
GST_DEBUG_OBJECT (dvdspu, "Adjusted window to fit video: %dx%d%+d%+d",
win.w, win.h, win.x, win.y);
rectangle = gst_video_overlay_rectangle_new_raw (buffer, win.x, win.y,
win.w, win.h, GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
gst_buffer_unref (buffer);
composition = gst_video_overlay_composition_new (rectangle);
gst_video_overlay_rectangle_unref (rectangle);
return composition;
map_failed:
GST_ERROR_OBJECT (dvdspu, "failed to map buffer");
gst_buffer_unref (buffer);
return NULL;
return composition;
}
static void

View file

@ -204,9 +204,11 @@ pgs_composition_object_render (PgsCompositionObject * obj, SpuState * state,
obj_h = GST_READ_UINT16_BE (data + 2);
data += 4;
/* Calculate object coordinates relative to the window */
min_x = obj_x = (gint) obj->x - (gint) state->pgs.win_x;
min_y = obj_y = (gint) obj->y - (gint) state->pgs.win_y;
/* window frame is located at (obj_x, obj_y) with size (obj_w, obj_h) */
g_assert (obj_w <= win_w);
g_assert (obj_h <= win_h);
min_x = obj_x = 0;
min_y = obj_y = 0;
if (obj->flags & PGS_COMPOSITION_OBJECT_FLAG_CROPPED) {
obj_x -= obj->crop_x;
@ -337,7 +339,8 @@ pgs_composition_object_clear (PgsCompositionObject * obj)
g_free (obj->rle_data);
obj->rle_data = NULL;
}
obj->rle_data_size = obj->rle_data_used = 0;
/* restore to cleared allocated state */
memset ((char *) obj, 0, sizeof (*obj));
}
static void
@ -662,8 +665,15 @@ parse_set_object_data (GstDVDSpu * dvdspu, guint8 type, guint8 * payload,
}
}
if (obj->rle_data_size == obj->rle_data_used)
if (obj->rle_data_size == obj->rle_data_used) {
dump_rle_data (dvdspu, obj->rle_data, obj->rle_data_size);
if (obj->rle_data_size >= 4) {
guint8 *data = obj->rle_data;
obj->width = GST_READ_UINT16_BE (data);
obj->height = GST_READ_UINT16_BE (data + 2);
}
}
if (payload != end) {
GST_ERROR ("PGS Set Object Data: %" G_GSSIZE_FORMAT " bytes not consumed",
@ -838,23 +848,35 @@ gstspu_pgs_handle_dvd_event (GstDVDSpu * dvdspu, GstEvent * event)
void
gstspu_pgs_get_render_geometry (GstDVDSpu * dvdspu,
gint * display_width, gint * display_height,
GstVideoRectangle * window_rect)
gint * display_width, gint * display_height, gint * count)
{
SpuPgsState *pgs_state = &dvdspu->spu_state.pgs;
PgsPresentationSegment *ps = &dvdspu->spu_state.pgs.pres_seg;
if (window_rect) {
window_rect->x = pgs_state->win_x;
window_rect->y = pgs_state->win_y;
window_rect->w = pgs_state->win_w;
window_rect->h = pgs_state->win_h;
}
if (count)
*count = ps->objects->len;
if (display_width)
*display_width = pgs_state->pres_seg.vid_w;
*display_width = ps->vid_w;
if (display_height)
*display_height = pgs_state->pres_seg.vid_h;
*display_height = ps->vid_h;
}
void
gstspu_pgs_get_render_geometry_n (GstDVDSpu * dvdspu, gint index,
GstVideoRectangle * window_rect)
{
PgsPresentationSegment *ps = &dvdspu->spu_state.pgs.pres_seg;
if (window_rect && index < ps->objects->len) {
PgsCompositionObject *cur =
&g_array_index (ps->objects, PgsCompositionObject, index);
window_rect->x = cur->x;
window_rect->y = cur->y;
window_rect->w = cur->width;
window_rect->h = cur->height;
}
}
void

View file

@ -82,6 +82,9 @@ struct PgsCompositionObject
/* Only valid if PGS_COMPOSITION_OBJECT_FLAG_CROPPED is set */
guint16 crop_x, crop_y, crop_w, crop_h;
/* Parsed width and height from Object Data */
guint16 width, height;
};
struct SpuPgsState {
@ -102,7 +105,8 @@ gboolean gstspu_pgs_execute_event (GstDVDSpu *dvdspu);
void gstspu_pgs_render (GstDVDSpu *dvdspu, GstVideoFrame *window);
gboolean gstspu_pgs_handle_dvd_event (GstDVDSpu *dvdspu, GstEvent *event);
void gstspu_pgs_get_render_geometry (GstDVDSpu *dvdspu,
gint *display_width, gint *display_height,
gint *display_width, gint *display_height, gint *count);
void gstspu_pgs_get_render_geometry_n (GstDVDSpu *dvdspu, gint index,
GstVideoRectangle *window_rect);
void gstspu_pgs_flush (GstDVDSpu *dvdspu);

View file

@ -65,6 +65,25 @@ typedef struct _GstExifWriter GstExifWriter;
typedef struct _GstExifReader GstExifReader;
typedef struct _GstExifTagData GstExifTagData;
#define GST_CAT_DEFAULT gst_exif_tag_ensure_debug_category()
static GstDebugCategory *
gst_exif_tag_ensure_debug_category (void)
{
static gsize cat_gonce = 0;
if (g_once_init_enter (&cat_gonce)) {
GstDebugCategory *cat = NULL;
GST_DEBUG_CATEGORY_INIT (cat, "exif-tags", 0, "EXIF tag parsing");
g_once_init_leave (&cat_gonce, (gsize) cat);
}
return (GstDebugCategory *) cat_gonce;
}
typedef void (*GstExifSerializationFunc) (GstExifWriter * writer,
const GstTagList * taglist, const GstExifTagMatch * exiftag);

View file

@ -45,35 +45,53 @@ pylib_loc = get_option('libpython-dir')
fsmod = import('fs')
pylib_prefix = 'lib'
pylib_suffix = 'so'
pylib_ver = python_dep.version()
pylib_locs = []
if host_system == 'windows'
if cc.get_argument_syntax() == 'msvc'
pylib_prefix = ''
endif
pylib_suffix = 'dll'
pylib_ver = pylib_ver.replace('.', '')
elif host_system == 'darwin'
pylib_suffix = 'dylib'
endif
pylib_fnames = []
# Library name with soversion, non-devel package
pylib_fnames += python.get_variable('INSTSONAME', [])
if python.has_variable('INSTSONAME')
# For example, libpython3.12.so.1.0 (Linux), libpython3.11.dll.a (MSYS2), etc.
pylib_fnames += python.get_variable('INSTSONAME')
endif
# Library name without soversion, devel package, framework, etc.
pylib_fnames += python.get_variable('LDLIBRARY', [])
if python.has_variable('LDLIBRARY')
# For example, libpython3.12.so (Linux), libpython3.11.dll.a (MSYS2), etc.
pylib_fnames += python.get_variable('LDLIBRARY')
endif
# Manually construct name as a fallback
pylib_fnames += [
pylib_prefix + 'python' + python_dep.version() + python_abi_flags + '.' + pylib_suffix
pylib_prefix + 'python' + pylib_ver + python_abi_flags + '.' + pylib_suffix
]
if pylib_loc != ''
pylib_locs = [pylib_loc]
else
pylib_locs = [
python.get_variable('LIBDIR', ''),
python.get_variable('LIBPL', ''),
]
if python.has_variable('LIBDIR')
pylib_locs += python.get_variable('LIBDIR')
endif
if python.has_variable('LIBPL')
pylib_locs += python.get_variable('LIBPL')
endif
# On Windows, python312.dll is in the rootdir where Python is installed,
# which is configured as the "prefix" in sysconfig.
if host_system == 'windows'
pylib_locs += python.get_variable('prefix')
endif
endif
pylib_fname = ''
foreach loc: pylib_locs
foreach fname: pylib_fnames
if fsmod.exists(loc / fname)
fpath = loc / fname
debug(f'Looking for Python library at: @fpath@')
if fsmod.exists(fpath)
pylib_fname = fname
message(f'PY_LIB_FNAME = @fname@ (@loc@)')
break
@ -81,12 +99,7 @@ foreach loc: pylib_locs
endforeach
endforeach
if pylib_fname == ''
error_msg = 'Could not find python library to load'
if python_opt.enabled()
error(error_msg)
else
message(error_msg)
endif
message('Could not find python library to load, will try loading at runtime')
endif
pygi_override_dir = get_option('pygi-overrides-dir')