Merge branch 'master' into 0.11

Conflicts:
	gst-libs/gst/tag/gstvorbistag.c
This commit is contained in:
Wim Taymans 2011-04-04 11:31:33 +02:00
commit da1c863711
11 changed files with 403 additions and 84 deletions

View file

@ -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);
}
}

View file

@ -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 */

View file

@ -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 ();
}

View file

@ -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 */

View file

@ -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,

View file

@ -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;
}

View file

@ -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) {

View file

@ -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);
}

View file

@ -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 = \

View file

@ -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 = \

View file

@ -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);