diff --git a/subprojects/gst-plugins-bad/gst/dvdspu/gstdvdspu.c b/subprojects/gst-plugins-bad/gst/dvdspu/gstdvdspu.c index aeee1a8157..30d02382df 100644 --- a/subprojects/gst-plugins-bad/gst/dvdspu/gstdvdspu.c +++ b/subprojects/gst-plugins-bad/gst/dvdspu/gstdvdspu.c @@ -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 diff --git a/subprojects/gst-plugins-bad/gst/dvdspu/gstspu-pgs.c b/subprojects/gst-plugins-bad/gst/dvdspu/gstspu-pgs.c index 3fa4c7d79a..2fd2f10e36 100644 --- a/subprojects/gst-plugins-bad/gst/dvdspu/gstspu-pgs.c +++ b/subprojects/gst-plugins-bad/gst/dvdspu/gstspu-pgs.c @@ -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 diff --git a/subprojects/gst-plugins-bad/gst/dvdspu/gstspu-pgs.h b/subprojects/gst-plugins-bad/gst/dvdspu/gstspu-pgs.h index 7d0689ecf3..ef34ff1bf4 100644 --- a/subprojects/gst-plugins-bad/gst/dvdspu/gstspu-pgs.h +++ b/subprojects/gst-plugins-bad/gst/dvdspu/gstspu-pgs.h @@ -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);