mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-04 05:22:30 +00:00
Merge branch 'master' into 0.11
Conflicts: gst-libs/gst/tag/gstvorbistag.c
This commit is contained in:
commit
da1c863711
11 changed files with 403 additions and 84 deletions
|
@ -62,6 +62,11 @@ GST_DEBUG_CATEGORY_STATIC (gst_ogg_mux_debug);
|
|||
? GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf) \
|
||||
: GST_BUFFER_TIMESTAMP (buf))
|
||||
|
||||
#define GST_BUFFER_RUNNING_TIME(buf, oggpad) \
|
||||
(GST_BUFFER_DURATION_IS_VALID (buf) \
|
||||
? gst_segment_to_running_time (&(oggpad)->segment, GST_FORMAT_TIME, \
|
||||
GST_BUFFER_TIMESTAMP (buf)) : 0)
|
||||
|
||||
#define GST_GP_FORMAT "[gp %8" G_GINT64_FORMAT "]"
|
||||
#define GST_GP_CAST(_gp) ((gint64) _gp)
|
||||
|
||||
|
@ -319,11 +324,30 @@ gst_ogg_mux_sink_event (GstPad * pad, GstEvent * event)
|
|||
GST_DEBUG_PAD_NAME (pad));
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_NEWSEGMENT:
|
||||
/* We don't support NEWSEGMENT events */
|
||||
gst_event_unref (event);
|
||||
ret = FALSE;
|
||||
case GST_EVENT_NEWSEGMENT:{
|
||||
gboolean update;
|
||||
gdouble rate;
|
||||
gdouble applied_rate;
|
||||
GstFormat format;
|
||||
gint64 start, stop, position;
|
||||
|
||||
gst_event_parse_new_segment_full (event, &update, &rate,
|
||||
&applied_rate, &format, &start, &stop, &position);
|
||||
|
||||
/* We don't support non time NEWSEGMENT events */
|
||||
if (format != GST_FORMAT_TIME) {
|
||||
gst_event_unref (event);
|
||||
return FALSE;
|
||||
}
|
||||
gst_segment_set_newsegment_full (&ogg_pad->segment, update, rate,
|
||||
applied_rate, format, start, stop, position);
|
||||
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_FLUSH_STOP:{
|
||||
gst_segment_init (&ogg_pad->segment, GST_FORMAT_TIME);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = TRUE;
|
||||
break;
|
||||
|
@ -428,6 +452,8 @@ gst_ogg_mux_request_new_pad (GstElement * element,
|
|||
oggpad->map.headers = NULL;
|
||||
oggpad->map.queued = NULL;
|
||||
|
||||
gst_segment_init (&oggpad->segment, GST_FORMAT_TIME);
|
||||
|
||||
oggpad->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
|
||||
gst_pad_set_event_function (newpad,
|
||||
GST_DEBUG_FUNCPTR (gst_ogg_mux_sink_event));
|
||||
|
@ -512,7 +538,8 @@ gst_ogg_mux_buffer_from_page (GstOggMux * mux, ogg_page * page, gboolean delta)
|
|||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_ogg_mux_push_buffer (GstOggMux * mux, GstBuffer * buffer)
|
||||
gst_ogg_mux_push_buffer (GstOggMux * mux, GstBuffer * buffer,
|
||||
GstOggPadData * oggpad)
|
||||
{
|
||||
GstCaps *caps;
|
||||
|
||||
|
@ -523,11 +550,11 @@ gst_ogg_mux_push_buffer (GstOggMux * mux, GstBuffer * buffer)
|
|||
|
||||
/* Ensure we have monotonically increasing timestamps in the output. */
|
||||
if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
|
||||
if (mux->last_ts != GST_CLOCK_TIME_NONE &&
|
||||
GST_BUFFER_TIMESTAMP (buffer) < mux->last_ts)
|
||||
gint64 run_time = GST_BUFFER_RUNNING_TIME (buffer, oggpad);
|
||||
if (mux->last_ts != GST_CLOCK_TIME_NONE && run_time < mux->last_ts)
|
||||
GST_BUFFER_TIMESTAMP (buffer) = mux->last_ts;
|
||||
else
|
||||
mux->last_ts = GST_BUFFER_TIMESTAMP (buffer);
|
||||
mux->last_ts = run_time;
|
||||
}
|
||||
|
||||
caps = gst_pad_get_negotiated_caps (mux->srcpad);
|
||||
|
@ -602,7 +629,7 @@ gst_ogg_mux_dequeue_page (GstOggMux * mux, GstFlowReturn * flowret)
|
|||
while (buf && GST_BUFFER_OFFSET_END (buf) == -1) {
|
||||
GST_LOG_OBJECT (pad->collect.pad, "[gp -1] pushing page");
|
||||
g_queue_pop_head (pad->pagebuffers);
|
||||
*flowret = gst_ogg_mux_push_buffer (mux, buf);
|
||||
*flowret = gst_ogg_mux_push_buffer (mux, buf, pad);
|
||||
buf = g_queue_peek_head (pad->pagebuffers);
|
||||
ret = TRUE;
|
||||
}
|
||||
|
@ -636,7 +663,7 @@ gst_ogg_mux_dequeue_page (GstOggMux * mux, GstFlowReturn * flowret)
|
|||
GST_GP_FORMAT " pushing oldest page buffer %p (granulepos time %"
|
||||
GST_TIME_FORMAT ")", GST_BUFFER_OFFSET_END (buf), buf,
|
||||
GST_TIME_ARGS (GST_BUFFER_OFFSET (buf)));
|
||||
*flowret = gst_ogg_mux_push_buffer (mux, buf);
|
||||
*flowret = gst_ogg_mux_push_buffer (mux, buf, opad);
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
|
@ -727,6 +754,11 @@ gst_ogg_mux_compare_pads (GstOggMux * ogg_mux, GstOggPadData * first,
|
|||
if (secondtime == GST_CLOCK_TIME_NONE)
|
||||
return 1;
|
||||
|
||||
firsttime = gst_segment_to_running_time (&first->segment, GST_FORMAT_TIME,
|
||||
firsttime);
|
||||
secondtime = gst_segment_to_running_time (&second->segment, GST_FORMAT_TIME,
|
||||
secondtime);
|
||||
|
||||
/* first buffer has higher timestamp, second one should go first */
|
||||
if (secondtime < firsttime)
|
||||
return 1;
|
||||
|
@ -1173,7 +1205,7 @@ gst_ogg_mux_send_headers (GstOggMux * mux)
|
|||
if (hwalk == NULL) {
|
||||
GST_LOG_OBJECT (mux,
|
||||
"flushing page as packet %" G_GUINT64_FORMAT " is first or "
|
||||
"last packet", packet.packetno);
|
||||
"last packet", (guint64) packet.packetno);
|
||||
while (ogg_stream_flush (&pad->map.stream, &page)) {
|
||||
GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE);
|
||||
|
||||
|
@ -1209,7 +1241,7 @@ gst_ogg_mux_send_headers (GstOggMux * mux)
|
|||
|
||||
hbufs = g_list_delete_link (hbufs, hbufs);
|
||||
|
||||
if ((ret = gst_ogg_mux_push_buffer (mux, buf)) != GST_FLOW_OK)
|
||||
if ((ret = gst_ogg_mux_push_buffer (mux, buf, NULL)) != GST_FLOW_OK)
|
||||
break;
|
||||
}
|
||||
/* free any remaining nodes/buffers in case we couldn't push them */
|
||||
|
@ -1685,6 +1717,8 @@ gst_ogg_mux_init_collectpads (GstCollectPads * collect)
|
|||
oggpad->data_pushed = FALSE;
|
||||
oggpad->pagebuffers = g_queue_new ();
|
||||
|
||||
gst_segment_init (&oggpad->segment, GST_FORMAT_TIME);
|
||||
|
||||
walk = g_slist_next (walk);
|
||||
}
|
||||
}
|
||||
|
@ -1715,6 +1749,8 @@ gst_ogg_mux_clear_collectpads (GstCollectPads * collect)
|
|||
gst_buffer_unref (oggpad->next_buffer);
|
||||
oggpad->next_buffer = NULL;
|
||||
}
|
||||
|
||||
gst_segment_init (&oggpad->segment, GST_FORMAT_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@ typedef struct
|
|||
GstOggStream map;
|
||||
gboolean have_type;
|
||||
|
||||
GstSegment segment;
|
||||
|
||||
/* These two buffers make a very simple queue - they enter as 'next_buffer'
|
||||
* and (usually) leave as 'buffer', except at EOS, when buffer will be NULL */
|
||||
GstBuffer *buffer; /* the first waiting buffer for the pad */
|
||||
|
|
|
@ -143,6 +143,13 @@ GST_DEBUG_CATEGORY (pango_debug);
|
|||
ret = (v0 * alpha + v1 * (255 - alpha)) / 255; \
|
||||
}
|
||||
|
||||
#define OVER(ret, alphaA, Ca, alphaB, Cb, alphaNew) \
|
||||
{ \
|
||||
gint _tmp; \
|
||||
_tmp = (Ca * alphaA + Cb * alphaB * (255 - alphaA) / 255) / alphaNew; \
|
||||
ret = CLAMP (_tmp, 0, 255); \
|
||||
}
|
||||
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
# define CAIRO_ARGB_A 3
|
||||
# define CAIRO_ARGB_R 2
|
||||
|
@ -186,7 +193,13 @@ static GstStaticPadTemplate src_template_factory =
|
|||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx ";"
|
||||
GST_VIDEO_CAPS_RGBx ";"
|
||||
GST_VIDEO_CAPS_xRGB ";"
|
||||
GST_VIDEO_CAPS_xBGR ";"
|
||||
GST_VIDEO_CAPS_RGBA ";"
|
||||
GST_VIDEO_CAPS_BGRA ";"
|
||||
GST_VIDEO_CAPS_ARGB ";"
|
||||
GST_VIDEO_CAPS_ABGR ";"
|
||||
GST_VIDEO_CAPS_YUV ("{AYUV, I420, UYVY, NV12, NV21}"))
|
||||
);
|
||||
|
||||
|
@ -195,7 +208,13 @@ static GstStaticPadTemplate video_sink_template_factory =
|
|||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx ";"
|
||||
GST_VIDEO_CAPS_RGBx ";"
|
||||
GST_VIDEO_CAPS_xRGB ";"
|
||||
GST_VIDEO_CAPS_xBGR ";"
|
||||
GST_VIDEO_CAPS_RGBA ";"
|
||||
GST_VIDEO_CAPS_BGRA ";"
|
||||
GST_VIDEO_CAPS_ARGB ";"
|
||||
GST_VIDEO_CAPS_ABGR ";"
|
||||
GST_VIDEO_CAPS_YUV ("{AYUV, I420, UYVY, NV12, NV21}"))
|
||||
);
|
||||
|
||||
|
@ -1439,6 +1458,8 @@ gst_text_overlay_shade_packed_Y (GstTextOverlay * overlay, guchar * dest,
|
|||
}
|
||||
|
||||
#define gst_text_overlay_shade_BGRx gst_text_overlay_shade_xRGB
|
||||
#define gst_text_overlay_shade_RGBx gst_text_overlay_shade_xRGB
|
||||
#define gst_text_overlay_shade_xBGR gst_text_overlay_shade_xRGB
|
||||
static inline void
|
||||
gst_text_overlay_shade_xRGB (GstTextOverlay * overlay, guchar * dest,
|
||||
gint x0, gint x1, gint y0, gint y1)
|
||||
|
@ -1464,6 +1485,36 @@ gst_text_overlay_shade_xRGB (GstTextOverlay * overlay, guchar * dest,
|
|||
}
|
||||
}
|
||||
|
||||
#define ARGB_SHADE_FUNCTION(name, OFFSET) \
|
||||
static inline void \
|
||||
gst_text_overlay_shade_##name (GstTextOverlay * overlay, guchar * dest, \
|
||||
gint x0, gint x1, gint y0, gint y1) \
|
||||
{ \
|
||||
gint i, j;\
|
||||
\
|
||||
x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);\
|
||||
x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);\
|
||||
\
|
||||
y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);\
|
||||
y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);\
|
||||
\
|
||||
for (i = y0; i < y1; i++) {\
|
||||
for (j = x0; j < x1; j++) {\
|
||||
gint y, y_pos, k;\
|
||||
y_pos = (i * 4 * overlay->width) + j * 4;\
|
||||
for (k = OFFSET; k < 3+OFFSET; k++) {\
|
||||
y = dest[y_pos + k] + overlay->shading_value;\
|
||||
dest[y_pos + k] = CLAMP (y, 0, 255);\
|
||||
}\
|
||||
}\
|
||||
}\
|
||||
}
|
||||
ARGB_SHADE_FUNCTION (ARGB, 1);
|
||||
ARGB_SHADE_FUNCTION (ABGR, 1);
|
||||
ARGB_SHADE_FUNCTION (RGBA, 0);
|
||||
ARGB_SHADE_FUNCTION (BGRA, 0);
|
||||
|
||||
|
||||
/* FIXME:
|
||||
* - use proper strides and offset for I420
|
||||
* - don't draw over the edge of the picture (try a longer
|
||||
|
@ -1617,7 +1668,7 @@ static inline void
|
|||
gst_text_overlay_blit_AYUV (GstTextOverlay * overlay,
|
||||
guint8 * rgb_pixels, gint xpos, gint ypos)
|
||||
{
|
||||
int a, r, g, b;
|
||||
int a, r, g, b, a1;
|
||||
int y, u, v;
|
||||
int i, j;
|
||||
int h, w;
|
||||
|
@ -1649,14 +1700,17 @@ gst_text_overlay_blit_AYUV (GstTextOverlay * overlay,
|
|||
|
||||
CAIRO_UNPREMULTIPLY (a, r, g, b);
|
||||
|
||||
// convert background to yuv
|
||||
COMP_Y (y, r, g, b);
|
||||
COMP_U (u, r, g, b);
|
||||
COMP_V (v, r, g, b);
|
||||
|
||||
a = (a * dest[0] + 128) >> 8;
|
||||
BLEND (dest[1], a, y, dest[1]);
|
||||
BLEND (dest[2], a, u, dest[2]);
|
||||
BLEND (dest[3], a, v, dest[3]);
|
||||
// preform text "OVER" background alpha compositing
|
||||
a1 = a + (dest[0] * (255 - a)) / 255 + 1; // add 1 to prevent divide by 0
|
||||
OVER (dest[1], a, y, dest[0], dest[1], a1);
|
||||
OVER (dest[2], a, u, dest[0], dest[2], a1);
|
||||
OVER (dest[3], a, v, dest[0], dest[3], a1);
|
||||
dest[0] = a1 - 1; // remove the temporary 1 we added
|
||||
|
||||
pimage += 4;
|
||||
dest += 4;
|
||||
|
@ -1712,6 +1766,57 @@ gst_text_overlay_blit_##name (GstTextOverlay * overlay, \
|
|||
}
|
||||
xRGB_BLIT_FUNCTION (xRGB, 1, 2, 3);
|
||||
xRGB_BLIT_FUNCTION (BGRx, 2, 1, 0);
|
||||
xRGB_BLIT_FUNCTION (xBGR, 3, 2, 1);
|
||||
xRGB_BLIT_FUNCTION (RGBx, 0, 1, 2);
|
||||
|
||||
#define ARGB_BLIT_FUNCTION(name, A, R, G, B) \
|
||||
static inline void \
|
||||
gst_text_overlay_blit_##name (GstTextOverlay * overlay, \
|
||||
guint8 * rgb_pixels, gint xpos, gint ypos) \
|
||||
{ \
|
||||
int a, r, g, b, a1; \
|
||||
int i, j; \
|
||||
int h, w; \
|
||||
guchar *pimage, *dest; \
|
||||
\
|
||||
w = overlay->image_width; \
|
||||
h = overlay->image_height; \
|
||||
\
|
||||
if (xpos < 0) { \
|
||||
xpos = 0; \
|
||||
} \
|
||||
\
|
||||
if (xpos + w > overlay->width) { \
|
||||
w = overlay->width - xpos; \
|
||||
} \
|
||||
\
|
||||
if (ypos + h > overlay->height) { \
|
||||
h = overlay->height - ypos; \
|
||||
} \
|
||||
\
|
||||
for (i = 0; i < h; i++) { \
|
||||
pimage = overlay->text_image + i * overlay->image_width * 4; \
|
||||
dest = rgb_pixels + (i + ypos) * 4 * overlay->width + xpos * 4; \
|
||||
for (j = 0; j < w; j++) { \
|
||||
a = pimage[CAIRO_ARGB_A]; \
|
||||
b = pimage[CAIRO_ARGB_B]; \
|
||||
g = pimage[CAIRO_ARGB_G]; \
|
||||
r = pimage[CAIRO_ARGB_R]; \
|
||||
CAIRO_UNPREMULTIPLY (a, r, g, b); \
|
||||
a1 = a + (dest[A] * (255 - a)) / 255 + 1; \
|
||||
OVER (dest[R], a, r, dest[0], dest[R], a1); \
|
||||
OVER (dest[G], a, g, dest[0], dest[G], a1); \
|
||||
OVER (dest[B], a, b, dest[0], dest[B], a1); \
|
||||
dest[A] = a1 - 1; \
|
||||
pimage += 4; \
|
||||
dest += 4; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
ARGB_BLIT_FUNCTION (RGBA, 3, 0, 1, 2);
|
||||
ARGB_BLIT_FUNCTION (BGRA, 3, 2, 1, 0);
|
||||
ARGB_BLIT_FUNCTION (ARGB, 0, 1, 2, 3);
|
||||
ARGB_BLIT_FUNCTION (ABGR, 0, 3, 2, 1);
|
||||
|
||||
static void
|
||||
gst_text_overlay_render_text (GstTextOverlay * overlay,
|
||||
|
@ -1839,11 +1944,41 @@ gst_text_overlay_push_frame (GstTextOverlay * overlay, GstBuffer * video_frame)
|
|||
xpos, xpos + overlay->image_width,
|
||||
ypos, ypos + overlay->image_height);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_xBGR:
|
||||
gst_text_overlay_shade_xBGR (overlay,
|
||||
GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
|
||||
ypos, ypos + overlay->image_height);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_BGRx:
|
||||
gst_text_overlay_shade_BGRx (overlay, data,
|
||||
xpos, xpos + overlay->image_width,
|
||||
ypos, ypos + overlay->image_height);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGBx:
|
||||
gst_text_overlay_shade_RGBx (overlay,
|
||||
GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
|
||||
ypos, ypos + overlay->image_height);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_ARGB:
|
||||
gst_text_overlay_shade_ARGB (overlay,
|
||||
GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
|
||||
ypos, ypos + overlay->image_height);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_ABGR:
|
||||
gst_text_overlay_shade_ABGR (overlay,
|
||||
GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
|
||||
ypos, ypos + overlay->image_height);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGBA:
|
||||
gst_text_overlay_shade_RGBA (overlay,
|
||||
GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
|
||||
ypos, ypos + overlay->image_height);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_BGRA:
|
||||
gst_text_overlay_shade_BGRA (overlay,
|
||||
GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
|
||||
ypos, ypos + overlay->image_height);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
@ -1873,6 +2008,30 @@ gst_text_overlay_push_frame (GstTextOverlay * overlay, GstBuffer * video_frame)
|
|||
case GST_VIDEO_FORMAT_xRGB:
|
||||
gst_text_overlay_blit_xRGB (overlay, data, xpos, ypos);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGBx:
|
||||
gst_text_overlay_blit_RGBx (overlay,
|
||||
GST_BUFFER_DATA (video_frame), xpos, ypos);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_xBGR:
|
||||
gst_text_overlay_blit_xBGR (overlay,
|
||||
GST_BUFFER_DATA (video_frame), xpos, ypos);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_ARGB:
|
||||
gst_text_overlay_blit_ARGB (overlay,
|
||||
GST_BUFFER_DATA (video_frame), xpos, ypos);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_ABGR:
|
||||
gst_text_overlay_blit_ABGR (overlay,
|
||||
GST_BUFFER_DATA (video_frame), xpos, ypos);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGBA:
|
||||
gst_text_overlay_blit_RGBA (overlay,
|
||||
GST_BUFFER_DATA (video_frame), xpos, ypos);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_BGRA:
|
||||
gst_text_overlay_blit_BGRA (overlay,
|
||||
GST_BUFFER_DATA (video_frame), xpos, ypos);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
|
|
@ -1326,6 +1326,57 @@ flushing:
|
|||
}
|
||||
}
|
||||
|
||||
static gint64
|
||||
gst_base_audio_sink_get_alignment (GstBaseAudioSink * sink,
|
||||
GstClockTime sample_offset)
|
||||
{
|
||||
GstRingBuffer *ringbuf = sink->ringbuffer;
|
||||
gint64 align;
|
||||
gint64 diff;
|
||||
gint64 maxdrift;
|
||||
gint segdone = g_atomic_int_get (&ringbuf->segdone) - ringbuf->segbase;
|
||||
gint64 samples_done = segdone * ringbuf->samples_per_seg;
|
||||
gint64 headroom = sample_offset - samples_done;
|
||||
gboolean allow_align = TRUE;
|
||||
|
||||
/* now try to align the sample to the previous one, first see how big the
|
||||
* difference is. */
|
||||
if (sample_offset >= sink->next_sample)
|
||||
diff = sample_offset - sink->next_sample;
|
||||
else
|
||||
diff = sink->next_sample - sample_offset;
|
||||
|
||||
/* calculate the max allowed drift in units of samples. By default this is
|
||||
* 20ms and should be anough to compensate for timestamp rounding errors. */
|
||||
maxdrift = (ringbuf->spec.rate * sink->priv->drift_tolerance) / GST_MSECOND;
|
||||
|
||||
/* calc align with previous sample */
|
||||
align = sink->next_sample - sample_offset;
|
||||
|
||||
/* don't align if it means writing behind the read-segment */
|
||||
if (diff > headroom && align < 0)
|
||||
allow_align = FALSE;
|
||||
|
||||
if (G_LIKELY (diff < maxdrift && allow_align)) {
|
||||
GST_DEBUG_OBJECT (sink,
|
||||
"align with prev sample, ABS (%" G_GINT64_FORMAT ") < %"
|
||||
G_GINT64_FORMAT, align, maxdrift);
|
||||
} else {
|
||||
/* calculate sample diff in seconds for error message */
|
||||
gint64 diff_s =
|
||||
gst_util_uint64_scale_int (diff, GST_SECOND, ringbuf->spec.rate);
|
||||
/* timestamps drifted apart from previous samples too much, we need to
|
||||
* resync. We log this as an element warning. */
|
||||
GST_WARNING_OBJECT (sink,
|
||||
"Unexpected discontinuity in audio timestamps of "
|
||||
"%s%" GST_TIME_FORMAT ", resyncing",
|
||||
sample_offset > sink->next_sample ? "+" : "-", GST_TIME_ARGS (diff_s));
|
||||
align = 0;
|
||||
}
|
||||
|
||||
return align;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
||||
{
|
||||
|
@ -1348,7 +1399,6 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
|||
GstFlowReturn ret;
|
||||
GstSegment clip_seg;
|
||||
gint64 time_offset;
|
||||
gint64 maxdrift;
|
||||
|
||||
sink = GST_BASE_AUDIO_SINK (bsink);
|
||||
|
||||
|
@ -1582,29 +1632,7 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
|||
goto no_align;
|
||||
}
|
||||
|
||||
/* now try to align the sample to the previous one, first see how big the
|
||||
* difference is. */
|
||||
if (sample_offset >= sink->next_sample)
|
||||
diff = sample_offset - sink->next_sample;
|
||||
else
|
||||
diff = sink->next_sample - sample_offset;
|
||||
|
||||
/* calculate the max allowed drift in units of samples. By default this is
|
||||
* 20ms and should be anough to compensate for timestamp rounding errors. */
|
||||
maxdrift = (ringbuf->spec.rate * sink->priv->drift_tolerance) / GST_MSECOND;
|
||||
|
||||
if (G_LIKELY (diff < maxdrift)) {
|
||||
/* calc align with previous sample */
|
||||
align = sink->next_sample - sample_offset;
|
||||
GST_DEBUG_OBJECT (sink,
|
||||
"align with prev sample, ABS (%" G_GINT64_FORMAT ") < %"
|
||||
G_GINT64_FORMAT, align, maxdrift);
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (sink,
|
||||
"discont timestamp (%" G_GINT64_FORMAT ") >= %" G_GINT64_FORMAT, diff,
|
||||
maxdrift);
|
||||
align = 0;
|
||||
}
|
||||
align = gst_base_audio_sink_get_alignment (sink, sample_offset);
|
||||
sink->priv->last_align = align;
|
||||
|
||||
/* apply alignment */
|
||||
|
|
|
@ -560,14 +560,19 @@ gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
|
|||
spec->buffer_time = src->buffer_time;
|
||||
spec->latency_time = src->latency_time;
|
||||
|
||||
if (!gst_ring_buffer_parse_caps (spec, caps))
|
||||
GST_OBJECT_LOCK (src);
|
||||
if (!gst_ring_buffer_parse_caps (spec, caps)) {
|
||||
GST_OBJECT_UNLOCK (src);
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
/* calculate suggested segsize and segtotal */
|
||||
spec->segsize =
|
||||
spec->rate * spec->bytes_per_sample * spec->latency_time / GST_MSECOND;
|
||||
spec->segtotal = spec->buffer_time / spec->latency_time;
|
||||
|
||||
GST_OBJECT_UNLOCK (src);
|
||||
|
||||
GST_DEBUG ("release old ringbuffer");
|
||||
|
||||
gst_ring_buffer_release (src->ringbuffer);
|
||||
|
@ -628,9 +633,12 @@ gst_base_audio_src_query (GstBaseSrc * bsrc, GstQuery * query)
|
|||
GstClockTime min_latency, max_latency;
|
||||
GstRingBufferSpec *spec;
|
||||
|
||||
GST_OBJECT_LOCK (src);
|
||||
if (G_UNLIKELY (src->ringbuffer == NULL
|
||||
|| src->ringbuffer->spec.rate == 0))
|
||||
|| src->ringbuffer->spec.rate == 0)) {
|
||||
GST_OBJECT_UNLOCK (src);
|
||||
goto done;
|
||||
}
|
||||
|
||||
spec = &src->ringbuffer->spec;
|
||||
|
||||
|
@ -642,6 +650,7 @@ gst_base_audio_src_query (GstBaseSrc * bsrc, GstQuery * query)
|
|||
max_latency =
|
||||
gst_util_uint64_scale_int (spec->segtotal * spec->segsize, GST_SECOND,
|
||||
spec->rate * spec->bytes_per_sample);
|
||||
GST_OBJECT_UNLOCK (src);
|
||||
|
||||
GST_DEBUG_OBJECT (src,
|
||||
"report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
|
||||
|
|
|
@ -161,7 +161,7 @@ gst_rtcp_buffer_validate_data (guint8 * data, guint len)
|
|||
goto wrong_length;
|
||||
|
||||
/* get padding */
|
||||
pad_bytes = data[len - 1];
|
||||
pad_bytes = data[data_len - 1];
|
||||
if (data_len != pad_bytes)
|
||||
goto wrong_padding;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
#include <gst/gsttagsetter.h>
|
||||
#include <gst/base/gstbytereader.h>
|
||||
#include <gst/base/gstbytewriter.h>
|
||||
#include "gsttageditingprivate.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -313,28 +315,20 @@ gst_vorbis_tag_add_coverart (GstTagList * tags, gchar * img_data_base64,
|
|||
{
|
||||
GstBuffer *img;
|
||||
gsize img_len;
|
||||
guchar *out;
|
||||
guint save = 0;
|
||||
gint state = 0;
|
||||
|
||||
if (base64_len < 2)
|
||||
goto not_enough_data;
|
||||
|
||||
/* img_data_base64 points to a temporary copy of the base64 encoded data, so
|
||||
* it's safe to do inpace decoding here
|
||||
* TODO: glib 2.20 and later provides g_base64_decode_inplace, so change this
|
||||
* to use glib's API instead once it's in wider use:
|
||||
* http://bugzilla.gnome.org/show_bug.cgi?id=564728
|
||||
* http://svn.gnome.org/viewvc/glib?view=revision&revision=7807 */
|
||||
out = (guchar *) img_data_base64;
|
||||
img_len = g_base64_decode_step (img_data_base64, base64_len,
|
||||
out, &state, &save);
|
||||
|
||||
*/
|
||||
g_base64_decode_inplace (img_data_base64, &img_len);
|
||||
if (img_len == 0)
|
||||
goto decode_failed;
|
||||
|
||||
img = gst_tag_image_data_to_image_buffer (out, img_len,
|
||||
GST_TAG_IMAGE_TYPE_NONE);
|
||||
img =
|
||||
gst_tag_image_data_to_image_buffer ((const guint8 *) img_data_base64,
|
||||
img_len, GST_TAG_IMAGE_TYPE_NONE);
|
||||
|
||||
if (img == NULL)
|
||||
goto convert_failed;
|
||||
|
@ -363,6 +357,65 @@ convert_failed:
|
|||
}
|
||||
}
|
||||
|
||||
/* Standardized way of adding pictures to vorbiscomments:
|
||||
* http://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE
|
||||
*/
|
||||
static void
|
||||
gst_vorbis_tag_add_metadata_block_picture (GstTagList * tags,
|
||||
gchar * value, gint value_len)
|
||||
{
|
||||
GstByteReader reader;
|
||||
guint32 img_len = 0, img_type = 0;
|
||||
guint32 img_mimetype_len = 0, img_description_len = 0;
|
||||
gsize decoded_len;
|
||||
const guint8 *data;
|
||||
|
||||
/* img_data_base64 points to a temporary copy of the base64 encoded data, so
|
||||
* it's safe to do inpace decoding here
|
||||
*/
|
||||
g_base64_decode_inplace (value, &decoded_len);
|
||||
if (decoded_len == 0)
|
||||
goto decode_failed;
|
||||
|
||||
gst_byte_reader_init (&reader, (guint8 *) value, decoded_len);
|
||||
|
||||
if (!gst_byte_reader_get_uint32_be (&reader, &img_type))
|
||||
goto error;
|
||||
|
||||
if (!gst_byte_reader_get_uint32_be (&reader, &img_mimetype_len))
|
||||
goto error;
|
||||
if (!gst_byte_reader_skip (&reader, img_mimetype_len))
|
||||
goto error;
|
||||
|
||||
if (!gst_byte_reader_get_uint32_be (&reader, &img_description_len))
|
||||
goto error;
|
||||
if (!gst_byte_reader_skip (&reader, img_description_len))
|
||||
goto error;
|
||||
|
||||
/* Skip width, height, color depth and number of colors for
|
||||
* indexed formats */
|
||||
if (!gst_byte_reader_skip (&reader, 4 * 4))
|
||||
goto error;
|
||||
|
||||
if (!gst_byte_reader_get_uint32_be (&reader, &img_len))
|
||||
goto error;
|
||||
|
||||
if (!gst_byte_reader_get_data (&reader, img_len, &data))
|
||||
goto error;
|
||||
|
||||
gst_tag_list_add_id3_image (tags, data, img_len, img_type);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
GST_WARNING
|
||||
("Couldn't extract image or image type from METADATA_BLOCK_PICTURE tag");
|
||||
return;
|
||||
decode_failed:
|
||||
GST_WARNING ("Failed to decode Base64 data from METADATA_BLOCK_PICTURE tag");
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_tag_list_from_vorbiscomment:
|
||||
* @data: data to convert
|
||||
|
@ -439,6 +492,8 @@ gst_tag_list_from_vorbiscomment (const guint8 * data, gsize size,
|
|||
continue;
|
||||
} else if (g_ascii_strcasecmp (cur, "COVERART") == 0) {
|
||||
gst_vorbis_tag_add_coverart (list, value, value_len);
|
||||
} else if (g_ascii_strcasecmp (cur, "METADATA_BLOCK_PICTURE") == 0) {
|
||||
gst_vorbis_tag_add_metadata_block_picture (list, value, value_len);
|
||||
} else {
|
||||
gst_vorbis_tag_add (list, cur, value);
|
||||
}
|
||||
|
@ -493,38 +548,79 @@ typedef struct
|
|||
MyForEach;
|
||||
|
||||
static GList *
|
||||
gst_tag_to_coverart (const GValue * image_value)
|
||||
gst_tag_to_metadata_block_picture (const gchar * tag,
|
||||
const GValue * image_value)
|
||||
{
|
||||
gchar *coverart_data, *data_result, *mime_result;
|
||||
gchar *comment_data, *data_result;
|
||||
const gchar *mime_type;
|
||||
guint mime_type_len;
|
||||
GstStructure *mime_struct;
|
||||
GstBuffer *buffer;
|
||||
GList *l = NULL;
|
||||
guint8 *data;
|
||||
gsize size;
|
||||
GstByteWriter writer;
|
||||
GstTagImageType image_type = GST_TAG_IMAGE_TYPE_NONE;
|
||||
gint width = 0, height = 0;
|
||||
guint8 *metadata_block;
|
||||
guint metadata_block_len;
|
||||
|
||||
g_return_val_if_fail (image_value != NULL, NULL);
|
||||
|
||||
buffer = gst_value_get_buffer (image_value);
|
||||
g_return_val_if_fail (gst_caps_is_fixed (buffer->caps), NULL);
|
||||
mime_struct = gst_caps_get_structure (buffer->caps, 0);
|
||||
|
||||
mime_type = gst_structure_get_name (mime_struct);
|
||||
if (strcmp (mime_type, "text/uri-list") == 0)
|
||||
mime_type = "-->";
|
||||
mime_type_len = strlen (mime_type);
|
||||
|
||||
gst_structure_get (mime_struct, "image-type", GST_TYPE_TAG_IMAGE_TYPE,
|
||||
&image_type, "width", G_TYPE_INT, &width, "height", G_TYPE_INT, &height,
|
||||
NULL);
|
||||
|
||||
metadata_block_len = 32 + mime_type_len + GST_BUFFER_SIZE (buffer);
|
||||
gst_byte_writer_init_with_size (&writer, metadata_block_len, TRUE);
|
||||
|
||||
if (image_type == GST_TAG_IMAGE_TYPE_NONE
|
||||
&& strcmp (tag, GST_TAG_PREVIEW_IMAGE) == 0) {
|
||||
gst_byte_writer_put_uint32_be_unchecked (&writer, 0x01);
|
||||
} else {
|
||||
/* Convert to ID3v2 APIC image type */
|
||||
if (image_type == GST_TAG_IMAGE_TYPE_NONE)
|
||||
image_type = GST_TAG_IMAGE_TYPE_UNDEFINED;
|
||||
else
|
||||
image_type = image_type + 2;
|
||||
gst_byte_writer_put_uint32_be_unchecked (&writer, image_type);
|
||||
}
|
||||
|
||||
gst_byte_writer_put_uint32_be_unchecked (&writer, mime_type_len);
|
||||
gst_byte_writer_put_data_unchecked (&writer, (guint8 *) mime_type,
|
||||
mime_type_len);
|
||||
/* description length */
|
||||
gst_byte_writer_put_uint32_be_unchecked (&writer, 0);
|
||||
gst_byte_writer_put_uint32_be_unchecked (&writer, width);
|
||||
gst_byte_writer_put_uint32_be_unchecked (&writer, height);
|
||||
/* color depth */
|
||||
gst_byte_writer_put_uint32_be_unchecked (&writer, 0);
|
||||
/* for indexed formats the number of colors */
|
||||
gst_byte_writer_put_uint32_be_unchecked (&writer, 0);
|
||||
|
||||
data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
|
||||
if (strcmp (mime_type, "text/uri-list") == 0) {
|
||||
/* URI reference */
|
||||
coverart_data = g_strndup ((gchar *) data, size);
|
||||
} else {
|
||||
coverart_data = g_base64_encode (data, size);
|
||||
}
|
||||
gst_byte_writer_put_uint32_be_unchecked (&writer, size);
|
||||
gst_byte_writer_put_data_unchecked (&writer, data, size);
|
||||
gst_buffer_unmap (buffer, data, size);
|
||||
|
||||
data_result = g_strdup_printf ("COVERART=%s", coverart_data);
|
||||
mime_result = g_strdup_printf ("COVERARTMIME=%s", mime_type);
|
||||
g_free (coverart_data);
|
||||
g_assert (gst_byte_writer_get_pos (&writer) == metadata_block_len);
|
||||
|
||||
metadata_block = gst_byte_writer_reset_and_get_data (&writer);
|
||||
comment_data = g_base64_encode (metadata_block, metadata_block_len);
|
||||
g_free (metadata_block);
|
||||
data_result = g_strdup_printf ("METADATA_BLOCK_PICTURE=%s", comment_data);
|
||||
g_free (comment_data);
|
||||
|
||||
l = g_list_append (l, data_result);
|
||||
l = g_list_append (l, mime_result);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
@ -559,7 +655,8 @@ gst_tag_to_vorbis_comments (const GstTagList * list, const gchar * tag)
|
|||
if ((strcmp (tag, GST_TAG_PREVIEW_IMAGE) == 0 &&
|
||||
gst_tag_list_get_tag_size (list, GST_TAG_IMAGE) == 0) ||
|
||||
strcmp (tag, GST_TAG_IMAGE) == 0) {
|
||||
return gst_tag_to_coverart (gst_tag_list_get_value_index (list, tag, 0));
|
||||
return gst_tag_to_metadata_block_picture (tag,
|
||||
gst_tag_list_get_value_index (list, tag, 0));
|
||||
}
|
||||
|
||||
if (strcmp (tag, GST_TAG_EXTENDED_COMMENT) != 0) {
|
||||
|
|
|
@ -1926,9 +1926,9 @@ gst_video_format_get_component_offset (GstVideoFormat format,
|
|||
if (component == 0)
|
||||
return 0;
|
||||
if (component == 1)
|
||||
return GST_ROUND_UP_4 (width) * GST_ROUND_UP_2 (height);
|
||||
return GST_ROUND_UP_4 (width) * height;
|
||||
if (component == 2) {
|
||||
return GST_ROUND_UP_4 (width) * GST_ROUND_UP_2 (height) +
|
||||
return GST_ROUND_UP_4 (width) * height +
|
||||
GST_ROUND_UP_4 (GST_ROUND_UP_4 (width) / 4) *
|
||||
(GST_ROUND_UP_4 (height) / 4);
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@ glib_gen_basename = gstencode
|
|||
built_sources = gstencode-marshal.c
|
||||
built_headers = gstencode-marshal.h
|
||||
|
||||
plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
|
||||
|
||||
plugin_LTLIBRARIES = libgstencodebin.la
|
||||
|
||||
libgstencodebin_la_SOURCES = \
|
||||
|
|
|
@ -6,8 +6,6 @@ glib_gen_basename = gstplay
|
|||
built_sources = gstplay-marshal.c
|
||||
built_headers = gstplay-marshal.h
|
||||
|
||||
plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
|
||||
|
||||
plugin_LTLIBRARIES = libgstplaybin.la libgstdecodebin.la libgstdecodebin2.la
|
||||
|
||||
libgstplaybin_la_SOURCES = \
|
||||
|
|
|
@ -424,14 +424,6 @@ GST_START_TEST (test_video_formats)
|
|||
off1 = gst_video_format_get_component_offset (fmt, 1, w, h);
|
||||
off2 = gst_video_format_get_component_offset (fmt, 2, w, h);
|
||||
|
||||
/* FIXME: for YUV9/YVU9 old videotestsrc code disagrees with new code
|
||||
* - figure out which is right */
|
||||
if (fmt == GST_VIDEO_FORMAT_YUV9 || fmt == GST_VIDEO_FORMAT_YVU9) {
|
||||
if (w == 1 && h == 1)
|
||||
GST_ERROR ("FIXME: fix GST_VIDEO_FORMAT_YUV9/YVU9 size checks");
|
||||
goto skip_check;
|
||||
}
|
||||
|
||||
fail_unless_equals_int (size, (unsigned long) paintinfo.endptr);
|
||||
fail_unless_equals_int (off0, (unsigned long) paintinfo.yp);
|
||||
fail_unless_equals_int (off1, (unsigned long) paintinfo.up);
|
||||
|
|
Loading…
Reference in a new issue