dvdspu: use multiple minimal sized PGS overlay rectangles
... rather than possibly 1 large at full video size Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6413>
This commit is contained in:
parent
99b1f5ddd2
commit
869b6f2968
@ -951,8 +951,9 @@ gstspu_render_composition (GstDVDSpu * dvdspu)
|
|||||||
GstVideoFormat format;
|
GstVideoFormat format;
|
||||||
GstVideoFrame frame;
|
GstVideoFrame frame;
|
||||||
GstVideoOverlayRectangle *rectangle;
|
GstVideoOverlayRectangle *rectangle;
|
||||||
GstVideoOverlayComposition *composition;
|
GstVideoOverlayComposition *composition = NULL;
|
||||||
GstVideoRectangle win;
|
GstVideoRectangle win;
|
||||||
|
gint rect_count, rect_index;
|
||||||
gint spu_w, spu_h;
|
gint spu_w, spu_h;
|
||||||
gsize size;
|
gsize size;
|
||||||
|
|
||||||
@ -960,78 +961,88 @@ gstspu_render_composition (GstDVDSpu * dvdspu)
|
|||||||
|
|
||||||
switch (dvdspu->spu_input_type) {
|
switch (dvdspu->spu_input_type) {
|
||||||
case SPU_INPUT_TYPE_PGS:
|
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;
|
break;
|
||||||
case SPU_INPUT_TYPE_VOBSUB:
|
case SPU_INPUT_TYPE_VOBSUB:
|
||||||
gstspu_vobsub_get_render_geometry (dvdspu, &spu_w, &spu_h, &win);
|
gstspu_vobsub_get_render_geometry (dvdspu, &spu_w, &spu_h, &win);
|
||||||
|
rect_count = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (win.w <= 0 || win.h <= 0 || spu_w <= 0 || spu_h <= 0) {
|
for (rect_index = 0; rect_index < rect_count; ++rect_index) {
|
||||||
GST_DEBUG_OBJECT (dvdspu, "skip render of empty window");
|
if (dvdspu->spu_input_type == SPU_INPUT_TYPE_PGS)
|
||||||
return NULL;
|
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;
|
return composition;
|
||||||
|
|
||||||
map_failed:
|
map_failed:
|
||||||
GST_ERROR_OBJECT (dvdspu, "failed to map buffer");
|
GST_ERROR_OBJECT (dvdspu, "failed to map buffer");
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
return NULL;
|
return composition;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -204,9 +204,11 @@ pgs_composition_object_render (PgsCompositionObject * obj, SpuState * state,
|
|||||||
obj_h = GST_READ_UINT16_BE (data + 2);
|
obj_h = GST_READ_UINT16_BE (data + 2);
|
||||||
data += 4;
|
data += 4;
|
||||||
|
|
||||||
/* Calculate object coordinates relative to the window */
|
/* window frame is located at (obj_x, obj_y) with size (obj_w, obj_h) */
|
||||||
min_x = obj_x = (gint) obj->x - (gint) state->pgs.win_x;
|
g_assert (obj_w <= win_w);
|
||||||
min_y = obj_y = (gint) obj->y - (gint) state->pgs.win_y;
|
g_assert (obj_h <= win_h);
|
||||||
|
min_x = obj_x = 0;
|
||||||
|
min_y = obj_y = 0;
|
||||||
|
|
||||||
if (obj->flags & PGS_COMPOSITION_OBJECT_FLAG_CROPPED) {
|
if (obj->flags & PGS_COMPOSITION_OBJECT_FLAG_CROPPED) {
|
||||||
obj_x -= obj->crop_x;
|
obj_x -= obj->crop_x;
|
||||||
@ -337,7 +339,8 @@ pgs_composition_object_clear (PgsCompositionObject * obj)
|
|||||||
g_free (obj->rle_data);
|
g_free (obj->rle_data);
|
||||||
obj->rle_data = NULL;
|
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
|
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);
|
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) {
|
if (payload != end) {
|
||||||
GST_ERROR ("PGS Set Object Data: %" G_GSSIZE_FORMAT " bytes not consumed",
|
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
|
void
|
||||||
gstspu_pgs_get_render_geometry (GstDVDSpu * dvdspu,
|
gstspu_pgs_get_render_geometry (GstDVDSpu * dvdspu,
|
||||||
gint * display_width, gint * display_height,
|
gint * display_width, gint * display_height, gint * count)
|
||||||
GstVideoRectangle * window_rect)
|
|
||||||
{
|
{
|
||||||
SpuPgsState *pgs_state = &dvdspu->spu_state.pgs;
|
PgsPresentationSegment *ps = &dvdspu->spu_state.pgs.pres_seg;
|
||||||
|
|
||||||
if (window_rect) {
|
if (count)
|
||||||
window_rect->x = pgs_state->win_x;
|
*count = ps->objects->len;
|
||||||
window_rect->y = pgs_state->win_y;
|
|
||||||
window_rect->w = pgs_state->win_w;
|
|
||||||
window_rect->h = pgs_state->win_h;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (display_width)
|
if (display_width)
|
||||||
*display_width = pgs_state->pres_seg.vid_w;
|
*display_width = ps->vid_w;
|
||||||
|
|
||||||
if (display_height)
|
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
|
void
|
||||||
|
@ -82,6 +82,9 @@ struct PgsCompositionObject
|
|||||||
|
|
||||||
/* Only valid if PGS_COMPOSITION_OBJECT_FLAG_CROPPED is set */
|
/* Only valid if PGS_COMPOSITION_OBJECT_FLAG_CROPPED is set */
|
||||||
guint16 crop_x, crop_y, crop_w, crop_h;
|
guint16 crop_x, crop_y, crop_w, crop_h;
|
||||||
|
|
||||||
|
/* Parsed width and height from Object Data */
|
||||||
|
guint16 width, height;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SpuPgsState {
|
struct SpuPgsState {
|
||||||
@ -102,7 +105,8 @@ gboolean gstspu_pgs_execute_event (GstDVDSpu *dvdspu);
|
|||||||
void gstspu_pgs_render (GstDVDSpu *dvdspu, GstVideoFrame *window);
|
void gstspu_pgs_render (GstDVDSpu *dvdspu, GstVideoFrame *window);
|
||||||
gboolean gstspu_pgs_handle_dvd_event (GstDVDSpu *dvdspu, GstEvent *event);
|
gboolean gstspu_pgs_handle_dvd_event (GstDVDSpu *dvdspu, GstEvent *event);
|
||||||
void gstspu_pgs_get_render_geometry (GstDVDSpu *dvdspu,
|
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);
|
GstVideoRectangle *window_rect);
|
||||||
void gstspu_pgs_flush (GstDVDSpu *dvdspu);
|
void gstspu_pgs_flush (GstDVDSpu *dvdspu);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user