mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-19 16:21:17 +00:00
Revert "dvdspu: render to AYUV overlay"
This reverts commit 5016a73190
.
This commit is contained in:
parent
23771469ea
commit
7d27dc7e23
10 changed files with 450 additions and 442 deletions
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
plugin_LTLIBRARIES = libgstdvdspu.la
|
plugin_LTLIBRARIES = libgstdvdspu.la
|
||||||
|
|
||||||
libgstdvdspu_la_SOURCES = gstdvdspu.c gstspu-vobsub.c gstspu-vobsub-render.c gstspu-pgs.c
|
libgstdvdspu_la_SOURCES = gstdvdspu.c gstdvdspu-render.c gstspu-vobsub.c gstspu-vobsub-render.c gstspu-pgs.c
|
||||||
|
|
||||||
libgstdvdspu_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
|
libgstdvdspu_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
|
||||||
libgstdvdspu_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) \
|
libgstdvdspu_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) \
|
||||||
|
|
99
gst/dvdspu/gstdvdspu-render.c
Normal file
99
gst/dvdspu/gstdvdspu-render.c
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
/* GStreamer DVD Sub-Picture Unit
|
||||||
|
* Copyright (C) 2007 Fluendo S.A. <info@fluendo.com>
|
||||||
|
* Copyright (C) 2009 Jan Schmidt <thaytan@noraisin.net>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
#include "gstdvdspu.h"
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_EXTERN (dvdspu_debug);
|
||||||
|
#define GST_CAT_DEFAULT dvdspu_debug
|
||||||
|
|
||||||
|
void
|
||||||
|
gstspu_clear_comp_buffers (SpuState * state)
|
||||||
|
{
|
||||||
|
/* The area to clear is the line inside the disp_rect, each entry 4 bytes,
|
||||||
|
* of the sub-sampled UV planes. */
|
||||||
|
gint16 left = state->comp_left / 2;
|
||||||
|
gint16 right = state->comp_right / 2;
|
||||||
|
gint16 uv_width = sizeof (guint32) * (right - left + 1);
|
||||||
|
|
||||||
|
memset (state->comp_bufs[0] + left, 0, uv_width);
|
||||||
|
memset (state->comp_bufs[1] + left, 0, uv_width);
|
||||||
|
memset (state->comp_bufs[2] + left, 0, uv_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gstspu_blend_comp_buffers (SpuState * state, guint8 * planes[3])
|
||||||
|
{
|
||||||
|
gint16 uv_end;
|
||||||
|
gint16 left, x;
|
||||||
|
guint8 *out_U;
|
||||||
|
guint8 *out_V;
|
||||||
|
guint32 *in_U;
|
||||||
|
guint32 *in_V;
|
||||||
|
guint32 *in_A;
|
||||||
|
gint16 comp_last_x = state->comp_right;
|
||||||
|
|
||||||
|
if (comp_last_x < state->comp_left)
|
||||||
|
return; /* Didn't draw in the comp buffers, nothing to do... */
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
GST_LOG ("Blending comp buffers from x=%d to x=%d",
|
||||||
|
state->comp_left, state->comp_right);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Set up the output pointers */
|
||||||
|
out_U = planes[1]; /* U plane */
|
||||||
|
out_V = planes[2]; /* V plane */
|
||||||
|
|
||||||
|
/* Input starts at the first pixel of the compositing buffer */
|
||||||
|
in_U = state->comp_bufs[0]; /* U comp buffer */
|
||||||
|
in_V = state->comp_bufs[1]; /* V comp buffer */
|
||||||
|
in_A = state->comp_bufs[2]; /* A comp buffer */
|
||||||
|
|
||||||
|
/* Calculate how many pixels to blend based on the maximum X value that was
|
||||||
|
* drawn in the render_line function, divided by 2 (rounding up) to account
|
||||||
|
* for UV sub-sampling */
|
||||||
|
uv_end = (comp_last_x + 1) / 2;
|
||||||
|
left = state->comp_left / 2;
|
||||||
|
|
||||||
|
out_U += left * GST_VIDEO_INFO_COMP_PSTRIDE (&state->info, 1);
|
||||||
|
out_V += left * GST_VIDEO_INFO_COMP_PSTRIDE (&state->info, 2);
|
||||||
|
for (x = left; x < uv_end; x++) {
|
||||||
|
guint32 tmp;
|
||||||
|
/* Each entry in the compositing buffer is 4 summed pixels, so the
|
||||||
|
* inverse alpha is (4 * 0xff) - in_A[x] */
|
||||||
|
guint16 inv_A = (4 * 0xff) - in_A[x];
|
||||||
|
|
||||||
|
tmp = in_U[x] + inv_A * *out_U;
|
||||||
|
*out_U = (guint8) (tmp / (4 * 0xff));
|
||||||
|
|
||||||
|
tmp = in_V[x] + inv_A * *out_V;
|
||||||
|
*out_V = (guint8) (tmp / (4 * 0xff));
|
||||||
|
|
||||||
|
out_U += GST_VIDEO_INFO_COMP_PSTRIDE (&state->info, 1);
|
||||||
|
out_V += GST_VIDEO_INFO_COMP_PSTRIDE (&state->info, 2);
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,9 +34,6 @@
|
||||||
|
|
||||||
#include <gst/gst-i18n-plugin.h>
|
#include <gst/gst-i18n-plugin.h>
|
||||||
#include <gst/video/video.h>
|
#include <gst/video/video.h>
|
||||||
#include <gst/video/video-overlay-composition.h>
|
|
||||||
#include <gst/video/gstvideometa.h>
|
|
||||||
#include <gst/video/gstvideosink.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -56,19 +53,19 @@ enum
|
||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
};
|
};
|
||||||
|
|
||||||
#define VIDEO_FORMATS GST_VIDEO_OVERLAY_COMPOSITION_BLEND_FORMATS
|
|
||||||
|
|
||||||
static GstStaticPadTemplate video_sink_factory =
|
static GstStaticPadTemplate video_sink_factory =
|
||||||
GST_STATIC_PAD_TEMPLATE ("video",
|
GST_STATIC_PAD_TEMPLATE ("video",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (VIDEO_FORMATS))
|
GST_STATIC_CAPS ("video/x-raw, " "format = (string) { I420, NV12, YV12 }, "
|
||||||
|
"width = (int) [ 16, 4096 ], " "height = (int) [ 16, 4096 ]")
|
||||||
);
|
);
|
||||||
|
|
||||||
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (VIDEO_FORMATS))
|
GST_STATIC_CAPS ("video/x-raw, " "format = (string) { I420, NV12, YV12 }, "
|
||||||
|
"width = (int) [ 16, 4096 ], " "height = (int) [ 16, 4096 ]")
|
||||||
);
|
);
|
||||||
|
|
||||||
static GstStaticPadTemplate subpic_sink_factory =
|
static GstStaticPadTemplate subpic_sink_factory =
|
||||||
|
@ -110,7 +107,6 @@ static gboolean gst_dvd_spu_subpic_event (GstPad * pad, GstObject * parent,
|
||||||
GstEvent * event);
|
GstEvent * event);
|
||||||
static gboolean gst_dvd_spu_subpic_set_caps (GstDVDSpu * dvdspu, GstPad * pad,
|
static gboolean gst_dvd_spu_subpic_set_caps (GstDVDSpu * dvdspu, GstPad * pad,
|
||||||
GstCaps * caps);
|
GstCaps * caps);
|
||||||
static gboolean gst_dvd_spu_negotiate (GstDVDSpu * dvdspu);
|
|
||||||
|
|
||||||
static void gst_dvd_spu_clear (GstDVDSpu * dvdspu);
|
static void gst_dvd_spu_clear (GstDVDSpu * dvdspu);
|
||||||
static void gst_dvd_spu_flush_spu_info (GstDVDSpu * dvdspu,
|
static void gst_dvd_spu_flush_spu_info (GstDVDSpu * dvdspu,
|
||||||
|
@ -213,7 +209,14 @@ static void
|
||||||
gst_dvd_spu_finalize (GObject * object)
|
gst_dvd_spu_finalize (GObject * object)
|
||||||
{
|
{
|
||||||
GstDVDSpu *dvdspu = GST_DVD_SPU (object);
|
GstDVDSpu *dvdspu = GST_DVD_SPU (object);
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
if (dvdspu->spu_state.comp_bufs[i] != NULL) {
|
||||||
|
g_free (dvdspu->spu_state.comp_bufs[i]);
|
||||||
|
dvdspu->spu_state.comp_bufs[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
g_queue_free (dvdspu->pending_spus);
|
g_queue_free (dvdspu->pending_spus);
|
||||||
g_mutex_clear (&dvdspu->spu_lock);
|
g_mutex_clear (&dvdspu->spu_lock);
|
||||||
|
|
||||||
|
@ -318,20 +321,24 @@ gst_dvd_spu_video_set_caps (GstDVDSpu * dvdspu, GstPad * pad, GstCaps * caps)
|
||||||
{
|
{
|
||||||
gboolean res = FALSE;
|
gboolean res = FALSE;
|
||||||
GstVideoInfo info;
|
GstVideoInfo info;
|
||||||
|
gint i;
|
||||||
SpuState *state;
|
SpuState *state;
|
||||||
|
|
||||||
if (!gst_video_info_from_caps (&info, caps))
|
if (!gst_video_info_from_caps (&info, caps))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
res = gst_pad_set_caps (dvdspu->srcpad, caps);
|
|
||||||
if (res) {
|
|
||||||
DVD_SPU_LOCK (dvdspu);
|
DVD_SPU_LOCK (dvdspu);
|
||||||
state = &dvdspu->spu_state;
|
|
||||||
state->info = info;
|
|
||||||
gst_dvd_spu_negotiate (dvdspu);
|
|
||||||
DVD_SPU_UNLOCK (dvdspu);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
state = &dvdspu->spu_state;
|
||||||
|
|
||||||
|
state->info = info;
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
state->comp_bufs[i] = g_realloc (state->comp_bufs[i],
|
||||||
|
sizeof (guint32) * info.width);
|
||||||
|
}
|
||||||
|
DVD_SPU_UNLOCK (dvdspu);
|
||||||
|
|
||||||
|
res = TRUE;
|
||||||
done:
|
done:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -548,9 +555,6 @@ gst_dvd_spu_video_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||||||
|
|
||||||
g_return_val_if_fail (dvdspu != NULL, GST_FLOW_ERROR);
|
g_return_val_if_fail (dvdspu != NULL, GST_FLOW_ERROR);
|
||||||
|
|
||||||
if (gst_pad_check_reconfigure (dvdspu->srcpad))
|
|
||||||
gst_dvd_spu_negotiate (dvdspu);
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (dvdspu, "video buffer %p with TS %" GST_TIME_FORMAT,
|
GST_LOG_OBJECT (dvdspu, "video buffer %p with TS %" GST_TIME_FORMAT,
|
||||||
buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
|
buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
|
||||||
|
|
||||||
|
@ -655,104 +659,13 @@ no_ref_frame:
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gstspu_fit_overlay_rectangle (GstDVDSpu * dvdspu, GstVideoRectangle * rect,
|
static void
|
||||||
gint spu_width, gint spu_height)
|
gstspu_render (GstDVDSpu * dvdspu, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
gint video_width = GST_VIDEO_INFO_WIDTH (&dvdspu->spu_state.info);
|
|
||||||
gint video_height = GST_VIDEO_INFO_HEIGHT (&dvdspu->spu_state.info);
|
|
||||||
GstVideoRectangle r;
|
|
||||||
|
|
||||||
r = *rect;
|
|
||||||
|
|
||||||
if (spu_width != video_width || spu_height != video_height) {
|
|
||||||
gdouble hscale, vscale;
|
|
||||||
|
|
||||||
hscale = (gdouble) video_width / (gdouble) spu_width;
|
|
||||||
vscale = (gdouble) video_height / (gdouble) spu_height;
|
|
||||||
|
|
||||||
r.x *= hscale;
|
|
||||||
r.y *= vscale;
|
|
||||||
r.w *= hscale;
|
|
||||||
r.h *= vscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r.x + r.w > video_width)
|
|
||||||
r.x = video_width - r.w;
|
|
||||||
|
|
||||||
if (r.x < 0) {
|
|
||||||
r.x = 0;
|
|
||||||
if (r.w > video_width)
|
|
||||||
r.w = video_width;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r.y + r.h > video_height)
|
|
||||||
r.y = video_height - r.h;
|
|
||||||
|
|
||||||
if (r.y < 0) {
|
|
||||||
r.y = 0;
|
|
||||||
if (r.h > video_height)
|
|
||||||
r.h = video_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r.x != rect->x || r.y != rect->y || r.w != rect->w || r.h != rect->h) {
|
|
||||||
*rect = r;
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstVideoOverlayComposition *
|
|
||||||
gstspu_render_composition (GstDVDSpu * dvdspu)
|
|
||||||
{
|
|
||||||
GstBuffer *buffer;
|
|
||||||
GstVideoInfo overlay_info;
|
|
||||||
GstVideoFormat format;
|
|
||||||
GstVideoFrame frame;
|
GstVideoFrame frame;
|
||||||
GstVideoOverlayRectangle *rectangle;
|
|
||||||
GstVideoOverlayComposition *composition;
|
|
||||||
GstVideoRectangle win;
|
|
||||||
gint spu_w, spu_h;
|
|
||||||
gsize size;
|
|
||||||
|
|
||||||
format = GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_YUV;
|
gst_video_frame_map (&frame, &dvdspu->spu_state.info, buf, GST_MAP_READWRITE);
|
||||||
|
|
||||||
switch (dvdspu->spu_input_type) {
|
|
||||||
case SPU_INPUT_TYPE_PGS:
|
|
||||||
gstspu_pgs_get_render_geometry (dvdspu, &spu_w, &spu_h, &win);
|
|
||||||
break;
|
|
||||||
case SPU_INPUT_TYPE_VOBSUB:
|
|
||||||
gstspu_vobsub_get_render_geometry (dvdspu, &spu_w, &spu_h, &win);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
switch (dvdspu->spu_input_type) {
|
||||||
case SPU_INPUT_TYPE_VOBSUB:
|
case SPU_INPUT_TYPE_VOBSUB:
|
||||||
|
@ -764,61 +677,7 @@ gstspu_render_composition (GstDVDSpu * dvdspu)
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_video_frame_unmap (&frame);
|
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))
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gstspu_render (GstDVDSpu * dvdspu, GstBuffer * buf)
|
|
||||||
{
|
|
||||||
GstVideoOverlayComposition *composition;
|
|
||||||
GstVideoFrame frame;
|
|
||||||
|
|
||||||
composition = gstspu_render_composition (dvdspu);
|
|
||||||
if (!composition)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (dvdspu->attach_compo_to_buffer) {
|
|
||||||
gst_buffer_add_video_overlay_composition_meta (buf, composition);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gst_video_frame_map (&frame, &dvdspu->spu_state.info, buf,
|
|
||||||
GST_MAP_READWRITE)) {
|
|
||||||
GST_WARNING_OBJECT (dvdspu, "failed to map video frame for blending");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_video_overlay_composition_blend (composition, &frame);
|
|
||||||
gst_video_frame_unmap (&frame);
|
|
||||||
|
|
||||||
done:
|
|
||||||
gst_video_overlay_composition_unref (composition);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* With SPU LOCK */
|
/* With SPU LOCK */
|
||||||
|
@ -1044,41 +903,6 @@ submit_new_spu_packet (GstDVDSpu * dvdspu, GstBuffer * buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_dvd_spu_negotiate (GstDVDSpu * dvdspu)
|
|
||||||
{
|
|
||||||
GstQuery *query;
|
|
||||||
GstCaps *caps;
|
|
||||||
gboolean attach = FALSE;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (dvdspu, "performing negotiation");
|
|
||||||
|
|
||||||
caps = gst_pad_get_current_caps (dvdspu->srcpad);
|
|
||||||
if (!caps || gst_caps_is_empty (caps))
|
|
||||||
goto no_format;
|
|
||||||
|
|
||||||
query = gst_query_new_allocation (caps, FALSE);
|
|
||||||
|
|
||||||
if (!gst_pad_peer_query (dvdspu->srcpad, query))
|
|
||||||
GST_DEBUG_OBJECT (dvdspu, "ALLOCATION query failed");
|
|
||||||
|
|
||||||
if (gst_query_find_allocation_meta (query,
|
|
||||||
GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL))
|
|
||||||
attach = TRUE;
|
|
||||||
|
|
||||||
gst_query_unref (query);
|
|
||||||
gst_caps_unref (caps);
|
|
||||||
|
|
||||||
dvdspu->attach_compo_to_buffer = attach;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
no_format:
|
|
||||||
if (caps)
|
|
||||||
gst_caps_unref (caps);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_dvd_spu_subpic_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
gst_dvd_spu_subpic_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
|
|
|
@ -71,6 +71,10 @@ struct SpuState {
|
||||||
|
|
||||||
GstVideoInfo info;
|
GstVideoInfo info;
|
||||||
|
|
||||||
|
guint32 *comp_bufs[3]; /* Compositing buffers for U+V & A */
|
||||||
|
guint16 comp_left;
|
||||||
|
guint16 comp_right;
|
||||||
|
|
||||||
SpuVobsubState vobsub;
|
SpuVobsubState vobsub;
|
||||||
SpuPgsState pgs;
|
SpuPgsState pgs;
|
||||||
};
|
};
|
||||||
|
@ -112,9 +116,6 @@ struct _GstDVDSpu {
|
||||||
|
|
||||||
/* Buffer to push after handling a DVD event, if any */
|
/* Buffer to push after handling a DVD event, if any */
|
||||||
GstBuffer *pending_frame;
|
GstBuffer *pending_frame;
|
||||||
|
|
||||||
/* Overlay composition */
|
|
||||||
gboolean attach_compo_to_buffer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstDVDSpuClass {
|
struct _GstDVDSpuClass {
|
||||||
|
|
|
@ -39,21 +39,19 @@ struct SpuRect {
|
||||||
gint16 bottom;
|
gint16 bottom;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Store a pre-multiplied YUV colour value */
|
/* Store a pre-multiplied colour value. The YUV fields hold the YUV values
|
||||||
|
* multiplied by the 8-bit alpha, to save computing it while rendering */
|
||||||
struct SpuColour {
|
struct SpuColour {
|
||||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
guint16 Y;
|
||||||
|
guint16 U;
|
||||||
|
guint16 V;
|
||||||
guint8 A;
|
guint8 A;
|
||||||
guint8 Y;
|
|
||||||
guint8 U;
|
|
||||||
guint8 V;
|
|
||||||
#else
|
|
||||||
guint8 V;
|
|
||||||
guint8 U;
|
|
||||||
guint8 Y;
|
|
||||||
guint8 A;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void gstspu_clear_comp_buffers (SpuState * state);
|
||||||
|
void gstspu_blend_comp_buffers (SpuState * state, guint8 * planes[3]);
|
||||||
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GSTSPU_COMMON_H__ */
|
#endif /* __GSTSPU_COMMON_H__ */
|
||||||
|
|
|
@ -171,19 +171,15 @@ dump_rle_data (GstDVDSpu * dvdspu, guint8 * data, guint32 len)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pgs_composition_object_render (PgsCompositionObject * obj, SpuState * state,
|
pgs_composition_object_render (PgsCompositionObject * obj, SpuState * state,
|
||||||
GstVideoFrame * window)
|
GstVideoFrame * frame)
|
||||||
{
|
{
|
||||||
SpuColour *colour;
|
SpuColour *colour;
|
||||||
guint8 *pixels, *p;
|
guint8 *planes[3]; /* YUV frame pointers */
|
||||||
gint stride;
|
gint strides[3];
|
||||||
gint win_w;
|
|
||||||
gint win_h;
|
|
||||||
guint8 *data, *end;
|
guint8 *data, *end;
|
||||||
guint16 obj_w, obj_h;
|
guint16 obj_w;
|
||||||
gint obj_x, obj_y;
|
guint16 obj_h G_GNUC_UNUSED;
|
||||||
gint min_x, max_x;
|
guint x, y, i, min_x, max_x;
|
||||||
gint min_y, max_y;
|
|
||||||
gint x, y, i;
|
|
||||||
|
|
||||||
if (G_UNLIKELY (obj->rle_data == NULL || obj->rle_data_size == 0
|
if (G_UNLIKELY (obj->rle_data == NULL || obj->rle_data_size == 0
|
||||||
|| obj->rle_data_used != obj->rle_data_size))
|
|| obj->rle_data_used != obj->rle_data_size))
|
||||||
|
@ -195,47 +191,37 @@ pgs_composition_object_render (PgsCompositionObject * obj, SpuState * state,
|
||||||
if (data + 4 > end)
|
if (data + 4 > end)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pixels = GST_VIDEO_FRAME_PLANE_DATA (window, 0);
|
/* FIXME: Calculate and use the cropping window for the output, as the
|
||||||
stride = GST_VIDEO_FRAME_PLANE_STRIDE (window, 0);
|
* intersection of the crop rectangle for this object (if any) and the
|
||||||
win_w = GST_VIDEO_FRAME_WIDTH (window);
|
* window specified by the object's window_id */
|
||||||
win_h = GST_VIDEO_FRAME_HEIGHT (window);
|
|
||||||
|
|
||||||
|
/* Store the start of each plane */
|
||||||
|
planes[0] = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
|
||||||
|
planes[1] = GST_VIDEO_FRAME_COMP_DATA (frame, 1);
|
||||||
|
planes[2] = GST_VIDEO_FRAME_COMP_DATA (frame, 2);
|
||||||
|
|
||||||
|
strides[0] = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
|
||||||
|
strides[1] = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1);
|
||||||
|
strides[2] = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2);
|
||||||
|
|
||||||
|
y = MIN (obj->y, state->info.height);
|
||||||
|
|
||||||
|
planes[0] += strides[0] * y;
|
||||||
|
planes[1] += strides[1] * (y / 2);
|
||||||
|
planes[2] += strides[2] * (y / 2);
|
||||||
|
|
||||||
|
/* RLE data: */
|
||||||
obj_w = GST_READ_UINT16_BE (data);
|
obj_w = GST_READ_UINT16_BE (data);
|
||||||
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 */
|
min_x = MIN (obj->x, strides[0]);
|
||||||
min_x = obj_x = (gint) obj->x - (gint) state->pgs.win_x;
|
max_x = MIN (obj->x + obj_w, strides[0]);
|
||||||
min_y = obj_y = (gint) obj->y - (gint) state->pgs.win_y;
|
|
||||||
|
|
||||||
if (obj->flags & PGS_COMPOSITION_OBJECT_FLAG_CROPPED) {
|
state->comp_left = x = min_x;
|
||||||
obj_x -= obj->crop_x;
|
state->comp_right = max_x;
|
||||||
obj_y -= obj->crop_y;
|
|
||||||
obj_w = MIN (obj_w, obj->crop_w);
|
|
||||||
obj_h = MIN (obj_h, obj->crop_h);
|
|
||||||
}
|
|
||||||
|
|
||||||
max_x = min_x + obj_w;
|
gstspu_clear_comp_buffers (state);
|
||||||
max_y = min_y + obj_h;
|
|
||||||
|
|
||||||
/* Early out if object is out of the window */
|
|
||||||
if (max_x <= 0 || max_y < 0 || min_x >= win_w || min_y >= win_h)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Crop inside window */
|
|
||||||
if (min_x < 0)
|
|
||||||
min_x = 0;
|
|
||||||
if (max_x > win_w)
|
|
||||||
max_x = win_w;
|
|
||||||
if (min_y < 0)
|
|
||||||
min_y = 0;
|
|
||||||
if (max_y > win_h)
|
|
||||||
max_y = win_h;
|
|
||||||
|
|
||||||
/* Write RLE data to the plane */
|
|
||||||
x = obj_x;
|
|
||||||
y = obj_y;
|
|
||||||
p = pixels + y * stride;
|
|
||||||
|
|
||||||
while (data < end) {
|
while (data < end) {
|
||||||
guint8 pal_id;
|
guint8 pal_id;
|
||||||
|
@ -278,56 +264,43 @@ pgs_composition_object_render (PgsCompositionObject * obj, SpuState * state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!run_len) {
|
|
||||||
x = obj_x;
|
|
||||||
y++;
|
|
||||||
if (y >= max_y)
|
|
||||||
break;
|
|
||||||
|
|
||||||
p = pixels + y * stride;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (y < min_y)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (x >= max_x)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (x < min_x) {
|
|
||||||
if (x + run_len <= min_x) {
|
|
||||||
x += run_len;
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
run_len -= min_x - x;
|
|
||||||
x = min_x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
colour = &state->pgs.palette[pal_id];
|
colour = &state->pgs.palette[pal_id];
|
||||||
|
if (colour->A) {
|
||||||
if (colour->A > 0) {
|
guint32 inv_A = 0xff - colour->A;
|
||||||
guint8 inv_A = 255 - colour->A;
|
|
||||||
|
|
||||||
if (G_UNLIKELY (x + run_len > max_x))
|
if (G_UNLIKELY (x + run_len > max_x))
|
||||||
run_len = max_x - x;
|
run_len = (max_x - x);
|
||||||
|
|
||||||
for (i = 0; i < run_len; i++) {
|
for (i = 0; i < run_len; i++) {
|
||||||
SpuColour *pix = &((SpuColour *) p)[x++];
|
planes[0][x] = (inv_A * planes[0][x] + colour->Y) / 0xff;
|
||||||
|
|
||||||
if (pix->A == 0) {
|
state->comp_bufs[0][x / 2] += colour->U;
|
||||||
memcpy (pix, colour, sizeof (*pix));
|
state->comp_bufs[1][x / 2] += colour->V;
|
||||||
} else {
|
state->comp_bufs[2][x / 2] += colour->A;
|
||||||
pix->A = colour->A;
|
x++;
|
||||||
pix->Y = colour->Y + pix->Y * inv_A / 255;
|
|
||||||
pix->U = colour->U + pix->U * inv_A / 255;
|
|
||||||
pix->V = colour->V + pix->V * inv_A / 255;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
x += run_len;
|
x += run_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!run_len || x > max_x) {
|
||||||
|
x = min_x;
|
||||||
|
planes[0] += strides[0];
|
||||||
|
|
||||||
|
if (y % 2) {
|
||||||
|
gstspu_blend_comp_buffers (state, planes);
|
||||||
|
gstspu_clear_comp_buffers (state);
|
||||||
|
|
||||||
|
planes[1] += strides[1];
|
||||||
|
planes[2] += strides[2];
|
||||||
}
|
}
|
||||||
|
y++;
|
||||||
|
if (y >= state->info.height)
|
||||||
|
return; /* Hit the bottom */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y % 2)
|
||||||
|
gstspu_blend_comp_buffers (state, planes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -454,10 +427,8 @@ parse_presentation_segment (GstDVDSpu * dvdspu, guint8 type, guint8 * payload,
|
||||||
"x %u y %u\n", i, obj->id, obj->win_id, obj->flags, obj->x, obj->y);
|
"x %u y %u\n", i, obj->id, obj->win_id, obj->flags, obj->x, obj->y);
|
||||||
|
|
||||||
if (obj->flags & PGS_COMPOSITION_OBJECT_FLAG_CROPPED) {
|
if (obj->flags & PGS_COMPOSITION_OBJECT_FLAG_CROPPED) {
|
||||||
if (payload + 8 > end) {
|
if (payload + 8 > end)
|
||||||
obj->flags &= ~PGS_COMPOSITION_OBJECT_FLAG_CROPPED;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
obj->crop_x = GST_READ_UINT16_BE (payload);
|
obj->crop_x = GST_READ_UINT16_BE (payload);
|
||||||
obj->crop_y = GST_READ_UINT16_BE (payload + 2);
|
obj->crop_y = GST_READ_UINT16_BE (payload + 2);
|
||||||
|
@ -524,10 +495,10 @@ parse_set_palette (GstDVDSpu * dvdspu, guint8 type, guint8 * payload,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Premultiply the palette entries by the alpha */
|
/* Premultiply the palette entries by the alpha */
|
||||||
|
state->pgs.palette[n].Y = Y * A;
|
||||||
|
state->pgs.palette[n].U = U * A;
|
||||||
|
state->pgs.palette[n].V = V * A;
|
||||||
state->pgs.palette[n].A = A;
|
state->pgs.palette[n].A = A;
|
||||||
state->pgs.palette[n].Y = Y * A / 255;
|
|
||||||
state->pgs.palette[n].U = U * A / 255;
|
|
||||||
state->pgs.palette[n].V = V * A / 255;
|
|
||||||
|
|
||||||
payload += PGS_PALETTE_ENTRY_SIZE;
|
payload += PGS_PALETTE_ENTRY_SIZE;
|
||||||
}
|
}
|
||||||
|
@ -790,7 +761,7 @@ gstspu_pgs_execute_event (GstDVDSpu * dvdspu)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gstspu_pgs_render (GstDVDSpu * dvdspu, GstVideoFrame * window)
|
gstspu_pgs_render (GstDVDSpu * dvdspu, GstVideoFrame * frame)
|
||||||
{
|
{
|
||||||
SpuState *state = &dvdspu->spu_state;
|
SpuState *state = &dvdspu->spu_state;
|
||||||
PgsPresentationSegment *ps = &state->pgs.pres_seg;
|
PgsPresentationSegment *ps = &state->pgs.pres_seg;
|
||||||
|
@ -802,7 +773,7 @@ gstspu_pgs_render (GstDVDSpu * dvdspu, GstVideoFrame * window)
|
||||||
for (i = 0; i < ps->objects->len; i++) {
|
for (i = 0; i < ps->objects->len; i++) {
|
||||||
PgsCompositionObject *cur =
|
PgsCompositionObject *cur =
|
||||||
&g_array_index (ps->objects, PgsCompositionObject, i);
|
&g_array_index (ps->objects, PgsCompositionObject, i);
|
||||||
pgs_composition_object_render (cur, state, window);
|
pgs_composition_object_render (cur, state, frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -813,27 +784,6 @@ gstspu_pgs_handle_dvd_event (GstDVDSpu * dvdspu, GstEvent * event)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
gstspu_pgs_get_render_geometry (GstDVDSpu * dvdspu,
|
|
||||||
gint * display_width, gint * display_height,
|
|
||||||
GstVideoRectangle * window_rect)
|
|
||||||
{
|
|
||||||
SpuPgsState *pgs_state = &dvdspu->spu_state.pgs;
|
|
||||||
|
|
||||||
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 (display_width)
|
|
||||||
*display_width = pgs_state->pres_seg.vid_w;
|
|
||||||
|
|
||||||
if (display_height)
|
|
||||||
*display_height = pgs_state->pres_seg.vid_h;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
gstspu_pgs_flush (GstDVDSpu * dvdspu)
|
gstspu_pgs_flush (GstDVDSpu * dvdspu)
|
||||||
{
|
{
|
||||||
|
|
|
@ -99,11 +99,8 @@ struct SpuPgsState {
|
||||||
|
|
||||||
void gstspu_pgs_handle_new_buf (GstDVDSpu * dvdspu, GstClockTime event_ts, GstBuffer *buf);
|
void gstspu_pgs_handle_new_buf (GstDVDSpu * dvdspu, GstClockTime event_ts, GstBuffer *buf);
|
||||||
gboolean gstspu_pgs_execute_event (GstDVDSpu *dvdspu);
|
gboolean gstspu_pgs_execute_event (GstDVDSpu *dvdspu);
|
||||||
void gstspu_pgs_render (GstDVDSpu *dvdspu, GstVideoFrame *window);
|
void gstspu_pgs_render (GstDVDSpu *dvdspu, GstVideoFrame *frame);
|
||||||
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,
|
|
||||||
gint *display_width, gint *display_height,
|
|
||||||
GstVideoRectangle *window_rect);
|
|
||||||
void gstspu_pgs_flush (GstDVDSpu *dvdspu);
|
void gstspu_pgs_flush (GstDVDSpu *dvdspu);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -43,10 +43,10 @@ gstspu_vobsub_recalc_palette (GstDVDSpu * dvdspu,
|
||||||
|
|
||||||
/* Convert incoming 4-bit alpha to 8 bit for blending */
|
/* Convert incoming 4-bit alpha to 8 bit for blending */
|
||||||
dest->A = (alpha[i] << 4) | alpha[i];
|
dest->A = (alpha[i] << 4) | alpha[i];
|
||||||
dest->Y = ((col >> 16) & 0xff) * dest->A / 255;
|
dest->Y = ((guint16) ((col >> 16) & 0xff)) * dest->A;
|
||||||
/* U/V are stored as V/U in the clut words, so switch them */
|
/* U/V are stored as V/U in the clut words, so switch them */
|
||||||
dest->V = ((col >> 8) & 0xff) * dest->A / 255;
|
dest->V = ((guint16) ((col >> 8) & 0xff)) * dest->A;
|
||||||
dest->U = (col & 0xff) * dest->A / 255;
|
dest->U = ((guint16) (col & 0xff)) * dest->A;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int y = 240;
|
int y = 240;
|
||||||
|
@ -56,13 +56,13 @@ gstspu_vobsub_recalc_palette (GstDVDSpu * dvdspu,
|
||||||
for (i = 0; i < 4; i++, dest++) {
|
for (i = 0; i < 4; i++, dest++) {
|
||||||
dest->A = (alpha[i] << 4) | alpha[i];
|
dest->A = (alpha[i] << 4) | alpha[i];
|
||||||
if (alpha[i] != 0) {
|
if (alpha[i] != 0) {
|
||||||
dest[0].Y = y * dest[0].A / 255;
|
dest[0].Y = y * dest[0].A;
|
||||||
y -= 112;
|
y -= 112;
|
||||||
if (y < 0)
|
if (y < 0)
|
||||||
y = 0;
|
y = 0;
|
||||||
}
|
}
|
||||||
dest[0].U = 128 * dest[0].A / 255;
|
dest[0].U = 128 * dest[0].A;
|
||||||
dest[0].V = 128 * dest[0].A / 255;
|
dest[0].V = 128 * dest[0].A;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,36 +169,28 @@ gstspu_vobsub_get_rle_code (SpuState * state, guint16 * rle_offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline gboolean
|
static inline gboolean
|
||||||
gstspu_vobsub_draw_rle_run (SpuState * state, GstVideoFrame * frame,
|
gstspu_vobsub_draw_rle_run (SpuState * state, gint16 x, gint16 end,
|
||||||
gint16 x, gint16 end, SpuColour * colour)
|
SpuColour * colour)
|
||||||
{
|
{
|
||||||
GST_TRACE ("Y: %d x: %d end %d %d %d %d %d",
|
#if 0
|
||||||
|
GST_LOG ("Y: %d x: %d end %d col %d %d %d %d",
|
||||||
state->vobsub.cur_Y, x, end, colour->Y, colour->U, colour->V, colour->A);
|
state->vobsub.cur_Y, x, end, colour->Y, colour->U, colour->V, colour->A);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (colour->A > 0) {
|
if (colour->A != 0) {
|
||||||
gint i;
|
guint32 inv_A = 0xff - colour->A;
|
||||||
guint8 *data;
|
|
||||||
guint8 inv_A = 255 - colour->A;
|
|
||||||
|
|
||||||
data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
|
/* FIXME: This could be more efficient */
|
||||||
data += GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0) *
|
while (x < end) {
|
||||||
(state->vobsub.cur_Y - state->vobsub.disp_rect.top);
|
state->vobsub.out_Y[x] =
|
||||||
|
(inv_A * state->vobsub.out_Y[x] + colour->Y) / 0xff;
|
||||||
x -= state->vobsub.disp_rect.left;
|
state->vobsub.out_U[x / 2] += colour->U;
|
||||||
end -= state->vobsub.disp_rect.left;
|
state->vobsub.out_V[x / 2] += colour->V;
|
||||||
|
state->vobsub.out_A[x / 2] += colour->A;
|
||||||
for (i = x; i < end; i++) {
|
x++;
|
||||||
SpuColour *pix = &((SpuColour *) data)[x++];
|
|
||||||
|
|
||||||
if (pix->A == 0) {
|
|
||||||
memcpy (pix, colour, sizeof (*pix));
|
|
||||||
} else {
|
|
||||||
pix->A = colour->A;
|
|
||||||
pix->Y = colour->Y + pix->Y * inv_A / 255;
|
|
||||||
pix->U = colour->U + pix->U * inv_A / 255;
|
|
||||||
pix->V = colour->V + pix->V * inv_A / 255;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
/* Update the compositing buffer so we know how much to blend later */
|
||||||
|
*(state->vobsub.comp_last_x_ptr) = end - 1; /* end is the start of the *next* run */
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -216,11 +208,11 @@ rle_end_x (guint16 rle_code, gint16 x, gint16 end)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean gstspu_vobsub_render_line_with_chgcol (SpuState * state,
|
static gboolean gstspu_vobsub_render_line_with_chgcol (SpuState * state,
|
||||||
GstVideoFrame * frame, guint16 * rle_offset);
|
guint8 * planes[3], guint16 * rle_offset);
|
||||||
static gboolean gstspu_vobsub_update_chgcol (SpuState * state);
|
static gboolean gstspu_vobsub_update_chgcol (SpuState * state);
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gstspu_vobsub_render_line (SpuState * state, GstVideoFrame * frame,
|
gstspu_vobsub_render_line (SpuState * state, guint8 * planes[3],
|
||||||
guint16 * rle_offset)
|
guint16 * rle_offset)
|
||||||
{
|
{
|
||||||
gint16 x, next_x, end, rle_code, next_draw_x;
|
gint16 x, next_x, end, rle_code, next_draw_x;
|
||||||
|
@ -234,13 +226,19 @@ gstspu_vobsub_render_line (SpuState * state, GstVideoFrame * frame,
|
||||||
/* Check the top & bottom, because we might not be within the region yet */
|
/* Check the top & bottom, because we might not be within the region yet */
|
||||||
if (state->vobsub.cur_Y >= state->vobsub.cur_chg_col->top &&
|
if (state->vobsub.cur_Y >= state->vobsub.cur_chg_col->top &&
|
||||||
state->vobsub.cur_Y <= state->vobsub.cur_chg_col->bottom) {
|
state->vobsub.cur_Y <= state->vobsub.cur_chg_col->bottom) {
|
||||||
return gstspu_vobsub_render_line_with_chgcol (state, frame, rle_offset);
|
return gstspu_vobsub_render_line_with_chgcol (state, planes,
|
||||||
|
rle_offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No special case. Render as normal */
|
/* No special case. Render as normal */
|
||||||
|
|
||||||
|
/* Set up our output pointers */
|
||||||
|
state->vobsub.out_Y = planes[0];
|
||||||
|
state->vobsub.out_U = state->comp_bufs[0];
|
||||||
|
state->vobsub.out_V = state->comp_bufs[1];
|
||||||
|
state->vobsub.out_A = state->comp_bufs[2];
|
||||||
/* We always need to start our RLE decoding byte_aligned */
|
/* We always need to start our RLE decoding byte_aligned */
|
||||||
*rle_offset = GST_ROUND_UP_2 (*rle_offset);
|
*rle_offset = GST_ROUND_UP_2 (*rle_offset);
|
||||||
|
|
||||||
|
@ -251,10 +249,12 @@ gstspu_vobsub_render_line (SpuState * state, GstVideoFrame * frame,
|
||||||
colour = &state->vobsub.main_pal[rle_code & 3];
|
colour = &state->vobsub.main_pal[rle_code & 3];
|
||||||
next_x = rle_end_x (rle_code, x, end);
|
next_x = rle_end_x (rle_code, x, end);
|
||||||
next_draw_x = next_x;
|
next_draw_x = next_x;
|
||||||
if (next_draw_x > state->vobsub.disp_rect.right)
|
if (next_draw_x > state->vobsub.clip_rect.right)
|
||||||
next_draw_x = state->vobsub.disp_rect.right; /* ensure no overflow */
|
next_draw_x = state->vobsub.clip_rect.right; /* ensure no overflow */
|
||||||
/* Now draw the run between [x,next_x) */
|
/* Now draw the run between [x,next_x) */
|
||||||
visible |= gstspu_vobsub_draw_rle_run (state, frame, x, next_draw_x, colour);
|
if (state->vobsub.cur_Y >= state->vobsub.clip_rect.top &&
|
||||||
|
state->vobsub.cur_Y <= state->vobsub.clip_rect.bottom)
|
||||||
|
visible |= gstspu_vobsub_draw_rle_run (state, x, next_draw_x, colour);
|
||||||
x = next_x;
|
x = next_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +289,7 @@ gstspu_vobsub_update_chgcol (SpuState * state)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gstspu_vobsub_render_line_with_chgcol (SpuState * state, GstVideoFrame * frame,
|
gstspu_vobsub_render_line_with_chgcol (SpuState * state, guint8 * planes[3],
|
||||||
guint16 * rle_offset)
|
guint16 * rle_offset)
|
||||||
{
|
{
|
||||||
SpuVobsubLineCtrlI *chg_col = state->vobsub.cur_chg_col;
|
SpuVobsubLineCtrlI *chg_col = state->vobsub.cur_chg_col;
|
||||||
|
@ -304,6 +304,11 @@ gstspu_vobsub_render_line_with_chgcol (SpuState * state, GstVideoFrame * frame,
|
||||||
gint16 cur_reg_end;
|
gint16 cur_reg_end;
|
||||||
gint i;
|
gint i;
|
||||||
|
|
||||||
|
state->vobsub.out_Y = planes[0];
|
||||||
|
state->vobsub.out_U = state->comp_bufs[0];
|
||||||
|
state->vobsub.out_V = state->comp_bufs[1];
|
||||||
|
state->vobsub.out_A = state->comp_bufs[2];
|
||||||
|
|
||||||
/* We always need to start our RLE decoding byte_aligned */
|
/* We always need to start our RLE decoding byte_aligned */
|
||||||
*rle_offset = GST_ROUND_UP_2 (*rle_offset);
|
*rle_offset = GST_ROUND_UP_2 (*rle_offset);
|
||||||
|
|
||||||
|
@ -339,13 +344,12 @@ gstspu_vobsub_render_line_with_chgcol (SpuState * state, GstVideoFrame * frame,
|
||||||
run_end = MIN (next_x, cur_reg_end);
|
run_end = MIN (next_x, cur_reg_end);
|
||||||
|
|
||||||
run_draw_end = run_end;
|
run_draw_end = run_end;
|
||||||
if (run_draw_end > state->vobsub.disp_rect.right)
|
if (run_draw_end > state->vobsub.clip_rect.right)
|
||||||
run_draw_end = state->vobsub.disp_rect.right; /* ensure no overflow */
|
run_draw_end = state->vobsub.clip_rect.right; /* ensure no overflow */
|
||||||
|
|
||||||
if (G_LIKELY (x < run_end)) {
|
if (G_LIKELY (x < run_end)) {
|
||||||
colour = &cur_pix_ctrl->pal_cache[rle_code & 3];
|
colour = &cur_pix_ctrl->pal_cache[rle_code & 3];
|
||||||
visible |= gstspu_vobsub_draw_rle_run (state, frame, x,
|
visible |= gstspu_vobsub_draw_rle_run (state, x, run_draw_end, colour);
|
||||||
run_draw_end, colour);
|
|
||||||
x = run_end;
|
x = run_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,37 +369,52 @@ gstspu_vobsub_render_line_with_chgcol (SpuState * state, GstVideoFrame * frame,
|
||||||
return visible;
|
return visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gstspu_vobsub_blend_comp_buffers (SpuState * state, guint8 * planes[3])
|
||||||
|
{
|
||||||
|
state->comp_left = state->vobsub.disp_rect.left;
|
||||||
|
state->comp_right =
|
||||||
|
MAX (state->vobsub.comp_last_x[0], state->vobsub.comp_last_x[1]);
|
||||||
|
|
||||||
|
state->comp_left = MAX (state->comp_left, state->vobsub.clip_rect.left);
|
||||||
|
state->comp_right = MIN (state->comp_right, state->vobsub.clip_rect.right);
|
||||||
|
|
||||||
|
gstspu_blend_comp_buffers (state, planes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gstspu_vobsub_clear_comp_buffers (SpuState * state)
|
||||||
|
{
|
||||||
|
state->comp_left = state->vobsub.clip_rect.left;
|
||||||
|
state->comp_right = state->vobsub.clip_rect.right;
|
||||||
|
|
||||||
|
gstspu_clear_comp_buffers (state);
|
||||||
|
|
||||||
|
state->vobsub.comp_last_x[0] = -1;
|
||||||
|
state->vobsub.comp_last_x[1] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gstspu_vobsub_draw_highlight (SpuState * state,
|
gstspu_vobsub_draw_highlight (SpuState * state,
|
||||||
GstVideoFrame * frame, SpuRect * rect)
|
GstVideoFrame * frame, SpuRect * rect)
|
||||||
{
|
{
|
||||||
SpuColour *cur;
|
guint8 *cur;
|
||||||
SpuRect r;
|
|
||||||
guint8 *data;
|
|
||||||
guint stride;
|
|
||||||
gint16 pos;
|
gint16 pos;
|
||||||
|
gint ystride;
|
||||||
|
|
||||||
r.left = rect->left - state->vobsub.disp_rect.left;
|
ystride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
|
||||||
r.right = rect->right - state->vobsub.disp_rect.left;
|
|
||||||
r.top = rect->top - state->vobsub.disp_rect.top;
|
|
||||||
r.bottom = rect->bottom - state->vobsub.disp_rect.top;
|
|
||||||
rect = &r;
|
|
||||||
|
|
||||||
data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
|
cur = GST_VIDEO_FRAME_COMP_DATA (frame, 0) + ystride * rect->top;
|
||||||
stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
|
for (pos = rect->left + 1; pos < rect->right; pos++)
|
||||||
|
cur[pos] = (cur[pos] / 2) + 0x8;
|
||||||
cur = (SpuColour *) (data + stride * rect->top);
|
cur = GST_VIDEO_FRAME_COMP_DATA (frame, 0) + ystride * rect->bottom;
|
||||||
for (pos = rect->left; pos < rect->right; pos++)
|
for (pos = rect->left + 1; pos < rect->right; pos++)
|
||||||
cur[pos].A = 0x80;
|
cur[pos] = (cur[pos] / 2) + 0x8;
|
||||||
|
cur = GST_VIDEO_FRAME_COMP_DATA (frame, 0) + ystride * rect->top;
|
||||||
cur = (SpuColour *) (data + stride * (rect->bottom - 1));
|
for (pos = rect->top; pos <= rect->bottom; pos++) {
|
||||||
for (pos = rect->left; pos < rect->right; pos++)
|
cur[rect->left] = (cur[rect->left] / 2) + 0x8;
|
||||||
cur[pos].A = 0x80;
|
cur[rect->right] = (cur[rect->right] / 2) + 0x8;
|
||||||
|
cur += ystride;
|
||||||
for (pos = rect->top; pos < rect->bottom; pos++) {
|
|
||||||
cur = (SpuColour *) (data + stride * pos);
|
|
||||||
cur[rect->left].A = 0x80;
|
|
||||||
cur[rect->right - 1].A = 0x80;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,8 +422,10 @@ void
|
||||||
gstspu_vobsub_render (GstDVDSpu * dvdspu, GstVideoFrame * frame)
|
gstspu_vobsub_render (GstDVDSpu * dvdspu, GstVideoFrame * frame)
|
||||||
{
|
{
|
||||||
SpuState *state = &dvdspu->spu_state;
|
SpuState *state = &dvdspu->spu_state;
|
||||||
|
guint8 *planes[3]; /* YUV frame pointers */
|
||||||
gint y, last_y;
|
gint y, last_y;
|
||||||
guint16 cur_offsets[2];
|
gint width, height;
|
||||||
|
gint strides[3];
|
||||||
|
|
||||||
/* Set up our initial state */
|
/* Set up our initial state */
|
||||||
if (G_UNLIKELY (state->vobsub.pix_buf == NULL))
|
if (G_UNLIKELY (state->vobsub.pix_buf == NULL))
|
||||||
|
@ -414,6 +435,18 @@ gstspu_vobsub_render (GstDVDSpu * dvdspu, GstVideoFrame * frame)
|
||||||
GST_MAP_READ))
|
GST_MAP_READ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Store the start of each plane */
|
||||||
|
planes[0] = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
|
||||||
|
planes[1] = GST_VIDEO_FRAME_COMP_DATA (frame, 1);
|
||||||
|
planes[2] = GST_VIDEO_FRAME_COMP_DATA (frame, 2);
|
||||||
|
|
||||||
|
strides[0] = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
|
||||||
|
strides[1] = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1);
|
||||||
|
strides[2] = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2);
|
||||||
|
|
||||||
|
width = GST_VIDEO_FRAME_WIDTH (frame);
|
||||||
|
height = GST_VIDEO_FRAME_HEIGHT (frame);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (dvdspu,
|
GST_DEBUG_OBJECT (dvdspu,
|
||||||
"Rendering SPU. disp_rect %d,%d to %d,%d. hl_rect %d,%d to %d,%d",
|
"Rendering SPU. disp_rect %d,%d to %d,%d. hl_rect %d,%d to %d,%d",
|
||||||
state->vobsub.disp_rect.left, state->vobsub.disp_rect.top,
|
state->vobsub.disp_rect.left, state->vobsub.disp_rect.top,
|
||||||
|
@ -421,6 +454,13 @@ gstspu_vobsub_render (GstDVDSpu * dvdspu, GstVideoFrame * frame)
|
||||||
state->vobsub.hl_rect.left, state->vobsub.hl_rect.top,
|
state->vobsub.hl_rect.left, state->vobsub.hl_rect.top,
|
||||||
state->vobsub.hl_rect.right, state->vobsub.hl_rect.bottom);
|
state->vobsub.hl_rect.right, state->vobsub.hl_rect.bottom);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dvdspu, "video size %d,%d", width, height);
|
||||||
|
|
||||||
|
/* When reading RLE data, we track the offset in nibbles... */
|
||||||
|
state->vobsub.cur_offsets[0] = state->vobsub.pix_data[0] * 2;
|
||||||
|
state->vobsub.cur_offsets[1] = state->vobsub.pix_data[1] * 2;
|
||||||
|
state->vobsub.max_offset = state->vobsub.pix_buf_map.size * 2;
|
||||||
|
|
||||||
/* Update all the palette caches */
|
/* Update all the palette caches */
|
||||||
gstspu_vobsub_update_palettes (dvdspu, state);
|
gstspu_vobsub_update_palettes (dvdspu, state);
|
||||||
|
|
||||||
|
@ -435,25 +475,140 @@ gstspu_vobsub_render (GstDVDSpu * dvdspu, GstVideoFrame * frame)
|
||||||
} else
|
} else
|
||||||
state->vobsub.cur_chg_col = NULL;
|
state->vobsub.cur_chg_col = NULL;
|
||||||
|
|
||||||
/* We start rendering from the first line of the display rect */
|
state->vobsub.clip_rect.left = state->vobsub.disp_rect.left;
|
||||||
y = state->vobsub.disp_rect.top;
|
state->vobsub.clip_rect.right = state->vobsub.disp_rect.right;
|
||||||
last_y = state->vobsub.disp_rect.bottom;
|
|
||||||
|
|
||||||
/* When reading RLE data, we track the offset in nibbles... */
|
/* center the image when display rectangle exceeds the video width */
|
||||||
state->vobsub.max_offset = state->vobsub.pix_buf_map.size * 2;
|
if (width <= state->vobsub.disp_rect.right) {
|
||||||
if (y & 1) {
|
gint left, disp_width;
|
||||||
cur_offsets[1] = state->vobsub.pix_data[0] * 2;
|
|
||||||
cur_offsets[0] = state->vobsub.pix_data[1] * 2;
|
disp_width = state->vobsub.disp_rect.right - state->vobsub.disp_rect.left
|
||||||
} else {
|
+ 1;
|
||||||
cur_offsets[0] = state->vobsub.pix_data[0] * 2;
|
left = (width - disp_width) / 2;
|
||||||
cur_offsets[1] = state->vobsub.pix_data[1] * 2;
|
state->vobsub.disp_rect.left = left;
|
||||||
|
state->vobsub.disp_rect.right = left + disp_width - 1;
|
||||||
|
|
||||||
|
/* if it clips to the right, shift it left, but only till zero */
|
||||||
|
if (state->vobsub.disp_rect.right >= width) {
|
||||||
|
gint shift = state->vobsub.disp_rect.right - width - 1;
|
||||||
|
if (shift > state->vobsub.disp_rect.left)
|
||||||
|
shift = state->vobsub.disp_rect.left;
|
||||||
|
state->vobsub.disp_rect.left -= shift;
|
||||||
|
state->vobsub.disp_rect.right -= shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Render line by line */
|
/* init clip to disp */
|
||||||
|
state->vobsub.clip_rect.left = state->vobsub.disp_rect.left;
|
||||||
|
state->vobsub.clip_rect.right = state->vobsub.disp_rect.right;
|
||||||
|
|
||||||
|
/* clip right after the shift */
|
||||||
|
if (state->vobsub.clip_rect.right >= width)
|
||||||
|
state->vobsub.clip_rect.right = width - 1;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dvdspu,
|
||||||
|
"clipping width to %d,%d", state->vobsub.clip_rect.left,
|
||||||
|
state->vobsub.clip_rect.right);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for the height, bring it up till it fits as well as it can. We
|
||||||
|
* assume the picture is in the lower part. We should better check where it
|
||||||
|
* is and do something more clever. */
|
||||||
|
state->vobsub.clip_rect.top = state->vobsub.disp_rect.top;
|
||||||
|
state->vobsub.clip_rect.bottom = state->vobsub.disp_rect.bottom;
|
||||||
|
if (height <= state->vobsub.disp_rect.bottom) {
|
||||||
|
|
||||||
|
/* shift it up, but only till zero */
|
||||||
|
gint shift = state->vobsub.disp_rect.bottom - height - 1;
|
||||||
|
if (shift > state->vobsub.disp_rect.top)
|
||||||
|
shift = state->vobsub.disp_rect.top;
|
||||||
|
state->vobsub.disp_rect.top -= shift;
|
||||||
|
state->vobsub.disp_rect.bottom -= shift;
|
||||||
|
|
||||||
|
/* start on even line */
|
||||||
|
if (state->vobsub.disp_rect.top & 1) {
|
||||||
|
state->vobsub.disp_rect.top--;
|
||||||
|
state->vobsub.disp_rect.bottom--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* init clip to disp */
|
||||||
|
state->vobsub.clip_rect.top = state->vobsub.disp_rect.top;
|
||||||
|
state->vobsub.clip_rect.bottom = state->vobsub.disp_rect.bottom;
|
||||||
|
|
||||||
|
/* clip right after the shift */
|
||||||
|
if (state->vobsub.clip_rect.bottom >= height)
|
||||||
|
state->vobsub.clip_rect.bottom = height - 1;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dvdspu,
|
||||||
|
"clipping height to %d,%d", state->vobsub.clip_rect.top,
|
||||||
|
state->vobsub.clip_rect.bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We start rendering from the first line of the display rect */
|
||||||
|
y = state->vobsub.disp_rect.top;
|
||||||
|
/* start_y is always an even number and we render lines in pairs from there,
|
||||||
|
* accumulating 2 lines of chroma then blending it. We might need to render a
|
||||||
|
* single line at the end if the display rect ends on an even line too. */
|
||||||
|
last_y = (state->vobsub.disp_rect.bottom - 1) & ~(0x01);
|
||||||
|
|
||||||
|
/* Update our plane references to the first line of the disp_rect */
|
||||||
|
planes[0] += strides[0] * y;
|
||||||
|
planes[1] += strides[1] * (y / 2);
|
||||||
|
planes[2] += strides[2] * (y / 2);
|
||||||
|
|
||||||
for (state->vobsub.cur_Y = y; state->vobsub.cur_Y <= last_y;
|
for (state->vobsub.cur_Y = y; state->vobsub.cur_Y <= last_y;
|
||||||
state->vobsub.cur_Y++) {
|
state->vobsub.cur_Y++) {
|
||||||
gstspu_vobsub_render_line (state, frame,
|
gboolean clip, visible = FALSE;
|
||||||
&cur_offsets[state->vobsub.cur_Y & 1]);
|
|
||||||
|
clip = (state->vobsub.cur_Y < state->vobsub.clip_rect.top
|
||||||
|
|| state->vobsub.cur_Y > state->vobsub.clip_rect.bottom);
|
||||||
|
|
||||||
|
/* Reset the compositing buffer */
|
||||||
|
gstspu_vobsub_clear_comp_buffers (state);
|
||||||
|
/* Render even line */
|
||||||
|
state->vobsub.comp_last_x_ptr = state->vobsub.comp_last_x;
|
||||||
|
gstspu_vobsub_render_line (state, planes, &state->vobsub.cur_offsets[0]);
|
||||||
|
|
||||||
|
/* Advance the luminance output pointer */
|
||||||
|
planes[0] += strides[0];
|
||||||
|
|
||||||
|
state->vobsub.cur_Y++;
|
||||||
|
|
||||||
|
/* Render odd line */
|
||||||
|
state->vobsub.comp_last_x_ptr = state->vobsub.comp_last_x + 1;
|
||||||
|
visible |=
|
||||||
|
gstspu_vobsub_render_line (state, planes,
|
||||||
|
&state->vobsub.cur_offsets[1]);
|
||||||
|
|
||||||
|
if (visible && !clip) {
|
||||||
|
/* Blend the accumulated UV compositing buffers onto the output */
|
||||||
|
gstspu_vobsub_blend_comp_buffers (state, planes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update all the output pointers */
|
||||||
|
planes[0] += strides[0];
|
||||||
|
planes[1] += strides[1];
|
||||||
|
planes[2] += strides[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->vobsub.cur_Y == state->vobsub.disp_rect.bottom) {
|
||||||
|
gboolean clip, visible = FALSE;
|
||||||
|
|
||||||
|
clip = (state->vobsub.cur_Y < state->vobsub.clip_rect.top
|
||||||
|
|| state->vobsub.cur_Y > state->vobsub.clip_rect.bottom);
|
||||||
|
|
||||||
|
g_assert ((state->vobsub.disp_rect.bottom & 0x01) == 0);
|
||||||
|
|
||||||
|
if (!clip) {
|
||||||
|
/* Render a remaining lone last even line. y already has the correct value
|
||||||
|
* after the above loop exited. */
|
||||||
|
gstspu_vobsub_clear_comp_buffers (state);
|
||||||
|
state->vobsub.comp_last_x_ptr = state->vobsub.comp_last_x;
|
||||||
|
visible |=
|
||||||
|
gstspu_vobsub_render_line (state, planes,
|
||||||
|
&state->vobsub.cur_offsets[0]);
|
||||||
|
if (visible)
|
||||||
|
gstspu_vobsub_blend_comp_buffers (state, planes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* for debugging purposes, draw a faint rectangle at the edges of the disp_rect */
|
/* for debugging purposes, draw a faint rectangle at the edges of the disp_rect */
|
||||||
|
|
|
@ -492,29 +492,6 @@ gstspu_vobsub_handle_dvd_event (GstDVDSpu * dvdspu, GstEvent * event)
|
||||||
return hl_change;
|
return hl_change;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
gstspu_vobsub_get_render_geometry (GstDVDSpu * dvdspu,
|
|
||||||
gint * display_width, gint * display_height,
|
|
||||||
GstVideoRectangle * window_rect)
|
|
||||||
{
|
|
||||||
SpuState *state = &dvdspu->spu_state;
|
|
||||||
|
|
||||||
if (window_rect) {
|
|
||||||
window_rect->x = state->vobsub.disp_rect.left;
|
|
||||||
window_rect->y = state->vobsub.disp_rect.top;
|
|
||||||
window_rect->w = state->vobsub.disp_rect.right -
|
|
||||||
state->vobsub.disp_rect.left + 1;
|
|
||||||
window_rect->h = state->vobsub.disp_rect.bottom -
|
|
||||||
state->vobsub.disp_rect.top + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (display_width)
|
|
||||||
*display_width = state->info.width;
|
|
||||||
|
|
||||||
if (display_height)
|
|
||||||
*display_height = state->info.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
gstspu_vobsub_flush (GstDVDSpu * dvdspu)
|
gstspu_vobsub_flush (GstDVDSpu * dvdspu)
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,6 +55,7 @@ struct SpuVobsubState {
|
||||||
GstMapInfo pix_buf_map; /* Mapped buffer info */
|
GstMapInfo pix_buf_map; /* Mapped buffer info */
|
||||||
|
|
||||||
SpuRect disp_rect;
|
SpuRect disp_rect;
|
||||||
|
SpuRect clip_rect;
|
||||||
SpuRect hl_rect;
|
SpuRect hl_rect;
|
||||||
|
|
||||||
guint32 current_clut[16]; /* Colour lookup table from incoming events */
|
guint32 current_clut[16]; /* Colour lookup table from incoming events */
|
||||||
|
@ -80,25 +81,31 @@ struct SpuVobsubState {
|
||||||
* need recalculating */
|
* need recalculating */
|
||||||
|
|
||||||
/* Rendering state vars below */
|
/* Rendering state vars below */
|
||||||
|
gint16 comp_last_x[2]; /* Maximum X values we rendered into the comp buffer (odd & even) */
|
||||||
|
gint16 *comp_last_x_ptr; /* Ptr to the current comp_last_x value to be updated by the render */
|
||||||
|
|
||||||
/* Current Y Position */
|
/* Current Y Position */
|
||||||
gint16 cur_Y;
|
gint16 cur_Y;
|
||||||
|
|
||||||
/* Current offset in nibbles into the pix_data */
|
/* Current offset in nibbles into the pix_data */
|
||||||
|
guint16 cur_offsets[2];
|
||||||
guint16 max_offset;
|
guint16 max_offset;
|
||||||
|
|
||||||
/* current ChgColCon Line Info */
|
/* current ChgColCon Line Info */
|
||||||
SpuVobsubLineCtrlI *cur_chg_col;
|
SpuVobsubLineCtrlI *cur_chg_col;
|
||||||
SpuVobsubLineCtrlI *cur_chg_col_end;
|
SpuVobsubLineCtrlI *cur_chg_col_end;
|
||||||
|
|
||||||
|
/* Output position tracking */
|
||||||
|
guint8 *out_Y;
|
||||||
|
guint32 *out_U;
|
||||||
|
guint32 *out_V;
|
||||||
|
guint32 *out_A;
|
||||||
};
|
};
|
||||||
|
|
||||||
void gstspu_vobsub_handle_new_buf (GstDVDSpu * dvdspu, GstClockTime event_ts, GstBuffer *buf);
|
void gstspu_vobsub_handle_new_buf (GstDVDSpu * dvdspu, GstClockTime event_ts, GstBuffer *buf);
|
||||||
gboolean gstspu_vobsub_execute_event (GstDVDSpu *dvdspu);
|
gboolean gstspu_vobsub_execute_event (GstDVDSpu *dvdspu);
|
||||||
void gstspu_vobsub_render (GstDVDSpu *dvdspu, GstVideoFrame *frame);
|
void gstspu_vobsub_render (GstDVDSpu *dvdspu, GstVideoFrame *frame);
|
||||||
gboolean gstspu_vobsub_handle_dvd_event (GstDVDSpu *dvdspu, GstEvent *event);
|
gboolean gstspu_vobsub_handle_dvd_event (GstDVDSpu *dvdspu, GstEvent *event);
|
||||||
void gstspu_vobsub_get_render_geometry (GstDVDSpu *dvdspu,
|
|
||||||
gint *display_width, gint *display_height,
|
|
||||||
GstVideoRectangle *window_rect);
|
|
||||||
void gstspu_vobsub_flush (GstDVDSpu *dvdspu);
|
void gstspu_vobsub_flush (GstDVDSpu *dvdspu);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue