2006-02-24 19:07:10 +00:00
|
|
|
/*
|
|
|
|
* gstcmmlenc.c - GStreamer CMML encoder
|
|
|
|
* Copyright (C) 2005 Alessandro Decina
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Alessandro Decina <alessandro@nnva.org>
|
|
|
|
*
|
|
|
|
* 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., 59 Temple Place - Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* SECTION:element-cmmlenc
|
|
|
|
* @see_also: cmmldec, oggmux
|
|
|
|
*
|
2009-01-28 15:46:06 +00:00
|
|
|
* Cmmlenc encodes a CMML document into a CMML stream. <ulink
|
2006-02-24 19:07:10 +00:00
|
|
|
* url="http://www.annodex.net/TR/draft-pfeiffer-cmml-02.html">CMML</ulink> is
|
|
|
|
* an XML markup language for time-continuous data maintained by the <ulink
|
|
|
|
* url="http:/www.annodex.org/">Annodex Foundation</ulink>.
|
2009-01-28 15:46:06 +00:00
|
|
|
*
|
|
|
|
* <refsect2>
|
2006-02-24 19:07:10 +00:00
|
|
|
* <title>Example pipeline</title>
|
2009-01-28 15:46:06 +00:00
|
|
|
* |[
|
2006-02-24 19:07:10 +00:00
|
|
|
* gst-launch -v filesrc location=annotations.cmml ! cmmlenc ! oggmux name=mux ! filesink location=annotated.ogg
|
2009-01-28 15:46:06 +00:00
|
|
|
* ]|
|
2006-02-24 19:07:10 +00:00
|
|
|
* </refsect2>
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include "gstcmmlenc.h"
|
|
|
|
#include "gstannodex.h"
|
|
|
|
|
2006-06-22 19:31:04 +00:00
|
|
|
GST_DEBUG_CATEGORY_STATIC (cmmlenc);
|
2006-02-24 19:07:10 +00:00
|
|
|
#define GST_CAT_DEFAULT cmmlenc
|
|
|
|
|
|
|
|
#define CMML_IDENT_HEADER_SIZE 29
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
ARG_0,
|
|
|
|
GST_CMML_ENC_GRANULERATE_N,
|
|
|
|
GST_CMML_ENC_GRANULERATE_D,
|
|
|
|
GST_CMML_ENC_GRANULESHIFT
|
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
Define GstElementDetails as const and also static (when defined as global)
Original commit message from CVS:
* ext/aalib/gstaasink.c:
* ext/annodex/gstcmmldec.c:
* ext/annodex/gstcmmlenc.c:
* ext/cairo/gsttextoverlay.c:
* ext/cairo/gsttimeoverlay.c:
* ext/cdio/gstcdiocddasrc.c:
* ext/dv/gstdvdec.c:
* ext/dv/gstdvdemux.c:
* ext/esd/esdmon.c:
* ext/esd/esdsink.c:
* ext/flac/gstflacenc.c:
* ext/flac/gstflactag.c:
* ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_base_init):
* ext/gconf/gstgconfaudiosrc.c: (gst_gconf_audio_src_base_init):
* ext/gconf/gstgconfvideosink.c: (gst_gconf_video_sink_base_init):
* ext/gconf/gstgconfvideosrc.c: (gst_gconf_video_src_base_init):
* ext/gdk_pixbuf/pixbufscale.c:
* ext/hal/gsthalaudiosink.c: (gst_hal_audio_sink_base_init):
* ext/hal/gsthalaudiosrc.c: (gst_hal_audio_src_base_init):
* ext/jpeg/gstjpegdec.c:
* ext/jpeg/gstjpegenc.c:
* ext/jpeg/gstsmokedec.c:
* ext/jpeg/gstsmokeenc.c:
* ext/libcaca/gstcacasink.c:
* ext/libmng/gstmngdec.c:
* ext/libmng/gstmngenc.c:
* ext/libpng/gstpngdec.c:
* ext/libpng/gstpngenc.c:
* ext/mikmod/gstmikmod.c:
* ext/raw1394/gstdv1394src.c:
* ext/shout2/gstshout2.c: (gst_shout2send_init):
* ext/shout2/gstshout2.h:
* ext/speex/gstspeexdec.c:
* ext/speex/gstspeexenc.c:
* gst/alpha/gstalpha.c:
* gst/alpha/gstalphacolor.c:
* gst/apetag/gstapedemux.c:
* gst/auparse/gstauparse.c:
* gst/autodetect/gstautoaudiosink.c:
(gst_auto_audio_sink_base_init):
* gst/autodetect/gstautovideosink.c:
(gst_auto_video_sink_base_init):
* gst/avi/gstavidemux.c: (gst_avi_demux_base_init):
* gst/avi/gstavimux.c: (gst_avimux_base_init):
* gst/cutter/gstcutter.c:
* gst/debug/breakmydata.c:
* gst/debug/efence.c:
* gst/debug/gstnavigationtest.c:
* gst/debug/gstnavseek.c:
* gst/debug/negotiation.c:
* gst/debug/progressreport.c:
* gst/debug/testplugin.c:
* gst/effectv/gstaging.c:
* gst/effectv/gstdice.c:
* gst/effectv/gstedge.c:
* gst/effectv/gstquark.c:
* gst/effectv/gstrev.c:
* gst/effectv/gstshagadelic.c:
* gst/effectv/gstvertigo.c:
* gst/effectv/gstwarp.c:
* gst/flx/gstflxdec.c:
* gst/goom/gstgoom.c:
* gst/icydemux/gsticydemux.c:
* gst/id3demux/gstid3demux.c:
* gst/interleave/deinterleave.c:
* gst/interleave/interleave.c:
* gst/law/alaw-decode.c: (gst_alawdec_base_init):
* gst/law/alaw-encode.c: (gst_alawenc_base_init):
* gst/law/mulaw-decode.c: (gst_mulawdec_base_init):
* gst/law/mulaw-encode.c: (gst_mulawenc_base_init):
* gst/level/gstlevel.c:
* gst/matroska/matroska-demux.c: (gst_matroska_demux_base_init):
* gst/matroska/matroska-mux.c: (gst_matroska_mux_base_init):
* gst/median/gstmedian.c:
* gst/monoscope/gstmonoscope.c:
* gst/multipart/multipartdemux.c:
* gst/multipart/multipartmux.c:
* gst/oldcore/gstaggregator.c:
* gst/oldcore/gstfdsink.c:
* gst/oldcore/gstmd5sink.c:
* gst/oldcore/gstmultifilesrc.c:
* gst/oldcore/gstpipefilter.c:
* gst/oldcore/gstshaper.c:
* gst/oldcore/gststatistics.c:
* gst/rtp/gstasteriskh263.c:
* gst/rtp/gstrtpL16depay.c:
* gst/rtp/gstrtpL16pay.c:
* gst/rtp/gstrtpamrdepay.c:
* gst/rtp/gstrtpamrpay.c:
* gst/rtp/gstrtpdepay.c:
* gst/rtp/gstrtpgsmpay.c:
* gst/rtp/gstrtph263pay.c:
* gst/rtp/gstrtph263pdepay.c:
* gst/rtp/gstrtph263ppay.c:
* gst/rtp/gstrtpilbcdepay.c:
* gst/rtp/gstrtpmp4gpay.c:
* gst/rtp/gstrtpmp4vdepay.c:
* gst/rtp/gstrtpmp4vpay.c:
* gst/rtp/gstrtpmpadepay.c:
* gst/rtp/gstrtpmpapay.c:
* gst/rtp/gstrtppcmadepay.c:
* gst/rtp/gstrtppcmapay.c:
* gst/rtp/gstrtppcmudepay.c:
* gst/rtp/gstrtppcmupay.c:
* gst/rtp/gstrtpspeexdepay.c:
* gst/rtp/gstrtpspeexpay.c:
* gst/rtsp/gstrtpdec.c:
* gst/rtsp/gstrtspsrc.c:
* gst/smpte/gstsmpte.c:
* gst/udp/gstdynudpsink.c:
* gst/udp/gstmultiudpsink.c:
* gst/udp/gstudpsink.c:
* gst/udp/gstudpsrc.c:
* gst/videobox/gstvideobox.c:
* gst/videofilter/gstgamma.c: (gst_gamma_base_init):
* gst/videofilter/gstvideobalance.c:
* gst/videofilter/gstvideoflip.c:
* gst/videofilter/gstvideotemplate.c:
(gst_videotemplate_base_init):
* gst/videomixer/videomixer.c:
* gst/wavparse/gstwavparse.c: (gst_wavparse_base_init),
(gst_wavparse_class_init), (gst_wavparse_dispose),
(gst_wavparse_reset), (gst_wavparse_init),
(gst_wavparse_perform_seek), (gst_wavparse_peek_chunk_info),
(gst_wavparse_peek_chunk), (gst_wavparse_stream_headers),
(gst_wavparse_parse_stream_init), (gst_wavparse_send_event),
(gst_wavparse_add_src_pad), (gst_wavparse_stream_data),
(gst_wavparse_chain), (gst_wavparse_srcpad_event),
(gst_wavparse_sink_activate), (gst_wavparse_sink_activate_pull),
(gst_wavparse_change_state):
* gst/wavparse/gstwavparse.h:
* sys/oss/gstossmixerelement.c:
* sys/oss/gstosssink.c:
* sys/oss/gstosssrc.c:
* sys/osxaudio/gstosxaudioelement.c:
* sys/osxaudio/gstosxaudiosink.c:
* sys/osxaudio/gstosxaudiosrc.c:
* sys/sunaudio/gstsunaudiomixer.c:
* sys/sunaudio/gstsunaudiosink.c:
Define GstElementDetails as const and also static (when defined as
global)
2006-04-25 21:39:46 +00:00
|
|
|
static const GstElementDetails gst_cmml_enc_details =
|
2006-03-30 15:37:05 +00:00
|
|
|
GST_ELEMENT_DETAILS ("CMML streams encoder",
|
|
|
|
"Codec/Encoder",
|
|
|
|
"Encodes CMML streams",
|
|
|
|
"Alessandro Decina <alessandro@nnva.org>");
|
2006-02-24 19:07:10 +00:00
|
|
|
|
|
|
|
static GstStaticPadTemplate gst_cmml_enc_src_factory =
|
|
|
|
GST_STATIC_PAD_TEMPLATE ("src",
|
|
|
|
GST_PAD_SRC,
|
|
|
|
GST_PAD_ALWAYS,
|
2006-02-25 19:07:41 +00:00
|
|
|
GST_STATIC_CAPS ("text/x-cmml, encoded = (boolean) true")
|
2006-02-24 19:07:10 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
static GstStaticPadTemplate gst_cmml_enc_sink_factory =
|
|
|
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
|
|
|
GST_PAD_SINK,
|
|
|
|
GST_PAD_ALWAYS,
|
2006-02-25 19:07:41 +00:00
|
|
|
GST_STATIC_CAPS ("text/x-cmml, encoded = (boolean) false")
|
2006-02-24 19:07:10 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
GST_BOILERPLATE (GstCmmlEnc, gst_cmml_enc, GstElement, GST_TYPE_ELEMENT);
|
|
|
|
static void gst_cmml_enc_get_property (GObject * object, guint property_id,
|
|
|
|
GValue * value, GParamSpec * pspec);
|
|
|
|
static void gst_cmml_enc_set_property (GObject * object, guint property_id,
|
|
|
|
const GValue * value, GParamSpec * pspec);
|
|
|
|
static gboolean gst_cmml_enc_sink_event (GstPad * pad, GstEvent * event);
|
|
|
|
static GstStateChangeReturn gst_cmml_enc_change_state (GstElement * element,
|
|
|
|
GstStateChange transition);
|
|
|
|
static GstFlowReturn gst_cmml_enc_chain (GstPad * pad, GstBuffer * buffer);
|
|
|
|
static void gst_cmml_enc_parse_preamble (GstCmmlEnc * enc,
|
|
|
|
guchar * preamble, guchar * processing_instruction);
|
|
|
|
static void gst_cmml_enc_parse_end_tag (GstCmmlEnc * enc);
|
|
|
|
static void gst_cmml_enc_parse_tag_head (GstCmmlEnc * enc,
|
|
|
|
GstCmmlTagHead * head);
|
|
|
|
static void gst_cmml_enc_parse_tag_clip (GstCmmlEnc * enc,
|
|
|
|
GstCmmlTagClip * tag);
|
|
|
|
static GstFlowReturn gst_cmml_enc_new_buffer (GstCmmlEnc * enc,
|
|
|
|
guchar * data, gint size, GstBuffer ** buffer);
|
|
|
|
static GstFlowReturn gst_cmml_enc_push_clip (GstCmmlEnc * enc,
|
|
|
|
GstCmmlTagClip * clip, GstClockTime prev_clip_time);
|
|
|
|
static GstFlowReturn gst_cmml_enc_push (GstCmmlEnc * enc, GstBuffer * buffer);
|
|
|
|
|
2006-02-25 11:37:10 +00:00
|
|
|
static void gst_cmml_enc_finalize (GObject * object);
|
|
|
|
|
2006-02-24 19:07:10 +00:00
|
|
|
static void
|
|
|
|
gst_cmml_enc_base_init (gpointer g_class)
|
|
|
|
{
|
|
|
|
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
|
|
|
|
|
|
|
gst_element_class_add_pad_template (element_class,
|
|
|
|
gst_static_pad_template_get (&gst_cmml_enc_sink_factory));
|
|
|
|
gst_element_class_add_pad_template (element_class,
|
|
|
|
gst_static_pad_template_get (&gst_cmml_enc_src_factory));
|
|
|
|
gst_element_class_set_details (element_class, &gst_cmml_enc_details);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gst_cmml_enc_class_init (GstCmmlEncClass * enc_class)
|
|
|
|
{
|
|
|
|
GObjectClass *klass = G_OBJECT_CLASS (enc_class);
|
|
|
|
|
|
|
|
klass->get_property = gst_cmml_enc_get_property;
|
|
|
|
klass->set_property = gst_cmml_enc_set_property;
|
2006-02-25 11:37:10 +00:00
|
|
|
klass->finalize = gst_cmml_enc_finalize;
|
2006-02-24 19:07:10 +00:00
|
|
|
|
|
|
|
g_object_class_install_property (klass, GST_CMML_ENC_GRANULERATE_N,
|
|
|
|
g_param_spec_int64 ("granule-rate-numerator",
|
|
|
|
"Granulerate numerator",
|
|
|
|
"Granulerate numerator",
|
2006-02-25 19:07:41 +00:00
|
|
|
0, G_MAXINT64, 1000, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
2006-02-24 19:07:10 +00:00
|
|
|
|
|
|
|
g_object_class_install_property (klass, GST_CMML_ENC_GRANULERATE_D,
|
|
|
|
g_param_spec_int64 ("granule-rate-denominator",
|
|
|
|
"Granulerate denominator",
|
|
|
|
"Granulerate denominator",
|
2006-02-25 19:07:41 +00:00
|
|
|
0, G_MAXINT64, 1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
2006-02-24 19:07:10 +00:00
|
|
|
|
|
|
|
g_object_class_install_property (klass, GST_CMML_ENC_GRANULESHIFT,
|
|
|
|
g_param_spec_uchar ("granule-shift",
|
|
|
|
"Granuleshift",
|
|
|
|
"The number of lower bits to use for partitioning a granule position",
|
2006-04-28 18:57:09 +00:00
|
|
|
0, 64, 32, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
2006-02-24 19:07:10 +00:00
|
|
|
|
|
|
|
GST_ELEMENT_CLASS (klass)->change_state = gst_cmml_enc_change_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gst_cmml_enc_init (GstCmmlEnc * enc, GstCmmlEncClass * klass)
|
|
|
|
{
|
|
|
|
enc->sinkpad =
|
|
|
|
gst_pad_new_from_static_template (&gst_cmml_enc_sink_factory, "sink");
|
|
|
|
gst_pad_set_chain_function (enc->sinkpad, gst_cmml_enc_chain);
|
|
|
|
gst_pad_set_event_function (enc->sinkpad, gst_cmml_enc_sink_event);
|
|
|
|
gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
|
|
|
|
|
|
|
|
enc->srcpad =
|
|
|
|
gst_pad_new_from_static_template (&gst_cmml_enc_src_factory, "src");
|
|
|
|
gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
|
|
|
|
|
|
|
|
enc->major = 3;
|
|
|
|
enc->minor = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gst_cmml_enc_set_property (GObject * object, guint property_id,
|
|
|
|
const GValue * value, GParamSpec * pspec)
|
|
|
|
{
|
|
|
|
GstCmmlEnc *enc = GST_CMML_ENC (object);
|
|
|
|
|
|
|
|
switch (property_id) {
|
|
|
|
case GST_CMML_ENC_GRANULERATE_N:
|
|
|
|
/* XXX: may need to flush clips */
|
|
|
|
enc->granulerate_n = g_value_get_int64 (value);
|
|
|
|
break;
|
|
|
|
case GST_CMML_ENC_GRANULERATE_D:
|
|
|
|
enc->granulerate_d = g_value_get_int64 (value);
|
|
|
|
break;
|
|
|
|
case GST_CMML_ENC_GRANULESHIFT:
|
|
|
|
enc->granuleshift = g_value_get_uchar (value);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gst_cmml_enc_get_property (GObject * object, guint property_id,
|
|
|
|
GValue * value, GParamSpec * pspec)
|
|
|
|
{
|
|
|
|
GstCmmlEnc *enc = GST_CMML_ENC (object);
|
|
|
|
|
|
|
|
switch (property_id) {
|
|
|
|
case GST_CMML_ENC_GRANULERATE_N:
|
|
|
|
g_value_set_int64 (value, enc->granulerate_n);
|
|
|
|
break;
|
|
|
|
case GST_CMML_ENC_GRANULERATE_D:
|
|
|
|
g_value_set_int64 (value, enc->granulerate_d);
|
|
|
|
break;
|
|
|
|
case GST_CMML_ENC_GRANULESHIFT:
|
|
|
|
g_value_set_uchar (value, enc->granuleshift);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-25 11:37:10 +00:00
|
|
|
static void
|
|
|
|
gst_cmml_enc_finalize (GObject * object)
|
|
|
|
{
|
|
|
|
GstCmmlEnc *enc = GST_CMML_ENC (object);
|
|
|
|
|
|
|
|
if (enc->tracks) {
|
|
|
|
gst_cmml_track_list_destroy (enc->tracks);
|
|
|
|
enc->tracks = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
2006-02-24 19:07:10 +00:00
|
|
|
static GstStateChangeReturn
|
|
|
|
gst_cmml_enc_change_state (GstElement * element, GstStateChange transition)
|
|
|
|
{
|
|
|
|
GstCmmlEnc *enc = GST_CMML_ENC (element);
|
|
|
|
GstStateChangeReturn res;
|
|
|
|
|
|
|
|
switch (transition) {
|
|
|
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
|
|
|
enc->parser = gst_cmml_parser_new (GST_CMML_PARSER_ENCODE);
|
|
|
|
enc->parser->user_data = enc;
|
|
|
|
enc->parser->preamble_callback =
|
|
|
|
(GstCmmlParserPreambleCallback) gst_cmml_enc_parse_preamble;
|
|
|
|
enc->parser->head_callback =
|
|
|
|
(GstCmmlParserHeadCallback) gst_cmml_enc_parse_tag_head;
|
|
|
|
enc->parser->clip_callback =
|
|
|
|
(GstCmmlParserClipCallback) gst_cmml_enc_parse_tag_clip;
|
|
|
|
enc->parser->cmml_end_callback =
|
|
|
|
(GstCmmlParserCmmlEndCallback) gst_cmml_enc_parse_end_tag;
|
|
|
|
enc->tracks = gst_cmml_track_list_new ();
|
|
|
|
enc->sent_headers = FALSE;
|
|
|
|
enc->sent_eos = FALSE;
|
|
|
|
enc->flow_return = GST_FLOW_OK;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = parent_class->change_state (element, transition);
|
|
|
|
|
|
|
|
switch (transition) {
|
|
|
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
|
|
|
{
|
|
|
|
gst_cmml_track_list_destroy (enc->tracks);
|
2006-02-25 11:37:10 +00:00
|
|
|
enc->tracks = NULL;
|
2006-02-24 19:07:10 +00:00
|
|
|
g_free (enc->preamble);
|
ext/annodex/gstannodex.c: Do some extra sanity checks.
Original commit message from CVS:
Patch by: Alessandro Decina <alessandro at nnva dot org>
* ext/annodex/gstannodex.c: (gst_annodex_granule_to_time):
Do some extra sanity checks.
Fixes #350340.
* ext/annodex/gstcmmlenc.c: (gst_cmml_enc_change_state),
(gst_cmml_enc_parse_tag_head), (gst_cmml_enc_parse_tag_clip),
(gst_cmml_enc_push_clip), (gst_cmml_enc_push):
Check if clip->start_time is valid before adding the clip to the
track list.
Reset enc->preamble going from PAUSED to READY.
Don't use GST_FLOW_UNEXPECTED for wrong usage of the element, it is
only used for EOS.
Only post an error message if we were the one that created the fatal
GstFlowReturn value.
* ext/annodex/gstcmmlutils.c: (gst_cmml_clock_time_from_npt),
(gst_cmml_clock_time_to_granule), (gst_cmml_track_list_has_clip):
Parse the seconds field of the npt-sec time format using %llu rather than
%d and check that the value scaled by GST_SECOND doesn't overflow.
Use guint64(s) to represent the keyindex and keyoffset fields of a granulepos.
Lookup a clip's track with clip->track rather than clip->id which
makes no sense.
Identify a clip by its track and start time and not its xml id.
do some more input checking and make sure we don't do undefined shifts.
* tests/check/elements/cmmldec.c: (setup_cmmldec),
(teardown_cmmldec), (check_output_buffer_is_equal), (push_data),
(cmml_tag_message_pop), (check_headers), (push_clip_full),
(push_clip), (push_empty_clip), (check_output_clip),
(GST_START_TEST), (cmmldec_suite):
* tests/check/elements/cmmlenc.c: (setup_cmmlenc),
(teardown_cmmlenc), (check_output_buffer_is_equal), (push_data),
(check_headers), (push_clip), (check_clip_times), (check_clip),
(check_empty_clip), (GST_START_TEST), (cmmlenc_suite):
Added some more checks.
2006-08-25 09:42:43 +00:00
|
|
|
enc->preamble = NULL;
|
2006-02-24 19:07:10 +00:00
|
|
|
gst_cmml_parser_free (enc->parser);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gst_cmml_enc_sink_event (GstPad * pad, GstEvent * event)
|
|
|
|
{
|
|
|
|
GstCmmlEnc *enc = GST_CMML_ENC (GST_PAD_PARENT (pad));
|
|
|
|
|
|
|
|
switch (GST_EVENT_TYPE (event)) {
|
|
|
|
case GST_EVENT_EOS:
|
|
|
|
{
|
|
|
|
if (!enc->sent_eos)
|
|
|
|
gst_cmml_enc_parse_end_tag (enc);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return gst_pad_event_default (pad, event);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GstFlowReturn
|
|
|
|
gst_cmml_enc_new_buffer (GstCmmlEnc * enc,
|
|
|
|
guchar * data, gint size, GstBuffer ** buffer)
|
|
|
|
{
|
|
|
|
GstFlowReturn res;
|
|
|
|
|
|
|
|
res = gst_pad_alloc_buffer (enc->srcpad, GST_BUFFER_OFFSET_NONE, size,
|
|
|
|
NULL, buffer);
|
|
|
|
if (res == GST_FLOW_OK) {
|
|
|
|
if (data)
|
|
|
|
memcpy (GST_BUFFER_DATA (*buffer), data, size);
|
|
|
|
} else {
|
2006-02-25 19:07:41 +00:00
|
|
|
GST_WARNING_OBJECT (enc, "alloc function returned error %s",
|
|
|
|
gst_flow_get_name (res));
|
2006-02-24 19:07:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GstCaps *
|
2006-02-25 19:07:41 +00:00
|
|
|
gst_cmml_enc_set_header_on_caps (GstCmmlEnc * enc, GstCaps * caps,
|
2006-02-24 19:07:10 +00:00
|
|
|
GstBuffer * ident, GstBuffer * preamble, GstBuffer * head)
|
|
|
|
{
|
|
|
|
GValue array = { 0 };
|
|
|
|
GValue value = { 0 };
|
|
|
|
GstStructure *structure;
|
2006-04-10 15:48:55 +00:00
|
|
|
GstBuffer *buffer;
|
2006-02-24 19:07:10 +00:00
|
|
|
|
|
|
|
caps = gst_caps_make_writable (caps);
|
|
|
|
structure = gst_caps_get_structure (caps, 0);
|
|
|
|
|
|
|
|
g_value_init (&array, GST_TYPE_ARRAY);
|
|
|
|
g_value_init (&value, GST_TYPE_BUFFER);
|
|
|
|
|
2006-04-10 15:48:55 +00:00
|
|
|
/* Make copies of header buffers to avoid circular references */
|
|
|
|
buffer = gst_buffer_copy (ident);
|
|
|
|
gst_value_set_buffer (&value, buffer);
|
2006-02-24 19:07:10 +00:00
|
|
|
gst_value_array_append_value (&array, &value);
|
2006-04-10 15:48:55 +00:00
|
|
|
gst_buffer_unref (buffer);
|
|
|
|
|
|
|
|
buffer = gst_buffer_copy (preamble);
|
|
|
|
gst_value_set_buffer (&value, buffer);
|
2006-02-24 19:07:10 +00:00
|
|
|
gst_value_array_append_value (&array, &value);
|
2006-04-10 15:48:55 +00:00
|
|
|
gst_buffer_unref (buffer);
|
|
|
|
|
|
|
|
buffer = gst_buffer_copy (head);
|
|
|
|
gst_value_set_buffer (&value, buffer);
|
2006-02-24 19:07:10 +00:00
|
|
|
gst_value_array_append_value (&array, &value);
|
2006-04-10 15:48:55 +00:00
|
|
|
gst_buffer_unref (buffer);
|
2006-02-24 19:07:10 +00:00
|
|
|
|
|
|
|
GST_BUFFER_FLAG_SET (ident, GST_BUFFER_FLAG_IN_CAPS);
|
|
|
|
GST_BUFFER_FLAG_SET (preamble, GST_BUFFER_FLAG_IN_CAPS);
|
|
|
|
GST_BUFFER_FLAG_SET (head, GST_BUFFER_FLAG_IN_CAPS);
|
|
|
|
|
|
|
|
gst_structure_set_value (structure, "streamheader", &array);
|
|
|
|
|
|
|
|
g_value_unset (&value);
|
|
|
|
g_value_unset (&array);
|
|
|
|
|
|
|
|
return caps;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create a CMML ident header buffer
|
|
|
|
*/
|
|
|
|
static GstFlowReturn
|
|
|
|
gst_cmml_enc_new_ident_header (GstCmmlEnc * enc, GstBuffer ** buffer)
|
|
|
|
{
|
|
|
|
guint8 ident_header[CMML_IDENT_HEADER_SIZE];
|
|
|
|
guint8 *wptr = ident_header;
|
|
|
|
|
|
|
|
memcpy (wptr, "CMML\0\0\0\0", 8);
|
|
|
|
wptr += 8;
|
|
|
|
GST_WRITE_UINT16_LE (wptr, enc->major);
|
|
|
|
wptr += 2;
|
|
|
|
GST_WRITE_UINT16_LE (wptr, enc->minor);
|
|
|
|
wptr += 2;
|
|
|
|
GST_WRITE_UINT64_LE (wptr, enc->granulerate_n);
|
|
|
|
wptr += 8;
|
|
|
|
GST_WRITE_UINT64_LE (wptr, enc->granulerate_d);
|
|
|
|
wptr += 8;
|
|
|
|
*wptr = enc->granuleshift;
|
|
|
|
|
|
|
|
return gst_cmml_enc_new_buffer (enc,
|
|
|
|
(guchar *) & ident_header, CMML_IDENT_HEADER_SIZE, buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* parse the CMML preamble */
|
|
|
|
static void
|
|
|
|
gst_cmml_enc_parse_preamble (GstCmmlEnc * enc,
|
|
|
|
guchar * preamble, guchar * processing_instruction)
|
|
|
|
{
|
|
|
|
GST_INFO_OBJECT (enc, "parsing preamble");
|
|
|
|
|
|
|
|
/* save the preamble: it will be pushed when the head tag is found */
|
|
|
|
enc->preamble = (guchar *) g_strconcat ((gchar *) preamble,
|
|
|
|
(gchar *) processing_instruction, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* parse the CMML end tag */
|
|
|
|
static void
|
|
|
|
gst_cmml_enc_parse_end_tag (GstCmmlEnc * enc)
|
|
|
|
{
|
|
|
|
GstBuffer *buffer;
|
|
|
|
|
|
|
|
GST_INFO_OBJECT (enc, "parsing end tag");
|
|
|
|
|
|
|
|
/* push an empty buffer to signal EOS */
|
|
|
|
enc->flow_return = gst_cmml_enc_new_buffer (enc, NULL, 0, &buffer);
|
|
|
|
if (enc->flow_return == GST_FLOW_OK) {
|
|
|
|
/* set granulepos 0 on EOS */
|
|
|
|
GST_BUFFER_OFFSET_END (buffer) = 0;
|
|
|
|
enc->flow_return = gst_cmml_enc_push (enc, buffer);
|
|
|
|
enc->sent_eos = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* encode the CMML head tag and push the CMML headers
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
gst_cmml_enc_parse_tag_head (GstCmmlEnc * enc, GstCmmlTagHead * head)
|
|
|
|
{
|
|
|
|
GList *headers = NULL;
|
|
|
|
GList *walk;
|
|
|
|
guchar *head_string;
|
|
|
|
GstCaps *caps;
|
|
|
|
GstBuffer *ident_buf, *preamble_buf, *head_buf;
|
|
|
|
GstBuffer *buffer;
|
|
|
|
|
|
|
|
if (enc->preamble == NULL)
|
|
|
|
goto flow_unexpected;
|
|
|
|
|
|
|
|
GST_INFO_OBJECT (enc, "parsing head tag");
|
|
|
|
|
|
|
|
enc->flow_return = gst_cmml_enc_new_ident_header (enc, &ident_buf);
|
|
|
|
if (enc->flow_return != GST_FLOW_OK)
|
|
|
|
goto alloc_error;
|
|
|
|
headers = g_list_append (headers, ident_buf);
|
|
|
|
|
|
|
|
enc->flow_return = gst_cmml_enc_new_buffer (enc,
|
|
|
|
enc->preamble, strlen ((gchar *) enc->preamble), &preamble_buf);
|
|
|
|
if (enc->flow_return != GST_FLOW_OK)
|
|
|
|
goto alloc_error;
|
|
|
|
headers = g_list_append (headers, preamble_buf);
|
|
|
|
|
|
|
|
head_string = gst_cmml_parser_tag_head_to_string (enc->parser, head);
|
|
|
|
enc->flow_return = gst_cmml_enc_new_buffer (enc,
|
|
|
|
head_string, strlen ((gchar *) head_string), &head_buf);
|
|
|
|
g_free (head_string);
|
|
|
|
if (enc->flow_return != GST_FLOW_OK)
|
|
|
|
goto alloc_error;
|
|
|
|
headers = g_list_append (headers, head_buf);
|
|
|
|
|
|
|
|
caps = gst_pad_get_caps (enc->srcpad);
|
2006-02-25 19:07:41 +00:00
|
|
|
caps = gst_cmml_enc_set_header_on_caps (enc, caps,
|
2006-02-24 19:07:10 +00:00
|
|
|
ident_buf, preamble_buf, head_buf);
|
|
|
|
|
2006-02-25 19:07:41 +00:00
|
|
|
while (headers) {
|
|
|
|
buffer = GST_BUFFER (headers->data);
|
2006-02-24 19:07:10 +00:00
|
|
|
/* set granulepos 0 on headers */
|
|
|
|
GST_BUFFER_OFFSET_END (buffer) = 0;
|
|
|
|
gst_buffer_set_caps (buffer, caps);
|
|
|
|
|
|
|
|
enc->flow_return = gst_cmml_enc_push (enc, buffer);
|
2006-02-25 19:07:41 +00:00
|
|
|
headers = g_list_delete_link (headers, headers);
|
|
|
|
|
2006-02-24 19:07:10 +00:00
|
|
|
if (GST_FLOW_IS_FATAL (enc->flow_return))
|
|
|
|
goto push_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
gst_caps_unref (caps);
|
|
|
|
|
|
|
|
enc->sent_headers = TRUE;
|
|
|
|
return;
|
|
|
|
|
|
|
|
flow_unexpected:
|
|
|
|
GST_ELEMENT_ERROR (enc, STREAM, ENCODE,
|
|
|
|
(NULL), ("got head tag before preamble"));
|
ext/annodex/gstannodex.c: Do some extra sanity checks.
Original commit message from CVS:
Patch by: Alessandro Decina <alessandro at nnva dot org>
* ext/annodex/gstannodex.c: (gst_annodex_granule_to_time):
Do some extra sanity checks.
Fixes #350340.
* ext/annodex/gstcmmlenc.c: (gst_cmml_enc_change_state),
(gst_cmml_enc_parse_tag_head), (gst_cmml_enc_parse_tag_clip),
(gst_cmml_enc_push_clip), (gst_cmml_enc_push):
Check if clip->start_time is valid before adding the clip to the
track list.
Reset enc->preamble going from PAUSED to READY.
Don't use GST_FLOW_UNEXPECTED for wrong usage of the element, it is
only used for EOS.
Only post an error message if we were the one that created the fatal
GstFlowReturn value.
* ext/annodex/gstcmmlutils.c: (gst_cmml_clock_time_from_npt),
(gst_cmml_clock_time_to_granule), (gst_cmml_track_list_has_clip):
Parse the seconds field of the npt-sec time format using %llu rather than
%d and check that the value scaled by GST_SECOND doesn't overflow.
Use guint64(s) to represent the keyindex and keyoffset fields of a granulepos.
Lookup a clip's track with clip->track rather than clip->id which
makes no sense.
Identify a clip by its track and start time and not its xml id.
do some more input checking and make sure we don't do undefined shifts.
* tests/check/elements/cmmldec.c: (setup_cmmldec),
(teardown_cmmldec), (check_output_buffer_is_equal), (push_data),
(cmml_tag_message_pop), (check_headers), (push_clip_full),
(push_clip), (push_empty_clip), (check_output_clip),
(GST_START_TEST), (cmmldec_suite):
* tests/check/elements/cmmlenc.c: (setup_cmmlenc),
(teardown_cmmlenc), (check_output_buffer_is_equal), (push_data),
(check_headers), (push_clip), (check_clip_times), (check_clip),
(check_empty_clip), (GST_START_TEST), (cmmlenc_suite):
Added some more checks.
2006-08-25 09:42:43 +00:00
|
|
|
enc->flow_return = GST_FLOW_ERROR;
|
2006-02-24 19:07:10 +00:00
|
|
|
return;
|
|
|
|
push_error:
|
|
|
|
gst_caps_unref (caps);
|
|
|
|
/* fallthrough */
|
|
|
|
alloc_error:
|
|
|
|
for (walk = headers; walk; walk = walk->next)
|
|
|
|
gst_buffer_unref (GST_BUFFER (walk->data));
|
|
|
|
g_list_free (headers);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* encode a CMML clip tag
|
|
|
|
* remove the start and end attributes (GstCmmlParser does this itself) and
|
|
|
|
* push the tag with the timestamp of its start attribute. If the tag has the
|
|
|
|
* end attribute, create a new empty clip and encode it.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
gst_cmml_enc_parse_tag_clip (GstCmmlEnc * enc, GstCmmlTagClip * clip)
|
|
|
|
{
|
|
|
|
GstCmmlTagClip *prev_clip;
|
|
|
|
GstClockTime prev_clip_time = GST_CLOCK_TIME_NONE;
|
|
|
|
|
|
|
|
/* this can happen if there's a programming error (eg user forgets to set
|
|
|
|
* the start-time property) or if one of the gst_cmml_clock_time_from_*
|
2006-02-25 19:07:41 +00:00
|
|
|
* overflows in GstCmmlParser */
|
2006-02-24 19:07:10 +00:00
|
|
|
if (clip->start_time == GST_CLOCK_TIME_NONE) {
|
|
|
|
GST_ELEMENT_ERROR (enc, STREAM, ENCODE,
|
|
|
|
(NULL), ("invalid start time for clip (%s)", clip->id));
|
|
|
|
enc->flow_return = GST_FLOW_ERROR;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-02-25 19:07:41 +00:00
|
|
|
/* get the previous clip's start time to encode the current granulepos */
|
2006-02-24 19:07:10 +00:00
|
|
|
prev_clip = gst_cmml_track_list_get_track_last_clip (enc->tracks,
|
|
|
|
(gchar *) clip->track);
|
|
|
|
if (prev_clip) {
|
|
|
|
prev_clip_time = prev_clip->start_time;
|
ext/annodex/gstannodex.c: Do some extra sanity checks.
Original commit message from CVS:
Patch by: Alessandro Decina <alessandro at nnva dot org>
* ext/annodex/gstannodex.c: (gst_annodex_granule_to_time):
Do some extra sanity checks.
Fixes #350340.
* ext/annodex/gstcmmlenc.c: (gst_cmml_enc_change_state),
(gst_cmml_enc_parse_tag_head), (gst_cmml_enc_parse_tag_clip),
(gst_cmml_enc_push_clip), (gst_cmml_enc_push):
Check if clip->start_time is valid before adding the clip to the
track list.
Reset enc->preamble going from PAUSED to READY.
Don't use GST_FLOW_UNEXPECTED for wrong usage of the element, it is
only used for EOS.
Only post an error message if we were the one that created the fatal
GstFlowReturn value.
* ext/annodex/gstcmmlutils.c: (gst_cmml_clock_time_from_npt),
(gst_cmml_clock_time_to_granule), (gst_cmml_track_list_has_clip):
Parse the seconds field of the npt-sec time format using %llu rather than
%d and check that the value scaled by GST_SECOND doesn't overflow.
Use guint64(s) to represent the keyindex and keyoffset fields of a granulepos.
Lookup a clip's track with clip->track rather than clip->id which
makes no sense.
Identify a clip by its track and start time and not its xml id.
do some more input checking and make sure we don't do undefined shifts.
* tests/check/elements/cmmldec.c: (setup_cmmldec),
(teardown_cmmldec), (check_output_buffer_is_equal), (push_data),
(cmml_tag_message_pop), (check_headers), (push_clip_full),
(push_clip), (push_empty_clip), (check_output_clip),
(GST_START_TEST), (cmmldec_suite):
* tests/check/elements/cmmlenc.c: (setup_cmmlenc),
(teardown_cmmlenc), (check_output_buffer_is_equal), (push_data),
(check_headers), (push_clip), (check_clip_times), (check_clip),
(check_empty_clip), (GST_START_TEST), (cmmlenc_suite):
Added some more checks.
2006-08-25 09:42:43 +00:00
|
|
|
if (prev_clip_time > clip->start_time) {
|
|
|
|
GST_ELEMENT_ERROR (enc, STREAM, ENCODE,
|
|
|
|
(NULL), ("previous clip start time > current clip (%s) start time",
|
|
|
|
clip->id));
|
|
|
|
enc->flow_return = GST_FLOW_ERROR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-02-25 19:07:41 +00:00
|
|
|
/* we don't need the prev clip anymore */
|
2006-02-24 19:07:10 +00:00
|
|
|
gst_cmml_track_list_del_clip (enc->tracks, prev_clip);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add the current clip to the tracklist */
|
|
|
|
gst_cmml_track_list_add_clip (enc->tracks, clip);
|
|
|
|
|
|
|
|
enc->flow_return = gst_cmml_enc_push_clip (enc, clip, prev_clip_time);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GstFlowReturn
|
|
|
|
gst_cmml_enc_push_clip (GstCmmlEnc * enc, GstCmmlTagClip * clip,
|
|
|
|
GstClockTime prev_clip_time)
|
|
|
|
{
|
|
|
|
GstFlowReturn res;
|
|
|
|
GstBuffer *buffer;
|
|
|
|
gchar *clip_string;
|
|
|
|
gint64 granulepos;
|
|
|
|
|
|
|
|
/* encode the clip */
|
|
|
|
clip_string =
|
|
|
|
(gchar *) gst_cmml_parser_tag_clip_to_string (enc->parser, clip);
|
|
|
|
|
|
|
|
res = gst_cmml_enc_new_buffer (enc,
|
|
|
|
(guchar *) clip_string, strlen (clip_string), &buffer);
|
|
|
|
g_free (clip_string);
|
|
|
|
if (res != GST_FLOW_OK)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
GST_INFO_OBJECT (enc, "encoding clip"
|
|
|
|
"(start-time: %" GST_TIME_FORMAT " end-time: %" GST_TIME_FORMAT,
|
|
|
|
GST_TIME_ARGS (clip->start_time), GST_TIME_ARGS (clip->end_time));
|
|
|
|
|
|
|
|
/* set the granulepos */
|
|
|
|
granulepos = gst_cmml_clock_time_to_granule (prev_clip_time, clip->start_time,
|
|
|
|
enc->granulerate_n, enc->granulerate_d, enc->granuleshift);
|
2006-02-25 19:36:24 +00:00
|
|
|
if (granulepos == -1) {
|
|
|
|
gst_buffer_unref (buffer);
|
2006-02-25 19:07:41 +00:00
|
|
|
goto granule_overflow;
|
2006-02-25 19:36:24 +00:00
|
|
|
}
|
2006-02-25 19:07:41 +00:00
|
|
|
|
2006-04-28 18:57:09 +00:00
|
|
|
GST_BUFFER_OFFSET (buffer) = clip->start_time;
|
2006-02-24 19:07:10 +00:00
|
|
|
GST_BUFFER_OFFSET_END (buffer) = granulepos;
|
|
|
|
GST_BUFFER_TIMESTAMP (buffer) = clip->start_time;
|
|
|
|
|
|
|
|
res = gst_cmml_enc_push (enc, buffer);
|
|
|
|
if (GST_FLOW_IS_FATAL (res))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
if (clip->end_time != GST_CLOCK_TIME_NONE) {
|
2006-02-25 19:07:41 +00:00
|
|
|
/* create a new empty clip for the same cmml track starting at end_time
|
2006-02-24 19:07:10 +00:00
|
|
|
*/
|
|
|
|
GObject *end_clip = g_object_new (GST_TYPE_CMML_TAG_CLIP,
|
|
|
|
"start-time", clip->end_time, "track", clip->track, NULL);
|
|
|
|
|
|
|
|
/* encode the empty end clip */
|
|
|
|
gst_cmml_enc_push_clip (enc, GST_CMML_TAG_CLIP (end_clip),
|
|
|
|
clip->start_time);
|
|
|
|
g_object_unref (end_clip);
|
|
|
|
}
|
|
|
|
done:
|
|
|
|
return res;
|
2006-02-25 19:07:41 +00:00
|
|
|
|
|
|
|
granule_overflow:
|
|
|
|
GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL), ("granulepos overflow"));
|
|
|
|
return GST_FLOW_ERROR;
|
2006-02-24 19:07:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static GstFlowReturn
|
|
|
|
gst_cmml_enc_push (GstCmmlEnc * enc, GstBuffer * buffer)
|
|
|
|
{
|
|
|
|
GstFlowReturn res;
|
|
|
|
|
|
|
|
/* FIXME: hack to make oggmux flush every cmml tag in its own page */
|
|
|
|
GST_BUFFER_DURATION (buffer) = G_MAXINT64;
|
|
|
|
|
|
|
|
res = gst_pad_push (enc->srcpad, buffer);
|
|
|
|
if (GST_FLOW_IS_FATAL (res))
|
ext/annodex/gstannodex.c: Do some extra sanity checks.
Original commit message from CVS:
Patch by: Alessandro Decina <alessandro at nnva dot org>
* ext/annodex/gstannodex.c: (gst_annodex_granule_to_time):
Do some extra sanity checks.
Fixes #350340.
* ext/annodex/gstcmmlenc.c: (gst_cmml_enc_change_state),
(gst_cmml_enc_parse_tag_head), (gst_cmml_enc_parse_tag_clip),
(gst_cmml_enc_push_clip), (gst_cmml_enc_push):
Check if clip->start_time is valid before adding the clip to the
track list.
Reset enc->preamble going from PAUSED to READY.
Don't use GST_FLOW_UNEXPECTED for wrong usage of the element, it is
only used for EOS.
Only post an error message if we were the one that created the fatal
GstFlowReturn value.
* ext/annodex/gstcmmlutils.c: (gst_cmml_clock_time_from_npt),
(gst_cmml_clock_time_to_granule), (gst_cmml_track_list_has_clip):
Parse the seconds field of the npt-sec time format using %llu rather than
%d and check that the value scaled by GST_SECOND doesn't overflow.
Use guint64(s) to represent the keyindex and keyoffset fields of a granulepos.
Lookup a clip's track with clip->track rather than clip->id which
makes no sense.
Identify a clip by its track and start time and not its xml id.
do some more input checking and make sure we don't do undefined shifts.
* tests/check/elements/cmmldec.c: (setup_cmmldec),
(teardown_cmmldec), (check_output_buffer_is_equal), (push_data),
(cmml_tag_message_pop), (check_headers), (push_clip_full),
(push_clip), (push_empty_clip), (check_output_clip),
(GST_START_TEST), (cmmldec_suite):
* tests/check/elements/cmmlenc.c: (setup_cmmlenc),
(teardown_cmmlenc), (check_output_buffer_is_equal), (push_data),
(check_headers), (push_clip), (check_clip_times), (check_clip),
(check_empty_clip), (GST_START_TEST), (cmmlenc_suite):
Added some more checks.
2006-08-25 09:42:43 +00:00
|
|
|
GST_WARNING_OBJECT (enc, "push returned: %s", gst_flow_get_name (res));
|
2006-02-24 19:07:10 +00:00
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GstFlowReturn
|
|
|
|
gst_cmml_enc_chain (GstPad * pad, GstBuffer * buffer)
|
|
|
|
{
|
|
|
|
GError *err = NULL;
|
|
|
|
GstCmmlEnc *enc = GST_CMML_ENC (GST_PAD_PARENT (pad));
|
|
|
|
|
|
|
|
/* the CMML handlers registered with enc->parser will override this when
|
|
|
|
* encoding/pushing the buffers downstream
|
|
|
|
*/
|
|
|
|
enc->flow_return = GST_FLOW_OK;
|
|
|
|
|
|
|
|
if (!gst_cmml_parser_parse_chunk (enc->parser,
|
|
|
|
(gchar *) GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), &err)) {
|
2009-10-09 10:19:35 +00:00
|
|
|
GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL), ("%s", err->message));
|
2006-02-24 19:07:10 +00:00
|
|
|
g_error_free (err);
|
|
|
|
enc->flow_return = GST_FLOW_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
gst_buffer_unref (buffer);
|
|
|
|
return enc->flow_return;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gst_cmml_enc_plugin_init (GstPlugin * plugin)
|
|
|
|
{
|
|
|
|
if (!gst_element_register (plugin, "cmmlenc", GST_RANK_NONE,
|
|
|
|
GST_TYPE_CMML_ENC))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
GST_DEBUG_CATEGORY_INIT (cmmlenc, "cmmlenc", 0,
|
|
|
|
"annodex cmml decoding element");
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|