From 97d59b66b3cab501546d573db685a9dcd3fde5a2 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 6 Sep 2011 15:40:55 +0200 Subject: [PATCH 01/21] Automatic update of common submodule From 605cd9a to a39eb83 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 605cd9a65e..a39eb835fb 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 605cd9a65ed61505f24b840d3fe8e252be72b151 +Subproject commit a39eb835fb3be2a4c5a6a89b5ca5cc064e79b2e2 From ae8d1227dacffd03e4f94861db5d89c59dcf08b6 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 6 Sep 2011 21:25:13 +0200 Subject: [PATCH 02/21] Automatic update of common submodule From a39eb83 to 11f0cd5 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index a39eb835fb..11f0cd5a3f 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit a39eb835fb3be2a4c5a6a89b5ca5cc064e79b2e2 +Subproject commit 11f0cd5a3fba36f85cf3e434150bfe66b1bf08d4 From d2e0027dca5cdd1c329e8e7492f13ae3ba19fe55 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 7 Sep 2011 14:25:41 +0200 Subject: [PATCH 03/21] docs: cleanup makefiles Remove commented out parts that we don't need. Remove "the wingo addition" - no so useful after all. Narrow down file-globs for plugin docs. --- docs/plugins/Makefile.am | 36 ++++++------------------------------ 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/docs/plugins/Makefile.am b/docs/plugins/Makefile.am index ea7fb3a762..90ed4b5902 100644 --- a/docs/plugins/Makefile.am +++ b/docs/plugins/Makefile.am @@ -13,33 +13,13 @@ FORMATS=html html: html-build.stamp include $(top_srcdir)/common/upload-doc.mak -# generated basefiles -#basefiles = \ -## $(DOC_MODULE).types \ -# $(DOC_MODULE)-sections.txt \ -# $(DOC_MODULE)-docs.sgml - -# ugly hack to make -unused.sgml work -#unused-build.stamp: -# BUILDDIR=`pwd` && \ -# cd $(srcdir)/tmpl && \ -# ln -sf gstreamer-libs-unused.sgml \ -# $$BUILDDIR/tmpl/gstreamer-libs-@GST_MAJORMINOR@-unused.sgml -# touch unused-build.stamp - -# these rules are added to create parallel docs using GST_MAJORMINOR -#$(basefiles): gstreamer-libs-@GST_MAJORMINOR@%: gstreamer-libs% -# cp $< $@ - -#CLEANFILES = $(basefiles) - # The top-level SGML file. Change it if you want. DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml # The directory containing the source code. Relative to $(top_srcdir). # gtk-doc will search all .c & .h files beneath here for inline comments # documenting functions and macros. -DOC_SOURCE_DIR = $(top_srcdir) +DOC_SOURCE_DIR = $(top_srcdir)/gst $(top_srcdir)/ext # Extra options to supply to gtkdoc-scan. SCAN_OPTIONS= @@ -53,14 +33,10 @@ FIXXREF_OPTIONS=--extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html \ --extra-dir=$(GSTPB_PREFIX)/share/gtk-doc/html # Used for dependencies. -HFILE_GLOB=$(DOC_SOURCE_DIR)/*/*/*.h -CFILE_GLOB=$(DOC_SOURCE_DIR)/*/*/*.c $(DOC_SOURCE_DIR)/*/*/*.cc - -# this is a wingo addition -# thomasvs: another nice wingo addition would be an explanation on why -# this is useful ;) - -SCANOBJ_DEPS = +HFILE_GLOB= \ + $(top_srcdir)/gst/*/*.h $(top_srcdir)/ext/*/*.h +CFILE_GLOB= \ + $(top_srcdir)/gst/*/*.c $(top_srcdir)/ext/*/*.c $ $(top_srcdir)/ext/*/*.cc # Header files to ignore when scanning. IGNORE_HFILES = @@ -110,7 +86,7 @@ extra_files = # CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib # contains GtkObjects/GObjects and you want to document signals and properties. GTKDOC_CFLAGS = $(GST_BASE_CFLAGS) -I$(top_builddir) -GTKDOC_LIBS = $(SCANOBJ_DEPS) $(GST_BASE_LIBS) +GTKDOC_LIBS = $(GST_BASE_LIBS) GTKDOC_CC=$(LIBTOOL) --tag=CC --mode=compile $(CC) GTKDOC_LD=$(LIBTOOL) --tag=CC --mode=link $(CC) From e7425b898cf0c7122b66375b9b06258bc9cca9db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 7 Sep 2011 14:36:46 +0200 Subject: [PATCH 04/21] amrnbenc: Use complete raw audio caps in the test --- tests/check/elements/amrnbenc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/check/elements/amrnbenc.c b/tests/check/elements/amrnbenc.c index 5161bd358e..82b938a30c 100644 --- a/tests/check/elements/amrnbenc.c +++ b/tests/check/elements/amrnbenc.c @@ -23,7 +23,7 @@ #include -#define SRC_CAPS "audio/x-raw-int,width=16,depth=16,channels=1,rate=8000" +#define SRC_CAPS "audio/x-raw-int,width=16,depth=16,channels=1,rate=8000,signed=true,endianness=BYTE_ORDER" #define SINK_CAPS "audio/AMR" GList *buffers; From 700d8b1c289ff4488db1359bb1ddaa97234b825c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 8 Sep 2011 14:33:00 +0100 Subject: [PATCH 05/21] rmdemux: delay announcing container tags until we have pads Fixes tags when transcoding. https://bugzilla.gnome.org/show_bug.cgi?id=658297 --- gst/realmedia/rmdemux.c | 18 +++++++++++++++--- gst/realmedia/rmdemux.h | 3 +++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/gst/realmedia/rmdemux.c b/gst/realmedia/rmdemux.c index 56c1f44483..65abd7e4b2 100644 --- a/gst/realmedia/rmdemux.c +++ b/gst/realmedia/rmdemux.c @@ -707,6 +707,11 @@ gst_rmdemux_reset (GstRMDemux * rmdemux) rmdemux->n_audio_streams = 0; rmdemux->n_video_streams = 0; + if (rmdemux->pending_tags != NULL) { + gst_tag_list_free (rmdemux->pending_tags); + rmdemux->pending_tags = NULL; + } + gst_adapter_clear (rmdemux->adapter); rmdemux->state = RMDEMUX_STATE_HEADER; rmdemux->have_pads = FALSE; @@ -1861,9 +1866,11 @@ gst_rmdemux_parse_cont (GstRMDemux * rmdemux, const guint8 * data, int length) GstTagList *tags; tags = gst_rm_utils_read_tags (data, length, gst_rm_utils_read_string16); - if (tags) { - gst_element_found_tags (GST_ELEMENT (rmdemux), tags); - } + + GST_LOG_OBJECT (rmdemux, "tags: %" GST_PTR_FORMAT, tags); + + rmdemux->pending_tags = + gst_tag_list_merge (rmdemux->pending_tags, tags, GST_TAG_MERGE_APPEND); } static GstFlowReturn @@ -2604,6 +2611,11 @@ gst_rmdemux_parse_packet (GstRMDemux * rmdemux, GstBuffer * in, guint16 version) gst_rmdemux_send_event (rmdemux, event); rmdemux->need_newsegment = FALSE; + + if (rmdemux->pending_tags != NULL) { + gst_element_found_tags (GST_ELEMENT (rmdemux), rmdemux->pending_tags); + rmdemux->pending_tags = NULL; + } } if (stream->pending_tags != NULL) { diff --git a/gst/realmedia/rmdemux.h b/gst/realmedia/rmdemux.h index 7a26741c82..eafba04b97 100644 --- a/gst/realmedia/rmdemux.h +++ b/gst/realmedia/rmdemux.h @@ -123,6 +123,9 @@ struct _GstRMDemux { guint32 object_id; guint32 size; guint16 object_version; + + /* container tags for all streams */ + GstTagList *pending_tags; }; struct _GstRMDemuxClass { From eee31aecb32c124c57c3e761722f349f27c78d7f Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Thu, 8 Sep 2011 17:01:27 +0200 Subject: [PATCH 06/21] asfpacket: skip empty payload packets ... which also avoids assertion failures and possible segfaults later on when possibly trying to join 2 empty buffers. --- gst/asfdemux/asfpacket.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/asfdemux/asfpacket.c b/gst/asfdemux/asfpacket.c index b56c81a798..552a559dc3 100644 --- a/gst/asfdemux/asfpacket.c +++ b/gst/asfdemux/asfpacket.c @@ -381,7 +381,8 @@ gst_asf_demux_parse_payload (GstASFDemux * demux, AsfPacket * packet, GST_LOG_OBJECT (demux, "payload length: %u", payload_len); - if ((stream = gst_asf_demux_get_stream (demux, stream_num))) { + if ((stream = gst_asf_demux_get_stream (demux, stream_num)) + && payload_len) { payload.buf = asf_packet_create_payload_buffer (packet, p_data, p_size, payload_len); From 56bd24365aecd05983a9f1d82aa2243b8ff6032a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 15 Aug 2011 16:23:04 +0100 Subject: [PATCH 07/21] mad: remove id3tag dependency used by in practice unreachable legacy code The mad mp3 decoder element shouldn't parse tags at all really, but we have so far kept this code around for backwards-compatibility reasons for people building manual pipelines for some reason. However, as it turns out that code has never actually worked in 0.10 in practice, since it only gets executed if mad_frame_decode() returns LOSTSYNC, which doesn't actually seem to happen any more though because of the preceding mad_header_decode(), which will discover and report the sync loss if it runs into a tag and make mad_frame_decode() try to resync right away. Discovered this while trying to make it use gst_tag_list_from_id3v2_tag(). --- configure.ac | 26 +---- ext/mad/Makefile.am | 4 +- ext/mad/gstmad.c | 233 --------------------------------------- gst-plugins-ugly.spec.in | 1 - 4 files changed, 4 insertions(+), 260 deletions(-) diff --git a/configure.ac b/configure.ac index c9a447f1a8..a740b12403 100644 --- a/configure.ac +++ b/configure.ac @@ -312,38 +312,16 @@ dnl *** mad *** translit(dnm, m, l) AM_CONDITIONAL(USE_MAD, true) AG_GST_CHECK_FEATURE(MAD, [mad mp3 decoder], mad, [ - dnl check with pkg-config first - AG_GST_PKG_CHECK_MODULES(ID3TAG, id3tag >= 0.15) - if test "x$HAVE_ID3TAG" = "xno"; then - dnl fall back to oldskool detection - AC_CHECK_HEADER(id3tag.h, [ - save_LIBS=$LIBS - LIBS="-lz" - AC_CHECK_LIB(id3tag, id3_tag_options, - HAVE_ID3TAG="yes" ID3TAG_LIBS="-lid3tag -lz") - LIBS=$save_LIBS - AC_SUBST(ID3TAG_LIBS) - ]) - fi - dnl check with pkg-config first AG_GST_PKG_CHECK_MODULES(MAD, mad >= 0.15) - MAD_LIBS="$MAD_LIBS $ID3TAG_LIBS" + MAD_LIBS="$MAD_LIBS" if test "x$HAVE_MAD" = "xno"; then dnl fall back to oldskool detection AC_CHECK_HEADER(mad.h, [ AC_CHECK_LIB(mad, mad_decoder_finish, - HAVE_MAD="yes" MAD_LIBS="-lmad $ID3TAG_LIBS") + HAVE_MAD="yes" MAD_LIBS="-lmad") ]) fi - - if test "x$HAVE_ID3TAG" = "xyes"; then - AC_DEFINE(HAVE_ID3TAG, 1, [defined if libid3tag is available]) - else - AC_MSG_WARN([libid3tag not available, MAD MP3 decoder will be built without - ID3 tag reading support (which is not a problem, since ID3 - tags are usually handled by id3demux)]) - fi ]) AC_SUBST(MAD_LIBS) diff --git a/ext/mad/Makefile.am b/ext/mad/Makefile.am index 8923456eee..85a22ff51d 100644 --- a/ext/mad/Makefile.am +++ b/ext/mad/Makefile.am @@ -4,10 +4,10 @@ libgstmad_la_SOURCES = gstmad.c libgstmad_la_CFLAGS = \ $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \ - $(MAD_CFLAGS) $(ID3TAG_CFLAGS) + $(MAD_CFLAGS) libgstmad_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) \ - -lgstaudio-$(GST_MAJORMINOR) $(MAD_LIBS) $(ID3TAG_LIBS) + -lgstaudio-$(GST_MAJORMINOR) $(MAD_LIBS) libgstmad_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstmad_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/ext/mad/gstmad.c b/ext/mad/gstmad.c index f066b670b5..bdc4fc6e9b 100644 --- a/ext/mad/gstmad.c +++ b/ext/mad/gstmad.c @@ -40,10 +40,6 @@ #include "gstmad.h" #include -#ifdef HAVE_ID3TAG -#include -#endif - enum { ARG_0, @@ -107,10 +103,6 @@ static GstStateChangeReturn gst_mad_change_state (GstElement * element, static void gst_mad_set_index (GstElement * element, GstIndex * index); static GstIndex *gst_mad_get_index (GstElement * element); -#ifdef HAVE_ID3TAG -static GstTagList *gst_mad_id3_to_tag_list (const struct id3_tag *tag); -#endif - GST_BOILERPLATE (GstMad, gst_mad, GstElement, GST_TYPE_ELEMENT); /* @@ -1534,53 +1526,6 @@ gst_mad_chain (GstPad * pad, GstBuffer * buffer) } else if (mad->stream.error == MAD_ERROR_LOSTSYNC) { /* lost sync, force a resync */ GST_INFO ("recoverable lost sync error"); - -#ifdef HAVE_ID3TAG - { - signed long tagsize; - - tagsize = id3_tag_query (mad->stream.this_frame, - mad->stream.bufend - mad->stream.this_frame); - - if (tagsize > mad->tempsize) { - GST_INFO ("mad: got partial id3 tag in buffer, skipping"); - } else if (tagsize > 0) { - struct id3_tag *tag; - id3_byte_t const *data; - - GST_INFO ("mad: got ID3 tag size %ld", tagsize); - - data = mad->stream.this_frame; - - /* mad has moved the pointer to the next frame over the start of the - * id3 tags, so we need to flush one byte less than the tagsize */ - mad_stream_skip (&mad->stream, tagsize - 1); - - tag = id3_tag_parse (data, tagsize); - if (tag) { - GstTagList *list; - - list = gst_mad_id3_to_tag_list (tag); - id3_tag_delete (tag); - GST_DEBUG ("found tag"); - gst_element_post_message (GST_ELEMENT (mad), - gst_message_new_tag (GST_OBJECT (mad), - gst_tag_list_copy (list))); - if (mad->tags) { - gst_tag_list_insert (mad->tags, list, GST_TAG_MERGE_PREPEND); - } else { - mad->tags = gst_tag_list_copy (list); - } - if (mad->need_newsegment) - mad->pending_events = - g_list_append (mad->pending_events, - gst_event_new_tag (list)); - else - gst_pad_push_event (mad->srcpad, gst_event_new_tag (list)); - } - } - } -#endif /* HAVE_ID3TAG */ } mad_frame_mute (&mad->frame); @@ -1925,184 +1870,6 @@ gst_mad_change_state (GstElement * element, GstStateChange transition) return ret; } -#ifdef HAVE_ID3TAG -/* id3 tag helper (FIXME: why does mad parse id3 tags at all? It shouldn't) */ -static GstTagList * -gst_mad_id3_to_tag_list (const struct id3_tag *tag) -{ - const struct id3_frame *frame; - const id3_ucs4_t *ucs4; - id3_utf8_t *utf8; - GstTagList *tag_list; - GType tag_type; - guint i = 0; - - tag_list = gst_tag_list_new (); - - while ((frame = id3_tag_findframe (tag, NULL, i++)) != NULL) { - const union id3_field *field; - unsigned int nstrings, j; - const gchar *tag_name; - - /* find me the function to query the frame id */ - gchar *id = g_strndup (frame->id, 5); - - tag_name = gst_tag_from_id3_tag (id); - if (tag_name == NULL) { - g_free (id); - continue; - } - - if (strcmp (id, "COMM") == 0) { - if (frame->nfields < 4) - continue; - - ucs4 = id3_field_getfullstring (&frame->fields[3]); - g_assert (ucs4); - - utf8 = id3_ucs4_utf8duplicate (ucs4); - if (utf8 == 0) - continue; - - if (!g_utf8_validate ((char *) utf8, -1, NULL)) { - GST_ERROR ("converted string is not valid utf-8"); - g_free (utf8); - continue; - } - - gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND, - GST_TAG_COMMENT, utf8, NULL); - - g_free (utf8); - continue; - } - - if (frame->nfields < 2) - continue; - - field = &frame->fields[1]; - nstrings = id3_field_getnstrings (field); - - for (j = 0; j < nstrings; ++j) { - ucs4 = id3_field_getstrings (field, j); - g_assert (ucs4); - - if (strcmp (id, ID3_FRAME_GENRE) == 0) - ucs4 = id3_genre_name (ucs4); - - utf8 = id3_ucs4_utf8duplicate (ucs4); - if (utf8 == 0) - continue; - - if (!g_utf8_validate ((char *) utf8, -1, NULL)) { - GST_ERROR ("converted string is not valid utf-8"); - free (utf8); - continue; - } - - tag_type = gst_tag_get_type (tag_name); - - /* be sure to add non-string tags here */ - switch (tag_type) { - case G_TYPE_UINT: - { - guint tmp; - gchar *check; - - tmp = strtoul ((char *) utf8, &check, 10); - - if (strcmp (tag_name, GST_TAG_DATE) == 0) { - GDate *d; - - if (*check != '\0') - break; - if (tmp == 0) - break; - d = g_date_new_dmy (1, 1, tmp); - tmp = g_date_get_julian (d); - g_date_free (d); - } else if (strcmp (tag_name, GST_TAG_TRACK_NUMBER) == 0) { - if (*check == '/') { - guint total; - - check++; - total = strtoul (check, &check, 10); - if (*check != '\0') - break; - - gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND, - GST_TAG_TRACK_COUNT, total, NULL); - } - } else if (strcmp (tag_name, GST_TAG_ALBUM_VOLUME_NUMBER) == 0) { - if (*check == '/') { - guint total; - - check++; - total = strtoul (check, &check, 10); - if (*check != '\0') - break; - - gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND, - GST_TAG_ALBUM_VOLUME_COUNT, total, NULL); - } - } - - if (*check != '\0') - break; - gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND, tag_name, tmp, - NULL); - break; - } - case G_TYPE_UINT64: - { - guint64 tmp; - - g_assert (strcmp (tag_name, GST_TAG_DURATION) == 0); - tmp = strtoul ((char *) utf8, NULL, 10); - if (tmp == 0) { - break; - } - gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND, - GST_TAG_DURATION, tmp * 1000 * 1000, NULL); - break; - } - case G_TYPE_STRING:{ - gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND, - tag_name, (const gchar *) utf8, NULL); - break; - } - /* handles GST_TYPE_DATE and anything else */ - default:{ - GValue src = { 0, }; - GValue dest = { 0, }; - - g_value_init (&src, G_TYPE_STRING); - g_value_set_string (&src, (const gchar *) utf8); - - g_value_init (&dest, tag_type); - if (g_value_transform (&src, &dest)) { - gst_tag_list_add_values (tag_list, GST_TAG_MERGE_APPEND, - tag_name, &dest, NULL); - } else { - GST_WARNING ("Failed to transform tag from string to type '%s'", - g_type_name (tag_type)); - } - g_value_unset (&src); - g_value_unset (&dest); - break; - } - } - free (utf8); - } - g_free (id); - } - - return tag_list; -} -#endif /* HAVE_ID3TAG */ - -/* plugin initialisation */ - static gboolean plugin_init (GstPlugin * plugin) { diff --git a/gst-plugins-ugly.spec.in b/gst-plugins-ugly.spec.in index 6c3c302810..20a9f53eaf 100644 --- a/gst-plugins-ugly.spec.in +++ b/gst-plugins-ugly.spec.in @@ -23,7 +23,6 @@ BuildRequires: gcc-c++ @USE_A52DEC_TRUE@BuildRequires: a52dec-devel >= 0.7.3 @USE_DVDREAD_TRUE@BuildRequires: libdvdread-devel >= 0.9.0 @USE_LAME_TRUE@BuildRequires: lame-devel >= 3.89 -@USE_MAD_TRUE@BuildRequires: libid3tag-devel >= 0.15.0 @USE_MAD_TRUE@BuildRequires: libmad-devel >= 0.15.0 @USE_MPEG2DEC_TRUE@BuildRequires: mpeg2dec-devel >= 0.4.0 From 20464efc8ea14d12862720171491a4d7ff550caf Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Fri, 16 Sep 2011 13:42:53 +0100 Subject: [PATCH 08/21] dvdreadsrc: fix sector search for packed titles Some DVD titles are packed in a single set, and we need to use the correct table to map times to sectors. https://bugzilla.gnome.org/show_bug.cgi?id=659252 --- ext/dvdread/dvdreadsrc.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/ext/dvdread/dvdreadsrc.c b/ext/dvdread/dvdreadsrc.c index a46ee4cf6f..a53019f9fd 100644 --- a/ext/dvdread/dvdreadsrc.c +++ b/ext/dvdread/dvdreadsrc.c @@ -682,23 +682,21 @@ gst_dvd_read_src_get_time_for_sector (GstDvdReadSrc * src, guint sector) static gint gst_dvd_read_src_get_sector_from_time (GstDvdReadSrc * src, GstClockTime ts) { - gint sector, i, j; + gint sector, j; - if (src->vts_tmapt == NULL || src->vts_tmapt->nr_of_tmaps == 0) + if (src->vts_tmapt == NULL || src->vts_tmapt->nr_of_tmaps < src->ttn) return -1; sector = 0; - for (i = 0; i < src->vts_tmapt->nr_of_tmaps; ++i) { - for (j = 0; j < src->vts_tmapt->tmap[i].nr_of_entries; ++j) { - GstClockTime entry_time; + for (j = 0; j < src->vts_tmapt->tmap[src->ttn - 1].nr_of_entries; ++j) { + GstClockTime entry_time; - entry_time = src->vts_tmapt->tmap[i].tmu * (j + 1) * GST_SECOND; - if (entry_time <= ts) { - sector = src->vts_tmapt->tmap[i].map_ent[j] & 0x7fffffff; - } - if (entry_time >= ts) { - return sector; - } + entry_time = src->vts_tmapt->tmap[src->ttn - 1].tmu * (j + 1) * GST_SECOND; + if (entry_time <= ts) { + sector = src->vts_tmapt->tmap[src->ttn - 1].map_ent[j] & 0x7fffffff; + } + if (entry_time >= ts) { + return sector; } } From 59ed3b7bf2898adba62bf71148135b3584f16289 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Fri, 16 Sep 2011 15:03:54 +0100 Subject: [PATCH 09/21] dvdreadsrc: fix sector seeking It was overly complicated, and did not take into account the offset needed for titles which do not start on a new file. https://bugzilla.gnome.org/show_bug.cgi?id=659252 --- ext/dvdread/dvdreadsrc.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/ext/dvdread/dvdreadsrc.c b/ext/dvdread/dvdreadsrc.c index a53019f9fd..ba36bec0e2 100644 --- a/ext/dvdread/dvdreadsrc.c +++ b/ext/dvdread/dvdreadsrc.c @@ -1545,25 +1545,27 @@ static gboolean gst_dvd_read_src_goto_sector (GstDvdReadSrc * src, int angle) { gint seek_to = src->cur_pack; - gint chapter, sectors, next, cur, i; + gint chapter, next, cur, i; /* retrieve position */ src->cur_pack = 0; + GST_DEBUG_OBJECT (src, "Goto sector %d, angle %d, within %d chapters", + seek_to, angle, src->num_chapters); + for (i = 0; i < src->num_chapters; i++) { gint c1, c2; cur_title_get_chapter_bounds (src, i, &c1, &c2); + GST_DEBUG_OBJECT (src, " Looking in chapter %d, bounds: %d %d", i, c1, c2); for (next = cur = c1; cur < c2;) { - if (next != cur) { - sectors = - src->cur_pgc->cell_playback[cur].last_sector - - src->cur_pgc->cell_playback[cur].first_sector; - if (src->cur_pack + sectors > seek_to) { - chapter = i; - goto done; - } - src->cur_pack += sectors; + gint first = src->cur_pgc->cell_playback[cur].first_sector; + gint last = src->cur_pgc->cell_playback[cur].last_sector; + GST_DEBUG_OBJECT (src, "Cell %d sector bounds: %d %d", cur, first, last); + if (seek_to >= first && seek_to <= last) { + GST_DEBUG_OBJECT (src, "Seek target found in chapter %d", i); + chapter = i; + goto done; } cur = next; if (src->cur_pgc->cell_playback[cur].block_type == BLOCK_TYPE_ANGLE_BLOCK) From 40274ad92fe98900dc128b2a76b5c0f10c48d26b Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Fri, 16 Sep 2011 15:35:06 +0100 Subject: [PATCH 10/21] dvdreadsrc: take into account first sector of the current title This fixes seeking on titles which do not start on a new file. https://bugzilla.gnome.org/show_bug.cgi?id=659252 --- ext/dvdread/dvdreadsrc.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ext/dvdread/dvdreadsrc.c b/ext/dvdread/dvdreadsrc.c index ba36bec0e2..1096de693b 100644 --- a/ext/dvdread/dvdreadsrc.c +++ b/ext/dvdread/dvdreadsrc.c @@ -1183,6 +1183,17 @@ gst_dvd_read_src_handle_seek_event (GstDvdReadSrc * src, GstEvent * event) return GST_BASE_SRC_CLASS (parent_class)->event (GST_BASE_SRC (src), event); } +static void +gst_dvd_read_src_get_sector_bounds (GstDvdReadSrc * src, gint * first, + gint * last) +{ + gint c1, c2, tmp; + cur_title_get_chapter_bounds (src, 0, &c1, &tmp); + cur_title_get_chapter_bounds (src, src->num_chapters - 1, &tmp, &c2); + *first = src->cur_pgc->cell_playback[c1].first_sector; + *last = src->cur_pgc->cell_playback[c2].last_sector; +} + static gboolean gst_dvd_read_src_do_seek (GstBaseSrc * basesrc, GstSegment * s) { @@ -1200,9 +1211,17 @@ gst_dvd_read_src_do_seek (GstBaseSrc * basesrc, GstSegment * s) old = src->cur_pack; if (s->format == sector_format) { + gint first, last; + gst_dvd_read_src_get_sector_bounds (src, &first, &last); + GST_DEBUG_OBJECT (src, "Format is sector, seeking to %d", s->last_stop); src->cur_pack = s->last_stop; + if (src->cur_pack < first) + src->cur_pack = first; + if (src->cur_pack > last) + src->cur_pack = last; } else if (s->format == GST_FORMAT_TIME) { gint sector; + GST_DEBUG_OBJECT (src, "Format is time"); sector = gst_dvd_read_src_get_sector_from_time (src, s->last_stop); @@ -1215,12 +1234,16 @@ gst_dvd_read_src_do_seek (GstBaseSrc * basesrc, GstSegment * s) src->cur_pack = sector; } else { /* byte format */ + gint first, last; + gst_dvd_read_src_get_sector_bounds (src, &first, &last); + GST_DEBUG_OBJECT (src, "Format is byte"); src->cur_pack = s->last_stop / DVD_VIDEO_LB_LEN; if (((gint64) src->cur_pack * DVD_VIDEO_LB_LEN) != s->last_stop) { GST_LOG_OBJECT (src, "rounded down offset %" G_GINT64_FORMAT " => %" G_GINT64_FORMAT, s->last_stop, (gint64) src->cur_pack * DVD_VIDEO_LB_LEN); } + src->cur_pack += first; } if (!gst_dvd_read_src_goto_sector (src, src->angle)) { From 2bfec2cccc16d6b14728d2fbd5de855d62398df5 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 26 Sep 2011 14:44:01 +0200 Subject: [PATCH 11/21] lamemp3enc: port to audioencoder --- ext/lame/Makefile.am | 6 +- ext/lame/gstlamemp3enc.c | 514 +++++++++------------------------------ ext/lame/gstlamemp3enc.h | 19 +- 3 files changed, 119 insertions(+), 420 deletions(-) diff --git a/ext/lame/Makefile.am b/ext/lame/Makefile.am index 4d83abaf3b..439a621dab 100644 --- a/ext/lame/Makefile.am +++ b/ext/lame/Makefile.am @@ -1,8 +1,10 @@ plugin_LTLIBRARIES = libgstlame.la libgstlame_la_SOURCES = gstlame.c gstlamemp3enc.c plugin.c -libgstlame_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(LAME_CFLAGS) -libgstlame_la_LIBADD = $(LAME_LIBS) $(GST_PLUGINS_BASE_LIBS) -lgstpbutils-@GST_MAJORMINOR@ $(GST_LIBS) +libgstlame_la_CFLAGS = -DGST_USE_UNSTABLE_API \ + $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(LAME_CFLAGS) +libgstlame_la_LIBADD = $(LAME_LIBS) $(GST_PLUGINS_BASE_LIBS) \ + -lgstaudio-$(GST_MAJORMINOR) $(GST_LIBS) libgstlame_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstlame_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/ext/lame/gstlamemp3enc.c b/ext/lame/gstlamemp3enc.c index c80ec8bc95..6b1a0d1dc1 100644 --- a/ext/lame/gstlamemp3enc.c +++ b/ext/lame/gstlamemp3enc.c @@ -68,8 +68,6 @@ #include "gstlamemp3enc.h" #include -#include - /* lame < 3.98 */ #ifndef HAVE_LAME_SET_VBR_QUALITY #define lame_set_VBR_quality(flags,q) lame_set_VBR_q((flags),(int)(q)) @@ -182,15 +180,19 @@ static void gst_lamemp3enc_base_init (gpointer g_class); static void gst_lamemp3enc_class_init (GstLameMP3EncClass * klass); static void gst_lamemp3enc_init (GstLameMP3Enc * gst_lame); +static gboolean gst_lamemp3enc_start (GstAudioEncoder * enc); +static gboolean gst_lamemp3enc_stop (GstAudioEncoder * enc); +static gboolean gst_lamemp3enc_set_format (GstAudioEncoder * enc, + GstAudioInfo * info); +static GstFlowReturn gst_lamemp3enc_handle_frame (GstAudioEncoder * enc, + GstBuffer * in_buf); +static void gst_lamemp3enc_flush (GstAudioEncoder * enc); + static void gst_lamemp3enc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_lamemp3enc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static gboolean gst_lamemp3enc_sink_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_lamemp3enc_chain (GstPad * pad, GstBuffer * buf); static gboolean gst_lamemp3enc_setup (GstLameMP3Enc * lame, GstTagList ** tags); -static GstStateChangeReturn gst_lamemp3enc_change_state (GstElement * element, - GstStateChange transition); static GstElementClass *parent_class = NULL; @@ -211,17 +213,10 @@ gst_lamemp3enc_get_type (void) 0, (GInstanceInitFunc) gst_lamemp3enc_init, }; - static const GInterfaceInfo preset_info = { - NULL, - NULL, - NULL - }; gst_lamemp3enc_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstLameMP3Enc", + g_type_register_static (GST_TYPE_AUDIO_ENCODER, "GstLameMP3Enc", &gst_lamemp3enc_info, 0); - g_type_add_interface_static (gst_lamemp3enc_type, GST_TYPE_PRESET, - &preset_info); } return gst_lamemp3enc_type; } @@ -263,9 +258,11 @@ gst_lamemp3enc_class_init (GstLameMP3EncClass * klass) { GObjectClass *gobject_class; GstElementClass *gstelement_class; + GstAudioEncoderClass *base_class; gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; + base_class = (GstAudioEncoderClass *) klass; parent_class = g_type_class_peek_parent (klass); @@ -273,64 +270,89 @@ gst_lamemp3enc_class_init (GstLameMP3EncClass * klass) gobject_class->get_property = gst_lamemp3enc_get_property; gobject_class->finalize = gst_lamemp3enc_finalize; + base_class->start = GST_DEBUG_FUNCPTR (gst_lamemp3enc_start); + base_class->stop = GST_DEBUG_FUNCPTR (gst_lamemp3enc_stop); + base_class->set_format = GST_DEBUG_FUNCPTR (gst_lamemp3enc_set_format); + base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_lamemp3enc_handle_frame); + base_class->flush = GST_DEBUG_FUNCPTR (gst_lamemp3enc_flush); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TARGET, g_param_spec_enum ("target", "Target", "Optimize for quality or bitrate", GST_TYPE_LAMEMP3ENC_TARGET, - DEFAULT_TARGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + DEFAULT_TARGET, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE, g_param_spec_int ("bitrate", "Bitrate (kb/s)", "Bitrate in kbit/sec (Only valid if target is bitrate, for CBR one " "of 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, " "256 or 320)", 8, 320, DEFAULT_BITRATE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CBR, g_param_spec_boolean ("cbr", "CBR", "Enforce constant bitrate encoding " "(Only valid if target is bitrate)", DEFAULT_CBR, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY, g_param_spec_float ("quality", "Quality", "VBR Quality from 0 to 10, 0 being the best " "(Only valid if target is quality)", 0.0, 9.999, - DEFAULT_QUALITY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + DEFAULT_QUALITY, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ENCODING_ENGINE_QUALITY, g_param_spec_enum ("encoding-engine-quality", "Encoding Engine Quality", "Quality/speed of the encoding engine, " "this does not affect the bitrate!", GST_TYPE_LAMEMP3ENC_ENCODING_ENGINE_QUALITY, DEFAULT_ENCODING_ENGINE_QUALITY, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MONO, g_param_spec_boolean ("mono", "Mono", "Enforce mono encoding", - DEFAULT_MONO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + DEFAULT_MONO, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_lamemp3enc_change_state); +static void +gst_lamemp3enc_init (GstLameMP3Enc * lame) +{ } static gboolean -gst_lamemp3enc_src_setcaps (GstPad * pad, GstCaps * caps) +gst_lamemp3enc_start (GstAudioEncoder * enc) { - GST_DEBUG_OBJECT (pad, "caps: %" GST_PTR_FORMAT, caps); + GstLameMP3Enc *lame = GST_LAMEMP3ENC (enc); + + GST_DEBUG_OBJECT (lame, "start"); return TRUE; } static gboolean -gst_lamemp3enc_sink_setcaps (GstPad * pad, GstCaps * caps) +gst_lamemp3enc_stop (GstAudioEncoder * enc) +{ + GstLameMP3Enc *lame = GST_LAMEMP3ENC (enc); + + GST_DEBUG_OBJECT (lame, "stop"); + + gst_lamemp3enc_release_memory (lame); + return TRUE; +} + +static gboolean +gst_lamemp3enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info) { GstLameMP3Enc *lame; gint out_samplerate; gint version; - GstStructure *structure; GstCaps *othercaps; + GstClockTime latency; GstTagList *tags = NULL; - lame = GST_LAMEMP3ENC (GST_PAD_PARENT (pad)); - structure = gst_caps_get_structure (caps, 0); + lame = GST_LAMEMP3ENC (enc); - if (!gst_structure_get_int (structure, "rate", &lame->samplerate)) - goto no_rate; - if (!gst_structure_get_int (structure, "channels", &lame->num_channels)) - goto no_channels; + /* parameters already parsed for us */ + lame->samplerate = GST_AUDIO_INFO_RATE (info); + lame->num_channels = GST_AUDIO_INFO_CHANNELS (info); + + /* but we might be asked to reconfigure, so reset */ + gst_lamemp3enc_release_memory (lame); GST_DEBUG_OBJECT (lame, "setting up lame"); if (!gst_lamemp3enc_setup (lame, &tags)) @@ -362,39 +384,27 @@ gst_lamemp3enc_sink_setcaps (GstPad * pad, GstCaps * caps) "rate", G_TYPE_INT, out_samplerate, NULL); /* and use these caps */ - gst_pad_set_caps (lame->srcpad, othercaps); - - if (tags) { - gst_pb_utils_add_codec_description_to_tag_list (tags, GST_TAG_CODEC, - othercaps); - gst_pb_utils_add_codec_description_to_tag_list (tags, GST_TAG_AUDIO_CODEC, - othercaps); - } - + gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), othercaps); gst_caps_unref (othercaps); + /* base class feedback: + * - we will handle buffers, just hand us all available + * - report latency */ + latency = gst_util_uint64_scale_int (lame_get_framesize (lame->lgf), + GST_SECOND, lame->samplerate); + gst_audio_encoder_set_latency (enc, latency, latency); + if (tags) - gst_element_found_tags_for_pad (GST_ELEMENT_CAST (lame), lame->srcpad, - tags); + gst_audio_encoder_merge_tags (enc, tags, GST_TAG_MERGE_REPLACE); return TRUE; -no_rate: - { - GST_ERROR_OBJECT (lame, "input caps have no sample rate field"); - return FALSE; - } -no_channels: - { - GST_ERROR_OBJECT (lame, "input caps have no channels field"); - return FALSE; - } zero_output_rate: { - GST_ELEMENT_ERROR (lame, LIBRARY, SETTINGS, (NULL), - ("LAMEMP3ENC decided on a zero sample rate")); if (tags) gst_tag_list_free (tags); + GST_ELEMENT_ERROR (lame, LIBRARY, SETTINGS, (NULL), + ("LAMEMP3ENC decided on a zero sample rate")); return FALSE; } setup_failed: @@ -405,152 +415,6 @@ setup_failed: } } -static GstCaps * -gst_lamemp3enc_sink_getcaps (GstPad * pad) -{ - const GstCaps *templ_caps; - GstLameMP3Enc *lame; - GstCaps *allowed = NULL; - GstCaps *caps, *filter_caps; - gint i, j; - - lame = GST_LAMEMP3ENC (gst_pad_get_parent (pad)); - - /* we want to be able to communicate to upstream elements like audioconvert - * and audioresample any rate/channel restrictions downstream (e.g. muxer - * only accepting certain sample rates) */ - templ_caps = gst_pad_get_pad_template_caps (pad); - allowed = gst_pad_get_allowed_caps (lame->srcpad); - if (!allowed || gst_caps_is_empty (allowed) || gst_caps_is_any (allowed)) { - caps = gst_caps_copy (templ_caps); - goto done; - } - - filter_caps = gst_caps_new_empty (); - - for (i = 0; i < gst_caps_get_size (templ_caps); i++) { - GQuark q_name; - - q_name = gst_structure_get_name_id (gst_caps_get_structure (templ_caps, i)); - - /* pick rate + channel fields from allowed caps */ - for (j = 0; j < gst_caps_get_size (allowed); j++) { - const GstStructure *allowed_s = gst_caps_get_structure (allowed, j); - const GValue *val; - GstStructure *s; - - s = gst_structure_id_empty_new (q_name); - if ((val = gst_structure_get_value (allowed_s, "rate"))) - gst_structure_set_value (s, "rate", val); - if ((val = gst_structure_get_value (allowed_s, "channels"))) - gst_structure_set_value (s, "channels", val); - - gst_caps_merge_structure (filter_caps, s); - } - } - - caps = gst_caps_intersect (filter_caps, templ_caps); - gst_caps_unref (filter_caps); - -done: - - gst_caps_replace (&allowed, NULL); - gst_object_unref (lame); - - return caps; -} - -static gint64 -gst_lamemp3enc_get_latency (GstLameMP3Enc * lame) -{ - return gst_util_uint64_scale_int (lame_get_framesize (lame->lgf), - GST_SECOND, lame->samplerate); -} - -static gboolean -gst_lamemp3enc_src_query (GstPad * pad, GstQuery * query) -{ - gboolean res = TRUE; - GstLameMP3Enc *lame; - GstPad *peerpad; - - lame = GST_LAMEMP3ENC (gst_pad_get_parent (pad)); - peerpad = gst_pad_get_peer (GST_PAD (lame->sinkpad)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_LATENCY: - { - if ((res = gst_pad_query (peerpad, query))) { - gboolean live; - GstClockTime min_latency, max_latency; - gint64 latency; - - if (lame->lgf == NULL) - break; - - gst_query_parse_latency (query, &live, &min_latency, &max_latency); - - latency = gst_lamemp3enc_get_latency (lame); - - /* add our latency */ - min_latency += latency; - if (max_latency != -1) - max_latency += latency; - - gst_query_set_latency (query, live, min_latency, max_latency); - } - break; - } - default: - res = gst_pad_query (peerpad, query); - break; - } - - gst_object_unref (peerpad); - gst_object_unref (lame); - return res; -} - -static void -gst_lamemp3enc_init (GstLameMP3Enc * lame) -{ - GST_DEBUG_OBJECT (lame, "starting initialization"); - - lame->sinkpad = - gst_pad_new_from_static_template (&gst_lamemp3enc_sink_template, "sink"); - gst_pad_set_event_function (lame->sinkpad, - GST_DEBUG_FUNCPTR (gst_lamemp3enc_sink_event)); - gst_pad_set_chain_function (lame->sinkpad, - GST_DEBUG_FUNCPTR (gst_lamemp3enc_chain)); - gst_pad_set_setcaps_function (lame->sinkpad, - GST_DEBUG_FUNCPTR (gst_lamemp3enc_sink_setcaps)); - gst_pad_set_getcaps_function (lame->sinkpad, - GST_DEBUG_FUNCPTR (gst_lamemp3enc_sink_getcaps)); - gst_element_add_pad (GST_ELEMENT (lame), lame->sinkpad); - - lame->srcpad = - gst_pad_new_from_static_template (&gst_lamemp3enc_src_template, "src"); - gst_pad_set_query_function (lame->srcpad, - GST_DEBUG_FUNCPTR (gst_lamemp3enc_src_query)); - gst_pad_set_setcaps_function (lame->srcpad, - GST_DEBUG_FUNCPTR (gst_lamemp3enc_src_setcaps)); - gst_element_add_pad (GST_ELEMENT (lame), lame->srcpad); - - lame->samplerate = 44100; - lame->num_channels = 2; - lame->setup = FALSE; - - /* Set default settings */ - lame->target = DEFAULT_TARGET; - lame->bitrate = DEFAULT_BITRATE; - lame->cbr = DEFAULT_CBR; - lame->quality = DEFAULT_QUALITY; - lame->encoding_engine_quality = DEFAULT_ENCODING_ENGINE_QUALITY; - lame->mono = DEFAULT_MONO; - - GST_DEBUG_OBJECT (lame, "done initializing"); -} - /* three underscores for ___rate is really really really * private as opposed to one underscore */ /* call this MACRO outside of the NULL state so that we have a higher chance @@ -654,128 +518,64 @@ gst_lamemp3enc_get_property (GObject * object, guint prop_id, GValue * value, } } -static gboolean -gst_lamemp3enc_sink_event (GstPad * pad, GstEvent * event) +static GstFlowReturn +gst_lamemp3enc_flush_full (GstLameMP3Enc * lame, gboolean push) { - gboolean ret; - GstLameMP3Enc *lame; + GstBuffer *buf; + gint size; + GstFlowReturn result = GST_FLOW_OK; - lame = GST_LAMEMP3ENC (gst_pad_get_parent (pad)); + if (!lame->lgf) + return GST_FLOW_OK; - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS:{ - GST_DEBUG_OBJECT (lame, "handling EOS event"); + buf = gst_buffer_new_and_alloc (7200); + size = lame_encode_flush (lame->lgf, GST_BUFFER_DATA (buf), 7200); - if (lame->lgf != NULL) { - GstBuffer *buf; - gint size; - - buf = gst_buffer_new_and_alloc (7200); - size = lame_encode_flush (lame->lgf, GST_BUFFER_DATA (buf), 7200); - - if (size > 0 && lame->last_flow == GST_FLOW_OK) { - gint64 duration; - - duration = gst_util_uint64_scale (size, 8 * GST_SECOND, - 1000 * lame->bitrate); - - if (lame->last_ts == GST_CLOCK_TIME_NONE) { - lame->last_ts = lame->eos_ts; - lame->last_duration = duration; - } else { - lame->last_duration += duration; - } - - GST_BUFFER_TIMESTAMP (buf) = lame->last_ts; - GST_BUFFER_DURATION (buf) = lame->last_duration; - lame->last_ts = GST_CLOCK_TIME_NONE; - GST_BUFFER_SIZE (buf) = size; - GST_DEBUG_OBJECT (lame, "pushing final packet of %u bytes", size); - gst_buffer_set_caps (buf, GST_PAD_CAPS (lame->srcpad)); - gst_pad_push (lame->srcpad, buf); - } else { - GST_DEBUG_OBJECT (lame, "no final packet (size=%d, last_flow=%s)", - size, gst_flow_get_name (lame->last_flow)); - gst_buffer_unref (buf); - } - } - - ret = gst_pad_event_default (pad, event); - break; - } - case GST_EVENT_FLUSH_START: - GST_DEBUG_OBJECT (lame, "handling FLUSH start event"); - /* forward event */ - ret = gst_pad_push_event (lame->srcpad, event); - break; - case GST_EVENT_FLUSH_STOP: - { - guchar *mp3_data = NULL; - gint mp3_buffer_size; - - GST_DEBUG_OBJECT (lame, "handling FLUSH stop event"); - - if (lame->lgf) { - /* clear buffers if we already have lame set up */ - mp3_buffer_size = 7200; - mp3_data = g_malloc (mp3_buffer_size); - lame_encode_flush (lame->lgf, mp3_data, mp3_buffer_size); - g_free (mp3_data); - } - - ret = gst_pad_push_event (lame->srcpad, event); - break; - } - case GST_EVENT_TAG:{ - GstTagList *tags; - - gst_event_parse_tag (event, &tags); - - tags = gst_tag_list_copy (tags); - gst_event_unref (event); - - gst_tag_list_remove_tag (tags, GST_TAG_CODEC); - gst_tag_list_remove_tag (tags, GST_TAG_AUDIO_CODEC); - event = gst_event_new_tag (tags); - - ret = gst_pad_push_event (lame->srcpad, event); - break; - } - default: - ret = gst_pad_event_default (pad, event); - break; + if (size > 0 && push) { + GST_BUFFER_SIZE (buf) = size; + GST_DEBUG_OBJECT (lame, "pushing final packet of %u bytes", size); + result = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (lame), buf, -1); + } else { + GST_DEBUG_OBJECT (lame, "no final packet (size=%d, push=%d)", size, push); + gst_buffer_unref (buf); + result = GST_FLOW_OK; } - gst_object_unref (lame); - return ret; + return result; +} + +static void +gst_lamemp3enc_flush (GstAudioEncoder * enc) +{ + gst_lamemp3enc_flush_full (GST_LAMEMP3ENC (enc), FALSE); } static GstFlowReturn -gst_lamemp3enc_chain (GstPad * pad, GstBuffer * buf) +gst_lamemp3enc_handle_frame (GstAudioEncoder * enc, GstBuffer * in_buf) { GstLameMP3Enc *lame; guchar *mp3_data; gint mp3_buffer_size, mp3_size; - gint64 duration; + GstBuffer *mp3_buf; GstFlowReturn result; gint num_samples; guint8 *data; guint size; - lame = GST_LAMEMP3ENC (GST_PAD_PARENT (pad)); + lame = GST_LAMEMP3ENC (enc); - GST_LOG_OBJECT (lame, "entered chain"); + /* squeeze remaining and push */ + if (G_UNLIKELY (in_buf == NULL)) + return gst_lamemp3enc_flush_full (lame, TRUE); - if (!lame->setup) - goto not_setup; - - data = GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf); + data = GST_BUFFER_DATA (in_buf); + size = GST_BUFFER_SIZE (in_buf); num_samples = size / 2; /* allocate space for output */ mp3_buffer_size = 1.25 * num_samples + 7200; - mp3_data = g_malloc (mp3_buffer_size); + mp3_buf = gst_buffer_new_and_alloc (mp3_buffer_size); + mp3_data = GST_BUFFER_DATA (mp3_buf); /* lame seems to be too stupid to get mono interleaved going */ if (lame->num_channels == 1) { @@ -791,75 +591,26 @@ gst_lamemp3enc_chain (GstPad * pad, GstBuffer * buf) GST_LOG_OBJECT (lame, "encoded %d bytes of audio to %d bytes of mp3", size, mp3_size); - duration = gst_util_uint64_scale_int (size, GST_SECOND, - 2 * lame->samplerate * lame->num_channels); - - if (GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE && - GST_BUFFER_DURATION (buf) != duration) { - GST_DEBUG_OBJECT (lame, "incoming buffer had incorrect duration %" - GST_TIME_FORMAT ", outgoing buffer will have correct duration %" - GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_TIME_ARGS (duration)); - } - - if (lame->last_ts == GST_CLOCK_TIME_NONE) { - lame->last_ts = GST_BUFFER_TIMESTAMP (buf); - lame->last_offs = GST_BUFFER_OFFSET (buf); - lame->last_duration = duration; + if (G_LIKELY (mp3_size > 0)) { + GST_BUFFER_SIZE (mp3_buf) = mp3_size; + result = gst_audio_encoder_finish_frame (enc, mp3_buf, -1); } else { - lame->last_duration += duration; - } - - gst_buffer_unref (buf); - - if (mp3_size < 0) { - g_warning ("error %d", mp3_size); - } - - if (mp3_size > 0) { - GstBuffer *outbuf; - - outbuf = gst_buffer_new (); - GST_BUFFER_DATA (outbuf) = mp3_data; - GST_BUFFER_MALLOCDATA (outbuf) = mp3_data; - GST_BUFFER_SIZE (outbuf) = mp3_size; - GST_BUFFER_TIMESTAMP (outbuf) = lame->last_ts; - GST_BUFFER_OFFSET (outbuf) = lame->last_offs; - GST_BUFFER_DURATION (outbuf) = lame->last_duration; - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (lame->srcpad)); - - result = gst_pad_push (lame->srcpad, outbuf); - lame->last_flow = result; - if (result != GST_FLOW_OK) { - GST_DEBUG_OBJECT (lame, "flow return: %s", gst_flow_get_name (result)); + if (mp3_size < 0) { + /* eat error ? */ + g_warning ("error %d", mp3_size); } - - if (GST_CLOCK_TIME_IS_VALID (lame->last_ts)) - lame->eos_ts = lame->last_ts + lame->last_duration; - else - lame->eos_ts = GST_CLOCK_TIME_NONE; - lame->last_ts = GST_CLOCK_TIME_NONE; - } else { - g_free (mp3_data); result = GST_FLOW_OK; + gst_buffer_unref (mp3_buf); } return result; - - /* ERRORS */ -not_setup: - { - gst_buffer_unref (buf); - GST_ELEMENT_ERROR (lame, CORE, NEGOTIATION, (NULL), - ("encoder not initialized (input is not audio?)")); - return GST_FLOW_ERROR; - } } /* set up the encoder state */ static gboolean gst_lamemp3enc_setup (GstLameMP3Enc * lame, GstTagList ** tags) { + gboolean res; #define CHECK_ERROR(command) G_STMT_START {\ if ((command) < 0) { \ @@ -877,14 +628,6 @@ gst_lamemp3enc_setup (GstLameMP3Enc * lame, GstTagList ** tags) GST_DEBUG_OBJECT (lame, "starting setup"); - /* check if we're already setup; if we are, we might want to check - * if this initialization is compatible with the previous one */ - /* FIXME: do this */ - if (lame->setup) { - GST_WARNING_OBJECT (lame, "already setup"); - lame->setup = FALSE; - } - lame->lgf = lame_init (); if (lame->lgf == NULL) @@ -892,15 +635,11 @@ gst_lamemp3enc_setup (GstLameMP3Enc * lame, GstTagList ** tags) *tags = gst_tag_list_new (); - /* post latency message on the bus */ - gst_element_post_message (GST_ELEMENT (lame), - gst_message_new_latency (GST_OBJECT (lame))); - /* copy the parameters over */ lame_set_in_samplerate (lame->lgf, lame->samplerate); /* let lame choose default samplerate unless outgoing sample rate is fixed */ - allowed_caps = gst_pad_get_allowed_caps (lame->srcpad); + allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (lame)); if (allowed_caps != NULL) { GstStructure *structure; @@ -954,53 +693,22 @@ gst_lamemp3enc_setup (GstLameMP3Enc * lame, GstTagList ** tags) /* initialize the lame encoder */ if ((retval = lame_init_params (lame->lgf)) >= 0) { - lame->setup = TRUE; /* FIXME: it would be nice to print out the mode here */ GST_INFO ("lame encoder setup (target %s, quality %f, bitrate %d, %d Hz, %d channels)", (lame->target == LAMEMP3ENC_TARGET_QUALITY) ? "quality" : "bitrate", lame->quality, lame->bitrate, lame->samplerate, lame->num_channels); + res = TRUE; } else { GST_ERROR_OBJECT (lame, "lame_init_params returned %d", retval); + res = FALSE; } GST_DEBUG_OBJECT (lame, "done with setup"); - - return lame->setup; + return res; #undef CHECK_ERROR } -static GstStateChangeReturn -gst_lamemp3enc_change_state (GstElement * element, GstStateChange transition) -{ - GstLameMP3Enc *lame; - GstStateChangeReturn result; - - lame = GST_LAMEMP3ENC (element); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - lame->last_flow = GST_FLOW_OK; - lame->last_ts = GST_CLOCK_TIME_NONE; - lame->eos_ts = GST_CLOCK_TIME_NONE; - break; - default: - break; - } - - result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: - gst_lamemp3enc_release_memory (lame); - break; - default: - break; - } - - return result; -} - gboolean gst_lamemp3enc_register (GstPlugin * plugin) { diff --git a/ext/lame/gstlamemp3enc.h b/ext/lame/gstlamemp3enc.h index 2ee8348952..9bf1225428 100644 --- a/ext/lame/gstlamemp3enc.h +++ b/ext/lame/gstlamemp3enc.h @@ -24,6 +24,7 @@ #include +#include G_BEGIN_DECLS @@ -49,37 +50,25 @@ typedef struct _GstLameMP3EncClass GstLameMP3EncClass; * Opaque data structure. */ struct _GstLameMP3Enc { - GstElement element; + GstAudioEncoder element; /*< private >*/ - GstPad *srcpad, *sinkpad; - gint samplerate; gint num_channels; - gboolean setup; + /* properties */ gint target; - gint bitrate; gboolean cbr; - gfloat quality; - gint encoding_engine_quality; - gboolean mono; - /* track this so we don't send a last buffer in eos handler after error */ - GstFlowReturn last_flow; - lame_global_flags *lgf; - - /* time tracker */ - guint64 last_ts, last_offs, last_duration, eos_ts; }; struct _GstLameMP3EncClass { - GstElementClass parent_class; + GstAudioEncoderClass parent_class; }; GType gst_lamemp3enc_get_type(void); From 19c6d5e45b2230f4d04b7ff182b83d4b5ea84146 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 26 Sep 2011 14:44:23 +0200 Subject: [PATCH 12/21] lamemp3enc: really report bitrate rather kbitrate --- ext/lame/gstlamemp3enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/lame/gstlamemp3enc.c b/ext/lame/gstlamemp3enc.c index 6b1a0d1dc1..f23e8d5fbb 100644 --- a/ext/lame/gstlamemp3enc.c +++ b/ext/lame/gstlamemp3enc.c @@ -678,7 +678,7 @@ gst_lamemp3enc_setup (GstLameMP3Enc * lame, GstTagList ** tags) CHECK_ERROR (lame_set_VBR_mean_bitrate_kbps (lame->lgf, lame->bitrate)); } gst_tag_list_add (*tags, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, - lame->bitrate, NULL); + lame->bitrate * 1000, NULL); } if (lame->encoding_engine_quality == LAMEMP3ENC_ENCODING_ENGINE_QUALITY_FAST) From 7961d3f2e3027bed25a7daf0a90e0e51b1568fad Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Fri, 23 Sep 2011 14:33:55 +0200 Subject: [PATCH 13/21] lamemp3enc: use some more boilerplate --- ext/lame/gstlamemp3enc.c | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/ext/lame/gstlamemp3enc.c b/ext/lame/gstlamemp3enc.c index f23e8d5fbb..e1692204ea 100644 --- a/ext/lame/gstlamemp3enc.c +++ b/ext/lame/gstlamemp3enc.c @@ -176,10 +176,6 @@ enum #define DEFAULT_ENCODING_ENGINE_QUALITY LAMEMP3ENC_ENCODING_ENGINE_QUALITY_STANDARD #define DEFAULT_MONO FALSE -static void gst_lamemp3enc_base_init (gpointer g_class); -static void gst_lamemp3enc_class_init (GstLameMP3EncClass * klass); -static void gst_lamemp3enc_init (GstLameMP3Enc * gst_lame); - static gboolean gst_lamemp3enc_start (GstAudioEncoder * enc); static gboolean gst_lamemp3enc_stop (GstAudioEncoder * enc); static gboolean gst_lamemp3enc_set_format (GstAudioEncoder * enc, @@ -194,32 +190,8 @@ static void gst_lamemp3enc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static gboolean gst_lamemp3enc_setup (GstLameMP3Enc * lame, GstTagList ** tags); -static GstElementClass *parent_class = NULL; - -GType -gst_lamemp3enc_get_type (void) -{ - static GType gst_lamemp3enc_type = 0; - - if (!gst_lamemp3enc_type) { - static const GTypeInfo gst_lamemp3enc_info = { - sizeof (GstLameMP3EncClass), - gst_lamemp3enc_base_init, - NULL, - (GClassInitFunc) gst_lamemp3enc_class_init, - NULL, - NULL, - sizeof (GstLameMP3Enc), - 0, - (GInstanceInitFunc) gst_lamemp3enc_init, - }; - - gst_lamemp3enc_type = - g_type_register_static (GST_TYPE_AUDIO_ENCODER, "GstLameMP3Enc", - &gst_lamemp3enc_info, 0); - } - return gst_lamemp3enc_type; -} +GST_BOILERPLATE (GstLameMP3Enc, gst_lamemp3enc, GstAudioEncoder, + GST_TYPE_AUDIO_ENCODER); static void gst_lamemp3enc_release_memory (GstLameMP3Enc * lame) @@ -311,7 +283,7 @@ gst_lamemp3enc_class_init (GstLameMP3EncClass * klass) } static void -gst_lamemp3enc_init (GstLameMP3Enc * lame) +gst_lamemp3enc_init (GstLameMP3Enc * lame, GstLameMP3EncClass * klass) { } From e33c98bc244e5876b6b44afb0be82fbb2151bdfa Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Fri, 23 Sep 2011 15:26:48 +0200 Subject: [PATCH 14/21] lame: port to audioencoder --- ext/lame/gstlame.c | 326 ++++++++++++++------------------------------- ext/lame/gstlame.h | 6 +- 2 files changed, 102 insertions(+), 230 deletions(-) diff --git a/ext/lame/gstlame.c b/ext/lame/gstlame.c index b4aecf9f46..36e408793e 100644 --- a/ext/lame/gstlame.c +++ b/ext/lame/gstlame.c @@ -21,7 +21,7 @@ /** * SECTION:element-lame - * @see_also: lamemp3enc, mad, vorbisenc + * @see_also: lame, mad, vorbisenc * * This element encodes raw integer audio into an MPEG-1 layer 3 (MP3) stream. * Note that MP3 is not @@ -31,7 +31,7 @@ * * * Note - * This element is deprecated, use the lamemp3enc element instead + * This element is deprecated, use the lame element instead * which provides a much simpler interface and results in better MP3 files. * * @@ -309,15 +309,19 @@ static void gst_lame_base_init (gpointer g_class); static void gst_lame_class_init (GstLameClass * klass); static void gst_lame_init (GstLame * gst_lame); +static gboolean gst_lame_start (GstAudioEncoder * enc); +static gboolean gst_lame_stop (GstAudioEncoder * enc); +static gboolean gst_lame_set_format (GstAudioEncoder * enc, + GstAudioInfo * info); +static GstFlowReturn gst_lame_handle_frame (GstAudioEncoder * enc, + GstBuffer * in_buf); +static void gst_lame_flush (GstAudioEncoder * enc); + static void gst_lame_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_lame_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static gboolean gst_lame_sink_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_lame_chain (GstPad * pad, GstBuffer * buf); static gboolean gst_lame_setup (GstLame * lame); -static GstStateChangeReturn gst_lame_change_state (GstElement * element, - GstStateChange transition); static GstElementClass *parent_class = NULL; @@ -352,7 +356,8 @@ gst_lame_get_type (void) }; gst_lame_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstLame", &gst_lame_info, 0); + g_type_register_static (GST_TYPE_AUDIO_ENCODER, "GstLame", + &gst_lame_info, 0); g_type_add_interface_static (gst_lame_type, GST_TYPE_TAG_SETTER, &tag_setter_info); g_type_add_interface_static (gst_lame_type, GST_TYPE_PRESET, &preset_info); @@ -397,9 +402,11 @@ gst_lame_class_init (GstLameClass * klass) { GObjectClass *gobject_class; GstElementClass *gstelement_class; + GstAudioEncoderClass *base_class; gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; + base_class = (GstAudioEncoderClass *) klass; parent_class = g_type_class_peek_parent (klass); @@ -407,6 +414,12 @@ gst_lame_class_init (GstLameClass * klass) gobject_class->get_property = gst_lame_get_property; gobject_class->finalize = gst_lame_finalize; + base_class->start = GST_DEBUG_FUNCPTR (gst_lame_start); + base_class->stop = GST_DEBUG_FUNCPTR (gst_lame_stop); + base_class->set_format = GST_DEBUG_FUNCPTR (gst_lame_set_format); + base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_lame_handle_frame); + base_class->flush = GST_DEBUG_FUNCPTR (gst_lame_flush); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE, g_param_spec_int ("bitrate", "Bitrate (kb/s)", "Bitrate in kbit/sec (8, 16, 24, 32, 40, 48, 56, 64, 80, 96, " @@ -565,39 +578,30 @@ gst_lame_class_init (GstLameClass * klass) GST_TYPE_LAME_PRESET, gst_lame_default_settings.preset, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); #endif - - gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_lame_change_state); } static gboolean -gst_lame_src_setcaps (GstPad * pad, GstCaps * caps) -{ - GST_DEBUG_OBJECT (pad, "caps: %" GST_PTR_FORMAT, caps); - return TRUE; -} - -static gboolean -gst_lame_sink_setcaps (GstPad * pad, GstCaps * caps) +gst_lame_set_format (GstAudioEncoder * enc, GstAudioInfo * info) { GstLame *lame; gint out_samplerate; gint version; - GstStructure *structure; GstCaps *othercaps; + GstClockTime latency; - lame = GST_LAME (GST_PAD_PARENT (pad)); - structure = gst_caps_get_structure (caps, 0); + lame = GST_LAME (enc); - if (!gst_structure_get_int (structure, "rate", &lame->samplerate)) - goto no_rate; - if (!gst_structure_get_int (structure, "channels", &lame->num_channels)) - goto no_channels; + /* parameters already parsed for us */ + lame->samplerate = GST_AUDIO_INFO_RATE (info); + lame->num_channels = GST_AUDIO_INFO_CHANNELS (info); + + /* but we might be asked to reconfigure, so reset */ + gst_lame_release_memory (lame); GST_DEBUG_OBJECT (lame, "setting up lame"); if (!gst_lame_setup (lame)) goto setup_failed; - out_samplerate = lame_get_out_samplerate (lame->lgf); if (out_samplerate == 0) goto zero_output_rate; @@ -624,21 +628,18 @@ gst_lame_sink_setcaps (GstPad * pad, GstCaps * caps) "rate", G_TYPE_INT, out_samplerate, NULL); /* and use these caps */ - gst_pad_set_caps (lame->srcpad, othercaps); + gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (lame), othercaps); gst_caps_unref (othercaps); + /* base class feedback: + * - we will handle buffers, just hand us all available + * - report latency */ + latency = gst_util_uint64_scale_int (lame_get_framesize (lame->lgf), + GST_SECOND, lame->samplerate); + gst_audio_encoder_set_latency (enc, latency, latency); + return TRUE; -no_rate: - { - GST_ERROR_OBJECT (lame, "input caps have no sample rate field"); - return FALSE; - } -no_channels: - { - GST_ERROR_OBJECT (lame, "input caps have no channels field"); - return FALSE; - } zero_output_rate: { GST_ELEMENT_ERROR (lame, LIBRARY, SETTINGS, (NULL), @@ -658,26 +659,6 @@ gst_lame_init (GstLame * lame) { GST_DEBUG_OBJECT (lame, "starting initialization"); - lame->sinkpad = - gst_pad_new_from_static_template (&gst_lame_sink_template, "sink"); - gst_pad_set_event_function (lame->sinkpad, - GST_DEBUG_FUNCPTR (gst_lame_sink_event)); - gst_pad_set_chain_function (lame->sinkpad, - GST_DEBUG_FUNCPTR (gst_lame_chain)); - gst_pad_set_setcaps_function (lame->sinkpad, - GST_DEBUG_FUNCPTR (gst_lame_sink_setcaps)); - gst_element_add_pad (GST_ELEMENT (lame), lame->sinkpad); - - lame->srcpad = - gst_pad_new_from_static_template (&gst_lame_src_template, "src"); - gst_pad_set_setcaps_function (lame->srcpad, - GST_DEBUG_FUNCPTR (gst_lame_src_setcaps)); - gst_element_add_pad (GST_ELEMENT (lame), lame->srcpad); - - lame->samplerate = 44100; - lame->num_channels = 2; - lame->setup = FALSE; - /* Set default settings */ lame->bitrate = gst_lame_default_settings.bitrate; lame->compression_ratio = gst_lame_default_settings.compression_ratio; @@ -714,6 +695,27 @@ gst_lame_init (GstLame * lame) GST_DEBUG_OBJECT (lame, "done initializing"); } +static gboolean +gst_lame_start (GstAudioEncoder * enc) +{ + GstLame *lame = GST_LAME (enc); + + GST_DEBUG_OBJECT (lame, "start"); + return TRUE; +} + +static gboolean +gst_lame_stop (GstAudioEncoder * enc) +{ + GstLame *lame = GST_LAME (enc); + + GST_DEBUG_OBJECT (lame, "stop"); + + gst_lame_release_memory (lame); + return TRUE; +} + + /* three underscores for ___rate is really really really * private as opposed to one underscore */ /* call this MACRO outside of the NULL state so that we have a higher chance @@ -979,108 +981,54 @@ gst_lame_get_property (GObject * object, guint prop_id, GValue * value, } } -static gboolean -gst_lame_sink_event (GstPad * pad, GstEvent * event) +static GstFlowReturn +gst_lame_flush_full (GstLame * lame, gboolean push) { - gboolean ret; - GstLame *lame; + GstBuffer *buf; + gint size; + GstFlowReturn result = GST_FLOW_OK; - lame = GST_LAME (gst_pad_get_parent (pad)); + if (!lame->lgf) + return GST_FLOW_OK; - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS:{ - GST_DEBUG_OBJECT (lame, "handling EOS event"); + buf = gst_buffer_new_and_alloc (7200); + size = lame_encode_flush (lame->lgf, GST_BUFFER_DATA (buf), 7200); - if (lame->lgf != NULL) { - GstBuffer *buf; - gint size; - - buf = gst_buffer_new_and_alloc (7200); - size = lame_encode_flush (lame->lgf, GST_BUFFER_DATA (buf), 7200); - - if (size > 0 && lame->last_flow == GST_FLOW_OK) { - gint64 duration; - - duration = gst_util_uint64_scale (size, 8 * GST_SECOND, - 1000 * lame->bitrate); - - if (lame->last_ts == GST_CLOCK_TIME_NONE) { - lame->last_ts = lame->eos_ts; - lame->last_duration = duration; - } else { - lame->last_duration += duration; - } - - GST_BUFFER_TIMESTAMP (buf) = lame->last_ts; - GST_BUFFER_DURATION (buf) = lame->last_duration; - lame->last_ts = GST_CLOCK_TIME_NONE; - GST_BUFFER_SIZE (buf) = size; - GST_DEBUG_OBJECT (lame, "pushing final packet of %u bytes", size); - gst_buffer_set_caps (buf, GST_PAD_CAPS (lame->srcpad)); - gst_pad_push (lame->srcpad, buf); - } else { - GST_DEBUG_OBJECT (lame, "no final packet (size=%d, last_flow=%s)", - size, gst_flow_get_name (lame->last_flow)); - gst_buffer_unref (buf); - } - } - - ret = gst_pad_event_default (pad, event); - break; - } - case GST_EVENT_FLUSH_START: - GST_DEBUG_OBJECT (lame, "handling FLUSH start event"); - /* forward event */ - ret = gst_pad_push_event (lame->srcpad, event); - break; - case GST_EVENT_FLUSH_STOP: - { - guchar *mp3_data = NULL; - gint mp3_buffer_size; - - GST_DEBUG_OBJECT (lame, "handling FLUSH stop event"); - - if (lame->lgf) { - /* clear buffers if we already have lame set up */ - mp3_buffer_size = 7200; - mp3_data = g_malloc (mp3_buffer_size); - lame_encode_flush (lame->lgf, mp3_data, mp3_buffer_size); - g_free (mp3_data); - } - - ret = gst_pad_push_event (lame->srcpad, event); - break; - } - case GST_EVENT_TAG: - GST_DEBUG_OBJECT (lame, "ignoring TAG event, passing it on"); - ret = gst_pad_push_event (lame->srcpad, event); - break; - default: - ret = gst_pad_event_default (pad, event); - break; + if (size > 0 && push) { + GST_BUFFER_SIZE (buf) = size; + GST_DEBUG_OBJECT (lame, "pushing final packet of %u bytes", size); + result = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (lame), buf, -1); + } else { + GST_DEBUG_OBJECT (lame, "no final packet (size=%d, push=%d)", size, push); + gst_buffer_unref (buf); + result = GST_FLOW_OK; } - gst_object_unref (lame); - return ret; + return result; +} + +static void +gst_lame_flush (GstAudioEncoder * enc) +{ + gst_lame_flush_full (GST_LAME (enc), FALSE); } static GstFlowReturn -gst_lame_chain (GstPad * pad, GstBuffer * buf) +gst_lame_handle_frame (GstAudioEncoder * enc, GstBuffer * buf) { GstLame *lame; guchar *mp3_data; + GstBuffer *mp3_buf; gint mp3_buffer_size, mp3_size; - gint64 duration; GstFlowReturn result; gint num_samples; guint8 *data; guint size; - lame = GST_LAME (GST_PAD_PARENT (pad)); + lame = GST_LAME (enc); - GST_LOG_OBJECT (lame, "entered chain"); - - if (!lame->setup) - goto not_setup; + /* squeeze remaining and push */ + if (G_UNLIKELY (buf == NULL)) + return gst_lame_flush_full (lame, TRUE); data = GST_BUFFER_DATA (buf); size = GST_BUFFER_SIZE (buf); @@ -1089,7 +1037,8 @@ gst_lame_chain (GstPad * pad, GstBuffer * buf) /* allocate space for output */ mp3_buffer_size = 1.25 * num_samples + 7200; - mp3_data = g_malloc (mp3_buffer_size); + mp3_buf = gst_buffer_new_and_alloc (mp3_buffer_size); + mp3_data = GST_BUFFER_DATA (mp3_buf); /* lame seems to be too stupid to get mono interleaved going */ if (lame->num_channels == 1) { @@ -1105,69 +1054,23 @@ gst_lame_chain (GstPad * pad, GstBuffer * buf) GST_LOG_OBJECT (lame, "encoded %d bytes of audio to %d bytes of mp3", size, mp3_size); - duration = gst_util_uint64_scale_int (size, GST_SECOND, - 2 * lame->samplerate * lame->num_channels); - - if (GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE && - GST_BUFFER_DURATION (buf) != duration) { - GST_DEBUG_OBJECT (lame, "incoming buffer had incorrect duration %" - GST_TIME_FORMAT ", outgoing buffer will have correct duration %" - GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_TIME_ARGS (duration)); - } - - if (lame->last_ts == GST_CLOCK_TIME_NONE) { - lame->last_ts = GST_BUFFER_TIMESTAMP (buf); - lame->last_offs = GST_BUFFER_OFFSET (buf); - lame->last_duration = duration; - } else { - lame->last_duration += duration; - } - - gst_buffer_unref (buf); - if (mp3_size < 0) { g_warning ("error %d", mp3_size); } - if (mp3_size > 0) { - GstBuffer *outbuf; - - outbuf = gst_buffer_new (); - GST_BUFFER_DATA (outbuf) = mp3_data; - GST_BUFFER_MALLOCDATA (outbuf) = mp3_data; - GST_BUFFER_SIZE (outbuf) = mp3_size; - GST_BUFFER_TIMESTAMP (outbuf) = lame->last_ts; - GST_BUFFER_OFFSET (outbuf) = lame->last_offs; - GST_BUFFER_DURATION (outbuf) = lame->last_duration; - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (lame->srcpad)); - - result = gst_pad_push (lame->srcpad, outbuf); - lame->last_flow = result; - if (result != GST_FLOW_OK) { - GST_DEBUG_OBJECT (lame, "flow return: %s", gst_flow_get_name (result)); - } - - if (GST_CLOCK_TIME_IS_VALID (lame->last_ts)) - lame->eos_ts = lame->last_ts + lame->last_duration; - else - lame->eos_ts = GST_CLOCK_TIME_NONE; - lame->last_ts = GST_CLOCK_TIME_NONE; + if (G_LIKELY (mp3_size > 0)) { + GST_BUFFER_SIZE (mp3_buf) = mp3_size; + result = gst_audio_encoder_finish_frame (enc, mp3_buf, -1); } else { - g_free (mp3_data); + if (mp3_size < 0) { + /* eat error ? */ + g_warning ("error %d", mp3_size); + } result = GST_FLOW_OK; + gst_buffer_unref (mp3_buf); } return result; - - /* ERRORS */ -not_setup: - { - gst_buffer_unref (buf); - GST_ELEMENT_ERROR (lame, CORE, NEGOTIATION, (NULL), - ("encoder not initialized (input is not audio?)")); - return GST_FLOW_ERROR; - } } /* set up the encoder state */ @@ -1204,7 +1107,7 @@ gst_lame_setup (GstLame * lame) lame_set_in_samplerate (lame->lgf, lame->samplerate); /* let lame choose default samplerate unless outgoing sample rate is fixed */ - allowed_caps = gst_pad_get_allowed_caps (lame->srcpad); + allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (lame)); if (allowed_caps != NULL) { GstStructure *structure; @@ -1294,37 +1197,6 @@ gst_lame_setup (GstLame * lame) #undef CHECK_ERROR } -static GstStateChangeReturn -gst_lame_change_state (GstElement * element, GstStateChange transition) -{ - GstLame *lame; - GstStateChangeReturn result; - - lame = GST_LAME (element); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - lame->last_flow = GST_FLOW_OK; - lame->last_ts = GST_CLOCK_TIME_NONE; - lame->eos_ts = GST_CLOCK_TIME_NONE; - break; - default: - break; - } - - result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: - gst_lame_release_memory (lame); - break; - default: - break; - } - - return result; -} - static gboolean gst_lame_get_default_settings (void) { diff --git a/ext/lame/gstlame.h b/ext/lame/gstlame.h index f9a1370c14..b84cca3f3d 100644 --- a/ext/lame/gstlame.h +++ b/ext/lame/gstlame.h @@ -27,6 +27,7 @@ G_BEGIN_DECLS #include +#include #define GST_TYPE_LAME \ (gst_lame_get_type()) @@ -48,10 +49,9 @@ typedef struct _GstLameClass GstLameClass; * Opaque data structure. */ struct _GstLame { - GstElement element; + GstAudioEncoder element; /*< private >*/ - GstPad *srcpad, *sinkpad; gint samplerate; gint num_channels; @@ -100,7 +100,7 @@ struct _GstLame { }; struct _GstLameClass { - GstElementClass parent_class; + GstAudioEncoderClass parent_class; }; GType gst_lame_get_type(void); From a1694e6f606061388675ea72a7d7eca8dd0aa37e Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Fri, 23 Sep 2011 15:32:01 +0200 Subject: [PATCH 15/21] lame: use some more boilerplate --- ext/lame/gstlame.c | 53 +++++++++------------------------------------- 1 file changed, 10 insertions(+), 43 deletions(-) diff --git a/ext/lame/gstlame.c b/ext/lame/gstlame.c index 36e408793e..c9616f7d45 100644 --- a/ext/lame/gstlame.c +++ b/ext/lame/gstlame.c @@ -305,10 +305,6 @@ enum #endif }; -static void gst_lame_base_init (gpointer g_class); -static void gst_lame_class_init (GstLameClass * klass); -static void gst_lame_init (GstLame * gst_lame); - static gboolean gst_lame_start (GstAudioEncoder * enc); static gboolean gst_lame_stop (GstAudioEncoder * enc); static gboolean gst_lame_set_format (GstAudioEncoder * enc, @@ -323,48 +319,19 @@ static void gst_lame_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static gboolean gst_lame_setup (GstLame * lame); -static GstElementClass *parent_class = NULL; - -GType -gst_lame_get_type (void) +static void +gst_lame_add_interfaces (GType lame_type) { - static GType gst_lame_type = 0; + static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL }; - if (!gst_lame_type) { - static const GTypeInfo gst_lame_info = { - sizeof (GstLameClass), - gst_lame_base_init, - NULL, - (GClassInitFunc) gst_lame_class_init, - NULL, - NULL, - sizeof (GstLame), - 0, - (GInstanceInitFunc) gst_lame_init, - }; - - /* FIXME: remove support for the GstTagSetter interface in 0.11 */ - static const GInterfaceInfo tag_setter_info = { - NULL, - NULL, - NULL - }; - static const GInterfaceInfo preset_info = { - NULL, - NULL, - NULL - }; - - gst_lame_type = - g_type_register_static (GST_TYPE_AUDIO_ENCODER, "GstLame", - &gst_lame_info, 0); - g_type_add_interface_static (gst_lame_type, GST_TYPE_TAG_SETTER, - &tag_setter_info); - g_type_add_interface_static (gst_lame_type, GST_TYPE_PRESET, &preset_info); - } - return gst_lame_type; + /* FIXME: remove support for the GstTagSetter interface in 0.11 */ + g_type_add_interface_static (lame_type, GST_TYPE_TAG_SETTER, + &tag_setter_info); } +GST_BOILERPLATE_FULL (GstLame, gst_lame, GstAudioEncoder, + GST_TYPE_AUDIO_ENCODER, gst_lame_add_interfaces); + static void gst_lame_release_memory (GstLame * lame) { @@ -655,7 +622,7 @@ setup_failed: } static void -gst_lame_init (GstLame * lame) +gst_lame_init (GstLame * lame, GstLameClass * klass) { GST_DEBUG_OBJECT (lame, "starting initialization"); From cd118451edd80308e3122fd027d6b1010cc4025f Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 26 Sep 2011 11:56:23 +0200 Subject: [PATCH 16/21] twolame: port to audioencoder --- ext/twolame/Makefile.am | 7 +- ext/twolame/gsttwolame.c | 333 +++++++++++---------------------------- ext/twolame/gsttwolame.h | 14 +- 3 files changed, 97 insertions(+), 257 deletions(-) diff --git a/ext/twolame/Makefile.am b/ext/twolame/Makefile.am index 74b6c0e5e4..1b32aae345 100644 --- a/ext/twolame/Makefile.am +++ b/ext/twolame/Makefile.am @@ -1,8 +1,11 @@ plugin_LTLIBRARIES = libgsttwolame.la libgsttwolame_la_SOURCES = gsttwolame.c -libgsttwolame_la_CFLAGS = $(GST_CFLAGS) $(TWOLAME_CFLAGS) -libgsttwolame_la_LIBADD = $(TWOLAME_LIBS) $(GST_LIBS) +libgsttwolame_la_CFLAGS = -DGST_USE_UNSTABLE_API \ + $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(TWOLAME_CFLAGS) +libgsttwolame_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \ + -lgstaudio-@GST_MAJORMINOR@ -lgstpbutils-@GST_MAJORMINOR@ \ + $(GST_LIBS) $(TWOLAME_LIBS) libgsttwolame_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgsttwolame_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/ext/twolame/gsttwolame.c b/ext/twolame/gsttwolame.c index 2cabc13a20..3006f1aa27 100644 --- a/ext/twolame/gsttwolame.c +++ b/ext/twolame/gsttwolame.c @@ -191,31 +191,22 @@ enum ARG_QUICK_MODE_COUNT }; +static gboolean gst_two_lame_start (GstAudioEncoder * enc); +static gboolean gst_two_lame_stop (GstAudioEncoder * enc); +static gboolean gst_two_lame_set_format (GstAudioEncoder * enc, + GstAudioInfo * info); +static GstFlowReturn gst_two_lame_handle_frame (GstAudioEncoder * enc, + GstBuffer * in_buf); +static void gst_two_lame_flush (GstAudioEncoder * enc); + static void gst_two_lame_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_two_lame_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static gboolean gst_two_lame_sink_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_two_lame_chain (GstPad * pad, GstBuffer * buf); static gboolean gst_two_lame_setup (GstTwoLame * twolame); -static GstStateChangeReturn gst_two_lame_change_state (GstElement * element, - GstStateChange transition); -static void -_do_init (GType object_type) -{ - const GInterfaceInfo preset_interface_info = { - NULL, /* interface_init */ - NULL, /* interface_finalize */ - NULL /* interface_data */ - }; - - g_type_add_interface_static (object_type, GST_TYPE_PRESET, - &preset_interface_info); -} - -GST_BOILERPLATE_FULL (GstTwoLame, gst_two_lame, GstElement, GST_TYPE_ELEMENT, - _do_init); +GST_BOILERPLATE (GstTwoLame, gst_two_lame, GstAudioEncoder, + GST_TYPE_AUDIO_ENCODER); static void gst_two_lame_release_memory (GstTwoLame * twolame) @@ -254,9 +245,11 @@ gst_two_lame_class_init (GstTwoLameClass * klass) { GObjectClass *gobject_class; GstElementClass *gstelement_class; + GstAudioEncoderClass *gstbase_class; gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; + gstbase_class = (GstAudioEncoderClass *) klass; parent_class = g_type_class_peek_parent (klass); @@ -264,6 +257,12 @@ gst_two_lame_class_init (GstTwoLameClass * klass) gobject_class->get_property = gst_two_lame_get_property; gobject_class->finalize = gst_two_lame_finalize; + gstbase_class->start = GST_DEBUG_FUNCPTR (gst_two_lame_start); + gstbase_class->stop = GST_DEBUG_FUNCPTR (gst_two_lame_stop); + gstbase_class->set_format = GST_DEBUG_FUNCPTR (gst_two_lame_set_format); + gstbase_class->handle_frame = GST_DEBUG_FUNCPTR (gst_two_lame_handle_frame); + gstbase_class->flush = GST_DEBUG_FUNCPTR (gst_two_lame_flush); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MODE, g_param_spec_enum ("mode", "Mode", "Encoding mode", GST_TYPE_TWO_LAME_MODE, gst_two_lame_default_settings.mode, @@ -349,39 +348,25 @@ gst_two_lame_class_init (GstTwoLameClass * klass) "Calculate Psymodel every n frames", 0, G_MAXINT, gst_two_lame_default_settings.quick_mode_count, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_two_lame_change_state); } static gboolean -gst_two_lame_src_setcaps (GstPad * pad, GstCaps * caps) -{ - GST_DEBUG_OBJECT (pad, "caps: %" GST_PTR_FORMAT, caps); - return TRUE; -} - -static gboolean -gst_two_lame_sink_setcaps (GstPad * pad, GstCaps * caps) +gst_two_lame_set_format (GstAudioEncoder * enc, GstAudioInfo * info) { GstTwoLame *twolame; gint out_samplerate; gint version; - GstStructure *structure; GstCaps *othercaps; - twolame = GST_TWO_LAME (GST_PAD_PARENT (pad)); - structure = gst_caps_get_structure (caps, 0); + twolame = GST_TWO_LAME (enc); - if (strcmp (gst_structure_get_name (structure), "audio/x-raw-int") == 0) - twolame->float_input = FALSE; - else - twolame->float_input = TRUE; + /* parameters already parsed for us */ + twolame->samplerate = GST_AUDIO_INFO_RATE (info); + twolame->num_channels = GST_AUDIO_INFO_CHANNELS (info); + twolame->float_input = !GST_AUDIO_INFO_IS_INTEGER (info); - if (!gst_structure_get_int (structure, "rate", &twolame->samplerate)) - goto no_rate; - if (!gst_structure_get_int (structure, "channels", &twolame->num_channels)) - goto no_channels; + /* but we might be asked to reconfigure, so reset */ + gst_two_lame_release_memory (twolame); GST_DEBUG_OBJECT (twolame, "setting up twolame"); if (!gst_two_lame_setup (twolame)) @@ -413,21 +398,14 @@ gst_two_lame_sink_setcaps (GstPad * pad, GstCaps * caps) G_TYPE_INT, out_samplerate, NULL); /* and use these caps */ - gst_pad_set_caps (twolame->srcpad, othercaps); + gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (twolame), othercaps); gst_caps_unref (othercaps); + /* not much base class feedback: + * - we will handle buffers, just hand us all available */ + return TRUE; -no_rate: - { - GST_ERROR_OBJECT (twolame, "input caps have no sample rate field"); - return FALSE; - } -no_channels: - { - GST_ERROR_OBJECT (twolame, "input caps have no channels field"); - return FALSE; - } zero_output_rate: { GST_ELEMENT_ERROR (twolame, LIBRARY, SETTINGS, (NULL), @@ -447,26 +425,6 @@ gst_two_lame_init (GstTwoLame * twolame, GstTwoLameClass * klass) { GST_DEBUG_OBJECT (twolame, "starting initialization"); - twolame->sinkpad = - gst_pad_new_from_static_template (&gst_two_lame_sink_template, "sink"); - gst_pad_set_event_function (twolame->sinkpad, - GST_DEBUG_FUNCPTR (gst_two_lame_sink_event)); - gst_pad_set_chain_function (twolame->sinkpad, - GST_DEBUG_FUNCPTR (gst_two_lame_chain)); - gst_pad_set_setcaps_function (twolame->sinkpad, - GST_DEBUG_FUNCPTR (gst_two_lame_sink_setcaps)); - gst_element_add_pad (GST_ELEMENT (twolame), twolame->sinkpad); - - twolame->srcpad = - gst_pad_new_from_static_template (&gst_two_lame_src_template, "src"); - gst_pad_set_setcaps_function (twolame->srcpad, - GST_DEBUG_FUNCPTR (gst_two_lame_src_setcaps)); - gst_element_add_pad (GST_ELEMENT (twolame), twolame->srcpad); - - twolame->samplerate = 44100; - twolame->num_channels = 2; - twolame->setup = FALSE; - twolame->mode = gst_two_lame_default_settings.mode; twolame->psymodel = gst_two_lame_default_settings.psymodel; twolame->bitrate = gst_two_lame_default_settings.bitrate; @@ -487,6 +445,26 @@ gst_two_lame_init (GstTwoLame * twolame, GstTwoLameClass * klass) GST_DEBUG_OBJECT (twolame, "done initializing"); } +static gboolean +gst_two_lame_start (GstAudioEncoder * enc) +{ + GstTwoLame *twolame = GST_TWO_LAME (enc); + + GST_DEBUG_OBJECT (twolame, "start"); + return TRUE; +} + +static gboolean +gst_two_lame_stop (GstAudioEncoder * enc) +{ + GstTwoLame *twolame = GST_TWO_LAME (enc); + + GST_DEBUG_OBJECT (twolame, "stop"); + + gst_two_lame_release_memory (twolame); + return TRUE; +} + /* three underscores for ___rate is really really really * private as opposed to one underscore */ /* call this MACRO outside of the NULL state so that we have a higher chance @@ -638,106 +616,54 @@ gst_two_lame_get_property (GObject * object, guint prop_id, GValue * value, } } -static gboolean -gst_two_lame_sink_event (GstPad * pad, GstEvent * event) +static GstFlowReturn +gst_two_lame_flush_full (GstTwoLame * lame, gboolean push) { - gboolean ret; - GstTwoLame *twolame; + GstBuffer *buf; + gint size; + GstFlowReturn result = GST_FLOW_OK; - twolame = GST_TWO_LAME (gst_pad_get_parent (pad)); + if (!lame->glopts) + return GST_FLOW_OK; - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS:{ - GST_DEBUG_OBJECT (twolame, "handling EOS event"); + buf = gst_buffer_new_and_alloc (16384); + size = twolame_encode_flush (lame->glopts, GST_BUFFER_DATA (buf), 16384); - if (twolame->glopts != NULL) { - GstBuffer *buf; - gint size; - - buf = gst_buffer_new_and_alloc (16384); - size = - twolame_encode_flush (twolame->glopts, GST_BUFFER_DATA (buf), - 16394); - - if (size > 0 && twolame->last_flow == GST_FLOW_OK) { - gint64 duration; - - duration = gst_util_uint64_scale (size, 8 * GST_SECOND, - 1000 * twolame->bitrate); - - if (twolame->last_ts == GST_CLOCK_TIME_NONE) { - twolame->last_ts = twolame->eos_ts; - twolame->last_duration = duration; - } else { - twolame->last_duration += duration; - } - - GST_BUFFER_TIMESTAMP (buf) = twolame->last_ts; - GST_BUFFER_DURATION (buf) = twolame->last_duration; - twolame->last_ts = GST_CLOCK_TIME_NONE; - GST_BUFFER_SIZE (buf) = size; - GST_DEBUG_OBJECT (twolame, "pushing final packet of %u bytes", size); - gst_buffer_set_caps (buf, GST_PAD_CAPS (twolame->srcpad)); - gst_pad_push (twolame->srcpad, buf); - } else { - GST_DEBUG_OBJECT (twolame, "no final packet (size=%d, last_flow=%s)", - size, gst_flow_get_name (twolame->last_flow)); - gst_buffer_unref (buf); - } - } - - ret = gst_pad_event_default (pad, event); - break; - } - case GST_EVENT_FLUSH_START: - GST_DEBUG_OBJECT (twolame, "handling FLUSH start event"); - /* forward event */ - ret = gst_pad_push_event (twolame->srcpad, event); - break; - case GST_EVENT_FLUSH_STOP: - { - guchar *mp3_data = NULL; - gint mp3_buffer_size; - - GST_DEBUG_OBJECT (twolame, "handling FLUSH stop event"); - - /* clear buffers */ - mp3_buffer_size = 16384; - mp3_data = g_malloc (mp3_buffer_size); - twolame_encode_flush (twolame->glopts, mp3_data, mp3_buffer_size); - - ret = gst_pad_push_event (twolame->srcpad, event); - - g_free (mp3_data); - break; - } - default: - ret = gst_pad_event_default (pad, event); - break; + if (size > 0 && push) { + GST_BUFFER_SIZE (buf) = size; + GST_DEBUG_OBJECT (lame, "pushing final packet of %u bytes", size); + result = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (lame), buf, -1); + } else { + GST_DEBUG_OBJECT (lame, "no final packet (size=%d, push=%d)", size, push); + gst_buffer_unref (buf); + result = GST_FLOW_OK; } - gst_object_unref (twolame); + return result; +} - return ret; +static void +gst_two_lame_flush (GstAudioEncoder * enc) +{ + gst_two_lame_flush_full (GST_TWO_LAME (enc), FALSE); } static GstFlowReturn -gst_two_lame_chain (GstPad * pad, GstBuffer * buf) +gst_two_lame_handle_frame (GstAudioEncoder * enc, GstBuffer * buf) { GstTwoLame *twolame; guchar *mp3_data; gint mp3_buffer_size, mp3_size; - gint64 duration; + GstBuffer *mp3_buf; GstFlowReturn result; gint num_samples; guint8 *data; guint size; - twolame = GST_TWO_LAME (GST_PAD_PARENT (pad)); + twolame = GST_TWO_LAME (enc); - GST_LOG_OBJECT (twolame, "entered chain"); - - if (!twolame->setup) - goto not_setup; + /* squeeze remaining and push */ + if (G_UNLIKELY (buf == NULL)) + return gst_two_lame_flush_full (twolame, TRUE); data = GST_BUFFER_DATA (buf); size = GST_BUFFER_SIZE (buf); @@ -749,7 +675,8 @@ gst_two_lame_chain (GstPad * pad, GstBuffer * buf) /* allocate space for output */ mp3_buffer_size = 1.25 * num_samples + 16384; - mp3_data = g_malloc (mp3_buffer_size); + mp3_buf = gst_buffer_new_and_alloc (mp3_buffer_size); + mp3_data = GST_BUFFER_DATA (mp3_buf); if (twolame->num_channels == 1) { if (twolame->float_input) @@ -774,73 +701,22 @@ gst_two_lame_chain (GstPad * pad, GstBuffer * buf) GST_LOG_OBJECT (twolame, "encoded %d bytes of audio to %d bytes of mp3", size, mp3_size); - if (twolame->float_input) - duration = gst_util_uint64_scale_int (size, GST_SECOND, - 4 * twolame->samplerate * twolame->num_channels); - else - duration = gst_util_uint64_scale_int (size, GST_SECOND, - 2 * twolame->samplerate * twolame->num_channels); - - if (GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE && - GST_BUFFER_DURATION (buf) != duration) { - GST_DEBUG_OBJECT (twolame, "incoming buffer had incorrect duration %" - GST_TIME_FORMAT ", outgoing buffer will have correct duration %" - GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_TIME_ARGS (duration)); - } - - if (twolame->last_ts == GST_CLOCK_TIME_NONE) { - twolame->last_ts = GST_BUFFER_TIMESTAMP (buf); - twolame->last_offs = GST_BUFFER_OFFSET (buf); - twolame->last_duration = duration; - } else { - twolame->last_duration += duration; - } - - gst_buffer_unref (buf); - if (mp3_size < 0) { - g_warning ("error %d", mp3_size); } if (mp3_size > 0) { - GstBuffer *outbuf; - - outbuf = gst_buffer_new (); - GST_BUFFER_DATA (outbuf) = mp3_data; - GST_BUFFER_MALLOCDATA (outbuf) = mp3_data; - GST_BUFFER_SIZE (outbuf) = mp3_size; - GST_BUFFER_TIMESTAMP (outbuf) = twolame->last_ts; - GST_BUFFER_OFFSET (outbuf) = twolame->last_offs; - GST_BUFFER_DURATION (outbuf) = twolame->last_duration; - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (twolame->srcpad)); - - result = gst_pad_push (twolame->srcpad, outbuf); - twolame->last_flow = result; - if (result != GST_FLOW_OK) { - GST_DEBUG_OBJECT (twolame, "flow return: %s", gst_flow_get_name (result)); - } - - if (GST_CLOCK_TIME_IS_VALID (twolame->last_ts)) - twolame->eos_ts = twolame->last_ts + twolame->last_duration; - else - twolame->eos_ts = GST_CLOCK_TIME_NONE; - twolame->last_ts = GST_CLOCK_TIME_NONE; + GST_BUFFER_SIZE (mp3_buf) = mp3_size; + result = gst_audio_encoder_finish_frame (enc, mp3_buf, -1); } else { - g_free (mp3_data); + if (mp3_size < 0) { + /* eat error ? */ + g_warning ("error %d", mp3_size); + } + gst_buffer_unref (mp3_buf); result = GST_FLOW_OK; } return result; - - /* ERRORS */ -not_setup: - { - gst_buffer_unref (buf); - GST_ELEMENT_ERROR (twolame, CORE, NEGOTIATION, (NULL), - ("encoder not initialized (input is not audio?)")); - return GST_FLOW_ERROR; - } } /* set up the encoder state */ @@ -877,7 +753,7 @@ gst_two_lame_setup (GstTwoLame * twolame) twolame_set_in_samplerate (twolame->glopts, twolame->samplerate); /* let twolame choose default samplerate unless outgoing sample rate is fixed */ - allowed_caps = gst_pad_get_allowed_caps (twolame->srcpad); + allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (twolame)); if (allowed_caps != NULL) { GstStructure *structure; @@ -949,37 +825,6 @@ gst_two_lame_setup (GstTwoLame * twolame) #undef CHECK_ERROR } -static GstStateChangeReturn -gst_two_lame_change_state (GstElement * element, GstStateChange transition) -{ - GstTwoLame *twolame; - GstStateChangeReturn result; - - twolame = GST_TWO_LAME (element); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - twolame->last_flow = GST_FLOW_OK; - twolame->last_ts = GST_CLOCK_TIME_NONE; - twolame->eos_ts = GST_CLOCK_TIME_NONE; - break; - default: - break; - } - - result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: - gst_two_lame_release_memory (twolame); - break; - default: - break; - } - - return result; -} - static gboolean gst_two_lame_get_default_settings (void) { diff --git a/ext/twolame/gsttwolame.h b/ext/twolame/gsttwolame.h index d8630c2388..deb3cf41db 100644 --- a/ext/twolame/gsttwolame.h +++ b/ext/twolame/gsttwolame.h @@ -24,6 +24,7 @@ #include +#include G_BEGIN_DECLS @@ -49,10 +50,7 @@ typedef struct _GstTwoLameClass GstTwoLameClass; * Opaque data structure. */ struct _GstTwoLame { - GstElement element; - - /*< private >*/ - GstPad *srcpad, *sinkpad; + GstAudioEncoder element; gint samplerate; gint num_channels; @@ -75,17 +73,11 @@ struct _GstTwoLame { gboolean quick_mode; gint quick_mode_count; - /* track this so we don't send a last buffer in eos handler after error */ - GstFlowReturn last_flow; - twolame_options *glopts; - - /* time tracker */ - guint64 last_ts, last_offs, last_duration, eos_ts; }; struct _GstTwoLameClass { - GstElementClass parent_class; + GstAudioEncoderClass parent_class; }; GType gst_two_lame_get_type(void); From 0431d015f4eda87ab4f024e713aae621ceaabb57 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 26 Sep 2011 12:07:15 +0200 Subject: [PATCH 17/21] twolame: improve output framing and timestamping ... which simply comes down to requesting one frame of input data at a time, since the encoder nicely turns this into 1 encoded frame. --- ext/twolame/gsttwolame.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ext/twolame/gsttwolame.c b/ext/twolame/gsttwolame.c index 3006f1aa27..bc2c07c5e1 100644 --- a/ext/twolame/gsttwolame.c +++ b/ext/twolame/gsttwolame.c @@ -401,8 +401,12 @@ gst_two_lame_set_format (GstAudioEncoder * enc, GstAudioInfo * info) gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (twolame), othercaps); gst_caps_unref (othercaps); - /* not much base class feedback: - * - we will handle buffers, just hand us all available */ + /* report needs to base class: + * hand one frame at a time, if we are pretty sure what a frame is */ + if (out_samplerate == twolame->samplerate) { + gst_audio_encoder_set_frame_samples (enc, 1152); + gst_audio_encoder_set_frame_max (enc, 1); + } return TRUE; From 7032f94e724f6b7408363be5951696b1ae3fba3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 26 Sep 2011 16:07:54 +0200 Subject: [PATCH 18/21] lame: Fix variable 'gstelement_class' set but not used compiler warning --- ext/lame/gstlame.c | 2 -- ext/lame/gstlamemp3enc.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/ext/lame/gstlame.c b/ext/lame/gstlame.c index c9616f7d45..5923ee0b44 100644 --- a/ext/lame/gstlame.c +++ b/ext/lame/gstlame.c @@ -368,11 +368,9 @@ static void gst_lame_class_init (GstLameClass * klass) { GObjectClass *gobject_class; - GstElementClass *gstelement_class; GstAudioEncoderClass *base_class; gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; base_class = (GstAudioEncoderClass *) klass; parent_class = g_type_class_peek_parent (klass); diff --git a/ext/lame/gstlamemp3enc.c b/ext/lame/gstlamemp3enc.c index e1692204ea..aec0f392c0 100644 --- a/ext/lame/gstlamemp3enc.c +++ b/ext/lame/gstlamemp3enc.c @@ -229,11 +229,9 @@ static void gst_lamemp3enc_class_init (GstLameMP3EncClass * klass) { GObjectClass *gobject_class; - GstElementClass *gstelement_class; GstAudioEncoderClass *base_class; gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; base_class = (GstAudioEncoderClass *) klass; parent_class = g_type_class_peek_parent (klass); From 5c390646ecc30841492e2e4c279fcef6901fb6ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 26 Sep 2011 16:08:20 +0200 Subject: [PATCH 19/21] lame: Don't get the parent class again, GST_BOILERPLATE does this already --- ext/lame/gstlame.c | 2 -- ext/lame/gstlamemp3enc.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/ext/lame/gstlame.c b/ext/lame/gstlame.c index 5923ee0b44..349d290817 100644 --- a/ext/lame/gstlame.c +++ b/ext/lame/gstlame.c @@ -373,8 +373,6 @@ gst_lame_class_init (GstLameClass * klass) gobject_class = (GObjectClass *) klass; base_class = (GstAudioEncoderClass *) klass; - parent_class = g_type_class_peek_parent (klass); - gobject_class->set_property = gst_lame_set_property; gobject_class->get_property = gst_lame_get_property; gobject_class->finalize = gst_lame_finalize; diff --git a/ext/lame/gstlamemp3enc.c b/ext/lame/gstlamemp3enc.c index aec0f392c0..40f9a6fc19 100644 --- a/ext/lame/gstlamemp3enc.c +++ b/ext/lame/gstlamemp3enc.c @@ -234,8 +234,6 @@ gst_lamemp3enc_class_init (GstLameMP3EncClass * klass) gobject_class = (GObjectClass *) klass; base_class = (GstAudioEncoderClass *) klass; - parent_class = g_type_class_peek_parent (klass); - gobject_class->set_property = gst_lamemp3enc_set_property; gobject_class->get_property = gst_lamemp3enc_get_property; gobject_class->finalize = gst_lamemp3enc_finalize; From eb6d67b2d4107a166b55310c9edf8d4ced7d9368 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 26 Sep 2011 16:28:08 +0200 Subject: [PATCH 20/21] twolame: Fix variable 'gstelement_class' set but not used compiler warning --- ext/twolame/gsttwolame.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ext/twolame/gsttwolame.c b/ext/twolame/gsttwolame.c index bc2c07c5e1..1677ff37ec 100644 --- a/ext/twolame/gsttwolame.c +++ b/ext/twolame/gsttwolame.c @@ -244,11 +244,9 @@ static void gst_two_lame_class_init (GstTwoLameClass * klass) { GObjectClass *gobject_class; - GstElementClass *gstelement_class; GstAudioEncoderClass *gstbase_class; gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; gstbase_class = (GstAudioEncoderClass *) klass; parent_class = g_type_class_peek_parent (klass); From 62497d4ba8f8e2759f0772e3eab77e1445701dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 26 Sep 2011 16:29:12 +0200 Subject: [PATCH 21/21] twolame: Simple fix for GstAudioEncoder API change --- ext/twolame/gsttwolame.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/twolame/gsttwolame.c b/ext/twolame/gsttwolame.c index 1677ff37ec..7d7fdc63cf 100644 --- a/ext/twolame/gsttwolame.c +++ b/ext/twolame/gsttwolame.c @@ -402,7 +402,8 @@ gst_two_lame_set_format (GstAudioEncoder * enc, GstAudioInfo * info) /* report needs to base class: * hand one frame at a time, if we are pretty sure what a frame is */ if (out_samplerate == twolame->samplerate) { - gst_audio_encoder_set_frame_samples (enc, 1152); + gst_audio_encoder_set_frame_samples_min (enc, 1152); + gst_audio_encoder_set_frame_samples_max (enc, 1152); gst_audio_encoder_set_frame_max (enc, 1); }