mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 11:45:25 +00:00
Merge branch 'master' into 0.11
Conflicts: ext/flac/gstflacdec.c gst/audioparsers/gstflacparse.c gst/isomp4/qtdemux.c
This commit is contained in:
commit
95f3987332
9 changed files with 496 additions and 10 deletions
|
@ -65,12 +65,14 @@ enum
|
||||||
ARG_YPAD,
|
ARG_YPAD,
|
||||||
ARG_DELTAX,
|
ARG_DELTAX,
|
||||||
ARG_DELTAY,
|
ARG_DELTAY,
|
||||||
|
ARG_SILENT,
|
||||||
ARG_FONT_DESC
|
ARG_FONT_DESC
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFAULT_YPAD 25
|
#define DEFAULT_YPAD 25
|
||||||
#define DEFAULT_XPAD 25
|
#define DEFAULT_XPAD 25
|
||||||
#define DEFAULT_FONT "sans"
|
#define DEFAULT_FONT "sans"
|
||||||
|
#define DEFAULT_SILENT FALSE
|
||||||
|
|
||||||
#define GST_CAIRO_TEXT_OVERLAY_DEFAULT_SCALE 20.0
|
#define GST_CAIRO_TEXT_OVERLAY_DEFAULT_SCALE 20.0
|
||||||
|
|
||||||
|
@ -201,6 +203,11 @@ gst_text_overlay_class_init (GstCairoTextOverlayClass * klass)
|
||||||
"See documentation of "
|
"See documentation of "
|
||||||
"pango_font_description_from_string"
|
"pango_font_description_from_string"
|
||||||
" for syntax.", "", G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
|
" for syntax.", "", G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
|
||||||
|
/* FIXME 0.11: rename to "visible" or "text-visible" or "render-text" */
|
||||||
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
|
||||||
|
g_param_spec_boolean ("silent", "silent",
|
||||||
|
"Whether to render the text string",
|
||||||
|
DEFAULT_SILENT, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -267,6 +274,8 @@ gst_text_overlay_init (GstCairoTextOverlay * overlay,
|
||||||
overlay->font = g_strdup (DEFAULT_FONT);
|
overlay->font = g_strdup (DEFAULT_FONT);
|
||||||
gst_text_overlay_font_init (overlay);
|
gst_text_overlay_font_init (overlay);
|
||||||
|
|
||||||
|
overlay->silent = DEFAULT_SILENT;
|
||||||
|
|
||||||
overlay->fps_n = 0;
|
overlay->fps_n = 0;
|
||||||
overlay->fps_d = 1;
|
overlay->fps_d = 1;
|
||||||
|
|
||||||
|
@ -410,6 +419,9 @@ gst_text_overlay_set_property (GObject * object, guint prop_id,
|
||||||
gst_text_overlay_font_init (overlay);
|
gst_text_overlay_font_init (overlay);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ARG_SILENT:
|
||||||
|
overlay->silent = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
default:{
|
default:{
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -431,6 +443,11 @@ gst_text_overlay_render_text (GstCairoTextOverlay * overlay,
|
||||||
gchar *string;
|
gchar *string;
|
||||||
double x, y;
|
double x, y;
|
||||||
|
|
||||||
|
if (overlay->silent) {
|
||||||
|
GST_DEBUG_OBJECT (overlay, "Silent mode, not rendering");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (textlen < 0)
|
if (textlen < 0)
|
||||||
textlen = strlen (text);
|
textlen = strlen (text);
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,7 @@ struct _GstCairoTextOverlay {
|
||||||
gint slant;
|
gint slant;
|
||||||
gint weight;
|
gint weight;
|
||||||
gdouble scale;
|
gdouble scale;
|
||||||
|
gboolean silent;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstCairoTextOverlayClass {
|
struct _GstCairoTextOverlayClass {
|
||||||
|
|
|
@ -527,6 +527,34 @@ gst_flac_parse_frame_header_is_valid (GstFlacParse * flacparse,
|
||||||
if (actual_crc != expected_crc)
|
if (actual_crc != expected_crc)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The FLAC format documentation says:
|
||||||
|
The "blocking strategy" bit determines how to calculate the sample number
|
||||||
|
of the first sample in the frame. If the bit is 0 (fixed-blocksize), the
|
||||||
|
frame header encodes the frame number as above, and the frame's starting
|
||||||
|
sample number will be the frame number times the blocksize. If it is 1
|
||||||
|
(variable-blocksize), the frame header encodes the frame's starting
|
||||||
|
sample number itself. (In the case of a fixed-blocksize stream, only the
|
||||||
|
last block may be shorter than the stream blocksize; its starting sample
|
||||||
|
number will be calculated as the frame number times the previous frame's
|
||||||
|
blocksize, or zero if it is the first frame).
|
||||||
|
|
||||||
|
Therefore, when in fixed block size mode, we only update the block size
|
||||||
|
the first time, then reuse that block size for subsequent calls.
|
||||||
|
This will also fix a timestamp problem with the last block's timestamp
|
||||||
|
being miscalculated by scaling the block number by a "wrong" block size.
|
||||||
|
*/
|
||||||
|
if (blocking_strategy == 0) {
|
||||||
|
if (flacparse->block_size != 0) {
|
||||||
|
/* after first block */
|
||||||
|
if (flacparse->block_size != block_size) {
|
||||||
|
/* TODO: can we know we're on the last frame, to avoid warning ? */
|
||||||
|
GST_WARNING_OBJECT (flacparse, "Block size is not constant");
|
||||||
|
block_size = flacparse->block_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (set) {
|
if (set) {
|
||||||
flacparse->block_size = block_size;
|
flacparse->block_size = block_size;
|
||||||
if (!flacparse->samplerate)
|
if (!flacparse->samplerate)
|
||||||
|
@ -706,7 +734,6 @@ gst_flac_parse_check_valid_frame (GstBaseParse * parse,
|
||||||
|
|
||||||
flacparse->offset = GST_BUFFER_OFFSET (buffer);
|
flacparse->offset = GST_BUFFER_OFFSET (buffer);
|
||||||
flacparse->blocking_strategy = 0;
|
flacparse->blocking_strategy = 0;
|
||||||
flacparse->block_size = 0;
|
|
||||||
flacparse->sample_number = 0;
|
flacparse->sample_number = 0;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (flacparse, "Found sync code");
|
GST_DEBUG_OBJECT (flacparse, "Found sync code");
|
||||||
|
@ -1404,7 +1431,6 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
|
||||||
|
|
||||||
flacparse->offset = -1;
|
flacparse->offset = -1;
|
||||||
flacparse->blocking_strategy = 0;
|
flacparse->blocking_strategy = 0;
|
||||||
flacparse->block_size = 0;
|
|
||||||
flacparse->sample_number = 0;
|
flacparse->sample_number = 0;
|
||||||
res = GST_FLOW_OK;
|
res = GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ libgstflv_la_LDFLAGS = ${GST_PLUGIN_LDFLAGS}
|
||||||
libgstflv_la_SOURCES = gstflvdemux.c gstflvmux.c
|
libgstflv_la_SOURCES = gstflvdemux.c gstflvmux.c
|
||||||
libgstflv_la_LIBTOOLFLAGS = --tag=disable-static
|
libgstflv_la_LIBTOOLFLAGS = --tag=disable-static
|
||||||
|
|
||||||
noinst_HEADERS = gstflvdemux.h gstflvmux.h
|
noinst_HEADERS = gstflvdemux.h gstflvmux.h amfdefs.h
|
||||||
|
|
||||||
Android.mk: Makefile.am $(BUILT_SOURCES)
|
Android.mk: Makefile.am $(BUILT_SOURCES)
|
||||||
androgenizer \
|
androgenizer \
|
||||||
|
|
|
@ -85,6 +85,9 @@ G_DEFINE_TYPE (GstFlvDemux, gst_flv_demux, GST_TYPE_ELEMENT);
|
||||||
/* 1 byte of tag type + 3 bytes of tag data size */
|
/* 1 byte of tag type + 3 bytes of tag data size */
|
||||||
#define FLV_TAG_TYPE_SIZE 4
|
#define FLV_TAG_TYPE_SIZE 4
|
||||||
|
|
||||||
|
/* two seconds - consider pts are resynced to another base if this different */
|
||||||
|
#define RESYNC_THRESHOLD 2000
|
||||||
|
|
||||||
static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux,
|
static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux,
|
||||||
GstEvent * event);
|
GstEvent * event);
|
||||||
static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux,
|
static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux,
|
||||||
|
@ -775,6 +778,23 @@ gst_flv_demux_push_tags (GstFlvDemux * demux)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 pts, guint32 * last,
|
||||||
|
GstClockTime * offset)
|
||||||
|
{
|
||||||
|
if (ABS (pts - *last) >= RESYNC_THRESHOLD) {
|
||||||
|
/* Theoretically, we should use substract the duration of the last buffer,
|
||||||
|
but this demuxer sends no durations on buffers, not sure if it cannot
|
||||||
|
know, or just does not care to calculate. */
|
||||||
|
gint32 dpts = pts - *last;
|
||||||
|
*offset -= dpts * GST_MSECOND;
|
||||||
|
GST_WARNING_OBJECT (demux,
|
||||||
|
"Large pts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
|
||||||
|
GST_TIME_FORMAT "", dpts, GST_TIME_ARGS (*offset));
|
||||||
|
}
|
||||||
|
*last = pts;
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
|
gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
|
@ -969,8 +989,12 @@ gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* detect (and deem to be resyncs) large pts gaps */
|
||||||
|
gst_flv_demux_update_resync (demux, pts, &demux->last_audio_pts,
|
||||||
|
&demux->audio_time_offset);
|
||||||
|
|
||||||
/* Fill buffer with data */
|
/* Fill buffer with data */
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND;
|
GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
|
||||||
GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
|
GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
|
||||||
GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
|
GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
|
||||||
GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
|
GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
|
||||||
|
@ -1341,8 +1365,12 @@ gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* detect (and deem to be resyncs) large pts gaps */
|
||||||
|
gst_flv_demux_update_resync (demux, pts, &demux->last_video_pts,
|
||||||
|
&demux->video_time_offset);
|
||||||
|
|
||||||
/* Fill buffer with data */
|
/* Fill buffer with data */
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND;
|
GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->video_time_offset;
|
||||||
GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
|
GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
|
||||||
GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
|
GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
|
||||||
GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
|
GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
|
||||||
|
@ -1659,6 +1687,8 @@ gst_flv_demux_cleanup (GstFlvDemux * demux)
|
||||||
demux->index_max_time = 0;
|
demux->index_max_time = 0;
|
||||||
|
|
||||||
demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
|
demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
|
||||||
|
demux->last_audio_pts = demux->last_video_pts = 0;
|
||||||
|
demux->audio_time_offset = demux->video_time_offset = 0;
|
||||||
|
|
||||||
demux->no_more_pads = FALSE;
|
demux->no_more_pads = FALSE;
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,8 @@ struct _GstFlvDemux
|
||||||
gboolean audio_linked;
|
gboolean audio_linked;
|
||||||
GstBuffer * audio_codec_data;
|
GstBuffer * audio_codec_data;
|
||||||
GstClockTime audio_start;
|
GstClockTime audio_start;
|
||||||
|
guint32 last_audio_pts;
|
||||||
|
GstClockTime audio_time_offset;
|
||||||
|
|
||||||
/* Video infos */
|
/* Video infos */
|
||||||
guint32 w;
|
guint32 w;
|
||||||
|
@ -108,6 +110,8 @@ struct _GstFlvDemux
|
||||||
gboolean got_par;
|
gboolean got_par;
|
||||||
GstBuffer * video_codec_data;
|
GstBuffer * video_codec_data;
|
||||||
GstClockTime video_start;
|
GstClockTime video_start;
|
||||||
|
guint32 last_video_pts;
|
||||||
|
GstClockTime video_time_offset;
|
||||||
gdouble framerate;
|
gdouble framerate;
|
||||||
|
|
||||||
gboolean random_access;
|
gboolean random_access;
|
||||||
|
|
|
@ -8831,8 +8831,16 @@ qtdemux_parse_tree (GstQTDemux * qtdemux)
|
||||||
/* Moving qt creation time (secs since 1904) to unix time */
|
/* Moving qt creation time (secs since 1904) to unix time */
|
||||||
if (creation_time != 0) {
|
if (creation_time != 0) {
|
||||||
if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
|
if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
|
||||||
|
GTimeVal now;
|
||||||
|
|
||||||
creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
|
creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
|
||||||
datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
|
/* some data cleansing sanity */
|
||||||
|
g_get_current_time (&now);
|
||||||
|
if (now.tv_sec + 24 * 3600 < creation_time) {
|
||||||
|
GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
|
||||||
|
} else {
|
||||||
|
datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
|
GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
|
||||||
"please file a bug at http://bugzilla.gnome.org");
|
"please file a bug at http://bugzilla.gnome.org");
|
||||||
|
@ -8868,8 +8876,13 @@ qtdemux_parse_tree (GstQTDemux * qtdemux)
|
||||||
|
|
||||||
/* set duration in the segment info */
|
/* set duration in the segment info */
|
||||||
gst_qtdemux_get_duration (qtdemux, &duration);
|
gst_qtdemux_get_duration (qtdemux, &duration);
|
||||||
if (duration)
|
if (duration) {
|
||||||
qtdemux->segment.duration = duration;
|
qtdemux->segment.duration = duration;
|
||||||
|
/* also do not exceed duration; stop is set that way post seek anyway,
|
||||||
|
* and segment activation falls back to duration,
|
||||||
|
* whereas loop only checks stop, so let's align this here as well */
|
||||||
|
qtdemux->segment.stop = duration;
|
||||||
|
}
|
||||||
|
|
||||||
/* parse all traks */
|
/* parse all traks */
|
||||||
trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
|
trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
|
||||||
|
|
|
@ -411,10 +411,12 @@ gst_ebml_write_element_push (GstEbmlWrite * ebml, GstBuffer * buf,
|
||||||
if (!buf_data)
|
if (!buf_data)
|
||||||
buf_data = GST_BUFFER_DATA (buf);
|
buf_data = GST_BUFFER_DATA (buf);
|
||||||
|
|
||||||
if (buf_data_end)
|
if (buf_data_end) {
|
||||||
data_size = buf_data_end - buf_data;
|
data_size = buf_data_end - buf_data;
|
||||||
else
|
GST_BUFFER_SIZE (buf) = data_size;
|
||||||
|
} else {
|
||||||
data_size = GST_BUFFER_SIZE (buf);
|
data_size = GST_BUFFER_SIZE (buf);
|
||||||
|
}
|
||||||
|
|
||||||
ebml->pos += data_size;
|
ebml->pos += data_size;
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <gst/rtp/gstrtpbuffer.h>
|
#include <gst/rtp/gstrtpbuffer.h>
|
||||||
|
|
||||||
|
@ -61,9 +63,23 @@ static GstStaticPadTemplate gst_rtp_h263p_pay_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("video/x-h263, " "variant = (string) \"itu\" ")
|
GST_STATIC_CAPS ("video/x-h263, " "variant = (string) \"itu\"")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We also return these in getcaps() as required by the SDP caps
|
||||||
|
*
|
||||||
|
* width = (int) [16, 4096]
|
||||||
|
* height = (int) [16, 4096]
|
||||||
|
* "annex-f = (boolean) {true, false},"
|
||||||
|
* "annex-i = (boolean) {true, false},"
|
||||||
|
* "annex-j = (boolean) {true, false},"
|
||||||
|
* "annex-l = (boolean) {true, false},"
|
||||||
|
* "annex-t = (boolean) {true, false},"
|
||||||
|
* "annex-v = (boolean) {true, false}")
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_rtp_h263p_pay_src_template =
|
static GstStaticPadTemplate gst_rtp_h263p_pay_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
|
@ -87,6 +103,8 @@ static void gst_rtp_h263p_pay_get_property (GObject * object, guint prop_id,
|
||||||
|
|
||||||
static gboolean gst_rtp_h263p_pay_setcaps (GstBaseRTPPayload * payload,
|
static gboolean gst_rtp_h263p_pay_setcaps (GstBaseRTPPayload * payload,
|
||||||
GstCaps * caps);
|
GstCaps * caps);
|
||||||
|
static GstCaps *gst_rtp_h263p_pay_sink_getcaps (GstBaseRTPPayload * payload,
|
||||||
|
GstPad * pad);
|
||||||
static GstFlowReturn gst_rtp_h263p_pay_handle_buffer (GstBaseRTPPayload *
|
static GstFlowReturn gst_rtp_h263p_pay_handle_buffer (GstBaseRTPPayload *
|
||||||
payload, GstBuffer * buffer);
|
payload, GstBuffer * buffer);
|
||||||
|
|
||||||
|
@ -109,6 +127,7 @@ gst_rtp_h263p_pay_class_init (GstRtpH263PPayClass * klass)
|
||||||
gobject_class->get_property = gst_rtp_h263p_pay_get_property;
|
gobject_class->get_property = gst_rtp_h263p_pay_get_property;
|
||||||
|
|
||||||
gstbasertppayload_class->set_caps = gst_rtp_h263p_pay_setcaps;
|
gstbasertppayload_class->set_caps = gst_rtp_h263p_pay_setcaps;
|
||||||
|
gstbasertppayload_class->get_caps = gst_rtp_h263p_pay_sink_getcaps;
|
||||||
gstbasertppayload_class->handle_buffer = gst_rtp_h263p_pay_handle_buffer;
|
gstbasertppayload_class->handle_buffer = gst_rtp_h263p_pay_handle_buffer;
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
||||||
|
@ -187,6 +206,380 @@ gst_rtp_h263p_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
caps_append (GstCaps * caps, GstStructure * in_s, guint x, guint y, guint mpi)
|
||||||
|
{
|
||||||
|
GstStructure *s;
|
||||||
|
|
||||||
|
if (!in_s)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mpi < 1 || mpi > 32)
|
||||||
|
return;
|
||||||
|
|
||||||
|
s = gst_structure_copy (in_s);
|
||||||
|
|
||||||
|
gst_structure_set (s,
|
||||||
|
"width", GST_TYPE_INT_RANGE, 1, x,
|
||||||
|
"height", GST_TYPE_INT_RANGE, 1, y,
|
||||||
|
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 1001 * mpi, NULL);
|
||||||
|
|
||||||
|
gst_caps_merge_structure (caps, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static GstCaps *
|
||||||
|
gst_rtp_h263p_pay_sink_getcaps (GstBaseRTPPayload * payload, GstPad * pad)
|
||||||
|
{
|
||||||
|
GstRtpH263PPay *rtph263ppay;
|
||||||
|
GstCaps *caps = gst_caps_new_empty ();
|
||||||
|
GstCaps *peercaps = NULL;
|
||||||
|
GstCaps *intersect = NULL;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
rtph263ppay = GST_RTP_H263P_PAY (payload);
|
||||||
|
|
||||||
|
peercaps = gst_pad_peer_get_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload));
|
||||||
|
if (!peercaps)
|
||||||
|
return
|
||||||
|
gst_caps_copy (gst_pad_get_pad_template_caps
|
||||||
|
(GST_BASE_RTP_PAYLOAD_SINKPAD (payload)));
|
||||||
|
|
||||||
|
intersect = gst_caps_intersect (peercaps,
|
||||||
|
gst_pad_get_pad_template_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload)));
|
||||||
|
gst_caps_unref (peercaps);
|
||||||
|
|
||||||
|
if (gst_caps_is_empty (intersect))
|
||||||
|
return intersect;
|
||||||
|
|
||||||
|
for (i = 0; i < gst_caps_get_size (intersect); i++) {
|
||||||
|
GstStructure *s = gst_caps_get_structure (intersect, i);
|
||||||
|
const gchar *encoding_name = gst_structure_get_string (s, "encoding-name");
|
||||||
|
|
||||||
|
if (!strcmp (encoding_name, "H263-2000")) {
|
||||||
|
const gchar *profile_str = gst_structure_get_string (s, "profile");
|
||||||
|
const gchar *level_str = gst_structure_get_string (s, "level");
|
||||||
|
int profile = 0;
|
||||||
|
int level = 0;
|
||||||
|
|
||||||
|
if (profile_str && level_str) {
|
||||||
|
gboolean i = FALSE, j = FALSE, l = FALSE, t = FALSE, f = FALSE,
|
||||||
|
v = FALSE;
|
||||||
|
GstStructure *new_s = gst_structure_new ("video/x-h263",
|
||||||
|
"variant", G_TYPE_STRING, "itu",
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
profile = atoi (profile_str);
|
||||||
|
level = atoi (level_str);
|
||||||
|
|
||||||
|
/* These profiles are defined in the H.263 Annex X */
|
||||||
|
switch (profile) {
|
||||||
|
case 0:
|
||||||
|
/* The Baseline Profile (Profile 0) */
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
/* H.320 Coding Efficiency Version 2 Backward-Compatibility Profile
|
||||||
|
* (Profile 1)
|
||||||
|
* Baseline + Annexes I, J, L.4 and T
|
||||||
|
*/
|
||||||
|
i = j = l = t = TRUE;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
/* Version 1 Backward-Compatibility Profile (Profile 2)
|
||||||
|
* Baseline + Annex F
|
||||||
|
*/
|
||||||
|
i = j = l = t = f = TRUE;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
/* Version 2 Interactive and Streaming Wireless Profile
|
||||||
|
* Baseline + Annexes I, J, T
|
||||||
|
*/
|
||||||
|
i = j = t = TRUE;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
/* Version 3 Interactive and Streaming Wireless Profile (Profile 4)
|
||||||
|
* Baseline + Annexes I, J, T, V, W.6.3.8,
|
||||||
|
*/
|
||||||
|
/* Missing W.6.3.8 */
|
||||||
|
i = j = t = v = TRUE;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
/* Conversational High Compression Profile (Profile 5)
|
||||||
|
* Baseline + Annexes F, I, J, L.4, T, D, U
|
||||||
|
*/
|
||||||
|
/* Missing D, U */
|
||||||
|
f = i = j = l = t = TRUE;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
/* Conversational Internet Profile (Profile 6)
|
||||||
|
* Baseline + Annexes F, I, J, L.4, T, D, U and
|
||||||
|
* K with arbitratry slice ordering
|
||||||
|
*/
|
||||||
|
/* Missing D, U, K with arbitratry slice ordering */
|
||||||
|
f = i = j = l = t = TRUE;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
/* Conversational Interlace Profile (Profile 7)
|
||||||
|
* Baseline + Annexes F, I, J, L.4, T, D, U, W.6.3.11
|
||||||
|
*/
|
||||||
|
/* Missing D, U, W.6.3.11 */
|
||||||
|
f = i = j = l = t = TRUE;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
/* High Latency Profile (Profile 8)
|
||||||
|
* Baseline + Annexes F, I, J, L.4, T, D, U, P.5, O.1.1 and
|
||||||
|
* K with arbitratry slice ordering
|
||||||
|
*/
|
||||||
|
/* Missing D, U, P.5, O.1.1 */
|
||||||
|
f = i = j = l = t = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (f || i || j || t || l || v) {
|
||||||
|
GValue list = { 0 };
|
||||||
|
GValue vstr = { 0 };
|
||||||
|
|
||||||
|
g_value_init (&list, GST_TYPE_LIST);
|
||||||
|
g_value_init (&vstr, G_TYPE_STRING);
|
||||||
|
|
||||||
|
g_value_set_static_string (&vstr, "h263");
|
||||||
|
gst_value_list_append_value (&list, &vstr);
|
||||||
|
g_value_set_static_string (&vstr, "h263p");
|
||||||
|
gst_value_list_append_value (&list, &vstr);
|
||||||
|
|
||||||
|
if (l || v) {
|
||||||
|
g_value_set_static_string (&vstr, "h263pp");
|
||||||
|
gst_value_list_append_value (&list, &vstr);
|
||||||
|
}
|
||||||
|
g_value_unset (&vstr);
|
||||||
|
|
||||||
|
gst_structure_set_value (new_s, "h263version", &list);
|
||||||
|
g_value_unset (&list);
|
||||||
|
} else {
|
||||||
|
gst_structure_set (new_s, "h263version", G_TYPE_STRING, "h263", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
gst_structure_set (new_s, "annex-f", G_TYPE_BOOLEAN, FALSE, NULL);
|
||||||
|
if (!i)
|
||||||
|
gst_structure_set (new_s, "annex-i", G_TYPE_BOOLEAN, FALSE, NULL);
|
||||||
|
if (!j)
|
||||||
|
gst_structure_set (new_s, "annex-j", G_TYPE_BOOLEAN, FALSE, NULL);
|
||||||
|
if (!t)
|
||||||
|
gst_structure_set (new_s, "annex-t", G_TYPE_BOOLEAN, FALSE, NULL);
|
||||||
|
if (!l)
|
||||||
|
gst_structure_set (new_s, "annex-l", G_TYPE_BOOLEAN, FALSE, NULL);
|
||||||
|
if (!v)
|
||||||
|
gst_structure_set (new_s, "annex-v", G_TYPE_BOOLEAN, FALSE, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
if (level <= 10 || level == 45) {
|
||||||
|
gst_structure_set (new_s,
|
||||||
|
"width", GST_TYPE_INT_RANGE, 1, 176,
|
||||||
|
"height", GST_TYPE_INT_RANGE, 1, 144,
|
||||||
|
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 2002, NULL);
|
||||||
|
gst_caps_merge_structure (caps, new_s);
|
||||||
|
} else if (level <= 20) {
|
||||||
|
GstStructure *s_copy = gst_structure_copy (new_s);
|
||||||
|
|
||||||
|
gst_structure_set (new_s,
|
||||||
|
"width", GST_TYPE_INT_RANGE, 1, 352,
|
||||||
|
"height", GST_TYPE_INT_RANGE, 1, 288,
|
||||||
|
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 2002, NULL);
|
||||||
|
gst_caps_merge_structure (caps, new_s);
|
||||||
|
|
||||||
|
gst_structure_set (s_copy,
|
||||||
|
"width", GST_TYPE_INT_RANGE, 1, 176,
|
||||||
|
"height", GST_TYPE_INT_RANGE, 1, 144,
|
||||||
|
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 1001, NULL);
|
||||||
|
gst_caps_merge_structure (caps, s_copy);
|
||||||
|
} else if (level <= 40) {
|
||||||
|
|
||||||
|
gst_structure_set (new_s,
|
||||||
|
"width", GST_TYPE_INT_RANGE, 1, 352,
|
||||||
|
"height", GST_TYPE_INT_RANGE, 1, 288,
|
||||||
|
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 1001, NULL);
|
||||||
|
gst_caps_merge_structure (caps, new_s);
|
||||||
|
} else if (level <= 50) {
|
||||||
|
GstStructure *s_copy = gst_structure_copy (new_s);
|
||||||
|
|
||||||
|
gst_structure_set (new_s,
|
||||||
|
"width", GST_TYPE_INT_RANGE, 1, 352,
|
||||||
|
"height", GST_TYPE_INT_RANGE, 1, 288,
|
||||||
|
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL);
|
||||||
|
gst_caps_merge_structure (caps, new_s);
|
||||||
|
|
||||||
|
gst_structure_set (s_copy,
|
||||||
|
"width", GST_TYPE_INT_RANGE, 1, 352,
|
||||||
|
"height", GST_TYPE_INT_RANGE, 1, 240,
|
||||||
|
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL);
|
||||||
|
gst_caps_merge_structure (caps, s_copy);
|
||||||
|
} else if (level <= 60) {
|
||||||
|
GstStructure *s_copy = gst_structure_copy (new_s);
|
||||||
|
|
||||||
|
gst_structure_set (new_s,
|
||||||
|
"width", GST_TYPE_INT_RANGE, 1, 720,
|
||||||
|
"height", GST_TYPE_INT_RANGE, 1, 288,
|
||||||
|
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL);
|
||||||
|
gst_caps_merge_structure (caps, new_s);
|
||||||
|
|
||||||
|
gst_structure_set (s_copy,
|
||||||
|
"width", GST_TYPE_INT_RANGE, 1, 720,
|
||||||
|
"height", GST_TYPE_INT_RANGE, 1, 240,
|
||||||
|
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL);
|
||||||
|
gst_caps_merge_structure (caps, s_copy);
|
||||||
|
} else if (level <= 70) {
|
||||||
|
GstStructure *s_copy = gst_structure_copy (new_s);
|
||||||
|
|
||||||
|
gst_structure_set (new_s,
|
||||||
|
"width", GST_TYPE_INT_RANGE, 1, 720,
|
||||||
|
"height", GST_TYPE_INT_RANGE, 1, 576,
|
||||||
|
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL);
|
||||||
|
gst_caps_merge_structure (caps, new_s);
|
||||||
|
|
||||||
|
gst_structure_set (s_copy,
|
||||||
|
"width", GST_TYPE_INT_RANGE, 1, 720,
|
||||||
|
"height", GST_TYPE_INT_RANGE, 1, 480,
|
||||||
|
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL);
|
||||||
|
gst_caps_merge_structure (caps, s_copy);
|
||||||
|
} else {
|
||||||
|
gst_caps_merge_structure (caps, new_s);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
GstStructure *new_s = gst_structure_new ("video/x-h263",
|
||||||
|
"variant", G_TYPE_STRING, "itu",
|
||||||
|
"h263version", G_TYPE_STRING, "h263",
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (rtph263ppay, "No profile or level specified"
|
||||||
|
" for H263-2000, defaulting to baseline H263");
|
||||||
|
|
||||||
|
gst_caps_merge_structure (caps, new_s);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gboolean f = FALSE, i = FALSE, j = FALSE, t = FALSE;
|
||||||
|
/* FIXME: ffmpeg support the Appendix K too, how do we express it ?
|
||||||
|
* guint k;
|
||||||
|
*/
|
||||||
|
const gchar *str;
|
||||||
|
GstStructure *new_s = gst_structure_new ("video/x-h263",
|
||||||
|
"variant", G_TYPE_STRING, "itu",
|
||||||
|
NULL);
|
||||||
|
gboolean added = FALSE;
|
||||||
|
|
||||||
|
str = gst_structure_get_string (s, "f");
|
||||||
|
if (str && !strcmp (str, "1"))
|
||||||
|
f = TRUE;
|
||||||
|
|
||||||
|
str = gst_structure_get_string (s, "i");
|
||||||
|
if (str && !strcmp (str, "1"))
|
||||||
|
i = TRUE;
|
||||||
|
|
||||||
|
str = gst_structure_get_string (s, "j");
|
||||||
|
if (str && !strcmp (str, "1"))
|
||||||
|
j = TRUE;
|
||||||
|
|
||||||
|
str = gst_structure_get_string (s, "t");
|
||||||
|
if (str && !strcmp (str, "1"))
|
||||||
|
t = TRUE;
|
||||||
|
|
||||||
|
if (f || i || j || t) {
|
||||||
|
GValue list = { 0 };
|
||||||
|
GValue vstr = { 0 };
|
||||||
|
|
||||||
|
g_value_init (&list, GST_TYPE_LIST);
|
||||||
|
g_value_init (&vstr, G_TYPE_STRING);
|
||||||
|
|
||||||
|
g_value_set_static_string (&vstr, "h263");
|
||||||
|
gst_value_list_append_value (&list, &vstr);
|
||||||
|
g_value_set_static_string (&vstr, "h263p");
|
||||||
|
gst_value_list_append_value (&list, &vstr);
|
||||||
|
g_value_unset (&vstr);
|
||||||
|
|
||||||
|
gst_structure_set_value (new_s, "h263version", &list);
|
||||||
|
g_value_unset (&list);
|
||||||
|
} else {
|
||||||
|
gst_structure_set (new_s, "h263version", G_TYPE_STRING, "h263", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
gst_structure_set (new_s, "annex-f", G_TYPE_BOOLEAN, FALSE, NULL);
|
||||||
|
if (!i)
|
||||||
|
gst_structure_set (new_s, "annex-i", G_TYPE_BOOLEAN, FALSE, NULL);
|
||||||
|
if (!j)
|
||||||
|
gst_structure_set (new_s, "annex-j", G_TYPE_BOOLEAN, FALSE, NULL);
|
||||||
|
if (!t)
|
||||||
|
gst_structure_set (new_s, "annex-t", G_TYPE_BOOLEAN, FALSE, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
str = gst_structure_get_string (s, "custom");
|
||||||
|
if (str) {
|
||||||
|
unsigned int xmax, ymax, mpi;
|
||||||
|
if (sscanf (str, "%u,%u,%u", &xmax, &ymax, &mpi) == 3) {
|
||||||
|
if (xmax % 4 && ymax % 4 && mpi >= 1 && mpi <= 32) {
|
||||||
|
caps_append (caps, new_s, xmax, ymax, mpi);
|
||||||
|
added = TRUE;
|
||||||
|
} else {
|
||||||
|
GST_WARNING_OBJECT (rtph263ppay, "Invalid custom framesize/MPI"
|
||||||
|
" %u x %u at %u, ignoring", xmax, ymax, mpi);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GST_WARNING_OBJECT (rtph263ppay, "Invalid custom framesize/MPI: %s,"
|
||||||
|
" ignoring", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str = gst_structure_get_string (s, "16cif");
|
||||||
|
if (str) {
|
||||||
|
int mpi = atoi (str);
|
||||||
|
caps_append (caps, new_s, 1408, 1152, mpi);
|
||||||
|
added = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = gst_structure_get_string (s, "4cif");
|
||||||
|
if (str) {
|
||||||
|
int mpi = atoi (str);
|
||||||
|
caps_append (caps, new_s, 704, 576, mpi);
|
||||||
|
added = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = gst_structure_get_string (s, "cif");
|
||||||
|
if (str) {
|
||||||
|
int mpi = atoi (str);
|
||||||
|
caps_append (caps, new_s, 352, 288, mpi);
|
||||||
|
added = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = gst_structure_get_string (s, "qcif");
|
||||||
|
if (str) {
|
||||||
|
int mpi = atoi (str);
|
||||||
|
caps_append (caps, new_s, 176, 144, mpi);
|
||||||
|
added = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = gst_structure_get_string (s, "sqcif");
|
||||||
|
if (str) {
|
||||||
|
int mpi = atoi (str);
|
||||||
|
caps_append (caps, new_s, 128, 96, mpi);
|
||||||
|
added = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (added)
|
||||||
|
gst_structure_free (new_s);
|
||||||
|
else
|
||||||
|
gst_caps_merge_structure (caps, new_s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_caps_unref (intersect);
|
||||||
|
|
||||||
|
return caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtp_h263p_pay_set_property (GObject * object, guint prop_id,
|
gst_rtp_h263p_pay_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec)
|
const GValue * value, GParamSpec * pspec)
|
||||||
|
|
Loading…
Reference in a new issue