mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
Merge branch 'master' into 0.11
Conflicts: configure.ac ext/kate/gstkateenc.c gst/colorspace/colorspace.c gst/mpegvideoparse/mpegvideoparse.c
This commit is contained in:
commit
a2a4300241
62 changed files with 2074 additions and 776 deletions
|
@ -63,7 +63,8 @@ libamrwb (for AMR-WB support)
|
||||||
(http://www.penguin.cz/~utx/amr)
|
(http://www.penguin.cz/~utx/amr)
|
||||||
libkate (for Kate support)
|
libkate (for Kate support)
|
||||||
(http://libkate.googlecode.com/)
|
(http://libkate.googlecode.com/)
|
||||||
|
librtmp (for RTMP support)
|
||||||
|
(http://rtmpdump.mplayerhq.hu/)
|
||||||
|
|
||||||
Optional (debian) packages:
|
Optional (debian) packages:
|
||||||
===========================
|
===========================
|
||||||
|
|
28
configure.ac
28
configure.ac
|
@ -71,6 +71,8 @@ AG_GST_GETTEXT([gst-plugins-bad-$GST_MAJORMINOR])
|
||||||
|
|
||||||
dnl *** check for arguments to configure ***
|
dnl *** check for arguments to configure ***
|
||||||
|
|
||||||
|
AG_GST_ARG_DISABLE_FATAL_WARNINGS
|
||||||
|
|
||||||
AG_GST_ARG_DEBUG
|
AG_GST_ARG_DEBUG
|
||||||
AG_GST_ARG_PROFILING
|
AG_GST_ARG_PROFILING
|
||||||
AG_GST_ARG_VALGRIND
|
AG_GST_ARG_VALGRIND
|
||||||
|
@ -208,9 +210,11 @@ AM_CONDITIONAL(HAVE_GST_CHECK, test "x$HAVE_GST_CHECK" = "xyes")
|
||||||
AG_GST_CHECK_GST_PLUGINS_BASE($GST_MAJORMINOR, [$GSTPB_REQ], yes)
|
AG_GST_CHECK_GST_PLUGINS_BASE($GST_MAJORMINOR, [$GSTPB_REQ], yes)
|
||||||
|
|
||||||
dnl check for uninstalled plugin directories for unit tests
|
dnl check for uninstalled plugin directories for unit tests
|
||||||
AG_GST_CHECK_GST_PLUGINS_GOOD($GST_MAJORMINOR, [0.11.0])
|
AG_GST_CHECK_UNINSTALLED_SETUP([
|
||||||
AG_GST_CHECK_GST_PLUGINS_UGLY($GST_MAJORMINOR, [0.11.0])
|
AG_GST_CHECK_GST_PLUGINS_GOOD($GST_MAJORMINOR, [0.11.0])
|
||||||
AG_GST_CHECK_GST_PLUGINS_FFMPEG($GST_MAJORMINOR, [0.11.0])
|
AG_GST_CHECK_GST_PLUGINS_UGLY($GST_MAJORMINOR, [0.11.0])
|
||||||
|
AG_GST_CHECK_GST_PLUGINS_FFMPEG($GST_MAJORMINOR, [0.11.0])
|
||||||
|
])
|
||||||
|
|
||||||
dnl Check for documentation xrefs
|
dnl Check for documentation xrefs
|
||||||
GLIB_PREFIX="`$PKG_CONFIG --variable=prefix glib-2.0`"
|
GLIB_PREFIX="`$PKG_CONFIG --variable=prefix glib-2.0`"
|
||||||
|
@ -288,14 +292,14 @@ AG_GST_SET_PACKAGE_RELEASE_DATETIME_WITH_NANO([$PACKAGE_VERSION_NANO],
|
||||||
dnl define an ERROR_CFLAGS Makefile variable
|
dnl define an ERROR_CFLAGS Makefile variable
|
||||||
dnl -Waggregate-return - libexif returns aggregates
|
dnl -Waggregate-return - libexif returns aggregates
|
||||||
dnl -Wundef - Windows headers check _MSC_VER unconditionally
|
dnl -Wundef - Windows headers check _MSC_VER unconditionally
|
||||||
AG_GST_SET_ERROR_CFLAGS($GST_GIT, [
|
AG_GST_SET_ERROR_CFLAGS($FATAL_WARNINGS, [
|
||||||
-Wmissing-declarations -Wmissing-prototypes -Wredundant-decls
|
-Wmissing-declarations -Wmissing-prototypes -Wredundant-decls
|
||||||
-Wwrite-strings -Wformat-security -Wold-style-definition
|
-Wwrite-strings -Wformat-security -Wold-style-definition
|
||||||
-Winit-self -Wmissing-include-dirs -Waddress -Wno-multichar
|
-Winit-self -Wmissing-include-dirs -Waddress -Wno-multichar
|
||||||
-Wnested-externs])
|
-Wnested-externs])
|
||||||
|
|
||||||
dnl define an ERROR_CXXFLAGS Makefile variable
|
dnl define an ERROR_CXXFLAGS Makefile variable
|
||||||
AG_GST_SET_ERROR_CXXFLAGS($GST_GIT, [
|
AG_GST_SET_ERROR_CXXFLAGS($FATAL_WARNINGS, [
|
||||||
-Wmissing-declarations -Wredundant-decls
|
-Wmissing-declarations -Wredundant-decls
|
||||||
-Wwrite-strings -Wformat-nonliteral -Wformat-security
|
-Wwrite-strings -Wformat-nonliteral -Wformat-security
|
||||||
-Winit-self -Wmissing-include-dirs -Waddress -Wno-multichar ])
|
-Winit-self -Wmissing-include-dirs -Waddress -Wno-multichar ])
|
||||||
|
@ -755,6 +759,16 @@ AG_GST_CHECK_FEATURE(CELT, [celt], celt, [
|
||||||
AC_SUBST(CELT_LIBS)
|
AC_SUBST(CELT_LIBS)
|
||||||
])
|
])
|
||||||
|
|
||||||
|
dnl *** chromaprint ***
|
||||||
|
translit(dnm, m, l) AM_CONDITIONAL(USE_CHROMAPRINT, true)
|
||||||
|
AG_GST_CHECK_FEATURE(CHROMAPRINT, [chromaprint], chromaprint, [
|
||||||
|
PKG_CHECK_MODULES(CHROMAPRINT, libchromaprint, HAVE_CHROMAPRINT="yes", [
|
||||||
|
HAVE_CHROMAPRINT="no"
|
||||||
|
])
|
||||||
|
AC_SUBST(CHROMAPRINT_CFLAGS)
|
||||||
|
AC_SUBST(CHROMAPRINT_LIBS)
|
||||||
|
])
|
||||||
|
|
||||||
dnl *** Cog ***
|
dnl *** Cog ***
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(USE_COG, true)
|
translit(dnm, m, l) AM_CONDITIONAL(USE_COG, true)
|
||||||
AG_GST_CHECK_FEATURE(COG, [Cog plugin], cog, [
|
AG_GST_CHECK_FEATURE(COG, [Cog plugin], cog, [
|
||||||
|
@ -1712,7 +1726,7 @@ AG_GST_CHECK_FEATURE(VDPAU, [VDPAU], vdpau, [
|
||||||
dnl *** schroedinger ***
|
dnl *** schroedinger ***
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(USE_SCHRO, true)
|
translit(dnm, m, l) AM_CONDITIONAL(USE_SCHRO, true)
|
||||||
AG_GST_CHECK_FEATURE(SCHRO, [Schroedinger video codec], schro, [
|
AG_GST_CHECK_FEATURE(SCHRO, [Schroedinger video codec], schro, [
|
||||||
AG_GST_PKG_CHECK_MODULES(SCHRO, schroedinger-1.0 >= 1.0.7)
|
AG_GST_PKG_CHECK_MODULES(SCHRO, schroedinger-1.0 >= 1.0.10)
|
||||||
])
|
])
|
||||||
|
|
||||||
dnl *** zbar ***
|
dnl *** zbar ***
|
||||||
|
@ -1800,6 +1814,7 @@ AM_CONDITIONAL(USE_APEXSINK, false)
|
||||||
AM_CONDITIONAL(USE_BZ2, false)
|
AM_CONDITIONAL(USE_BZ2, false)
|
||||||
AM_CONDITIONAL(USE_CDAUDIO, false)
|
AM_CONDITIONAL(USE_CDAUDIO, false)
|
||||||
AM_CONDITIONAL(USE_CELT, false)
|
AM_CONDITIONAL(USE_CELT, false)
|
||||||
|
AM_CONDITIONAL(USE_CHROMAPRINT, false)
|
||||||
AM_CONDITIONAL(USE_COG, false)
|
AM_CONDITIONAL(USE_COG, false)
|
||||||
AM_CONDITIONAL(USE_CURL, false)
|
AM_CONDITIONAL(USE_CURL, false)
|
||||||
AM_CONDITIONAL(USE_DC1394, false)
|
AM_CONDITIONAL(USE_DC1394, false)
|
||||||
|
@ -2056,6 +2071,7 @@ ext/apexsink/Makefile
|
||||||
ext/bz2/Makefile
|
ext/bz2/Makefile
|
||||||
ext/cdaudio/Makefile
|
ext/cdaudio/Makefile
|
||||||
ext/celt/Makefile
|
ext/celt/Makefile
|
||||||
|
ext/chromaprint/Makefile
|
||||||
ext/cog/Makefile
|
ext/cog/Makefile
|
||||||
ext/curl/Makefile
|
ext/curl/Makefile
|
||||||
ext/dc1394/Makefile
|
ext/dc1394/Makefile
|
||||||
|
|
|
@ -58,6 +58,12 @@ else
|
||||||
CELT_DIR=
|
CELT_DIR=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if USE_CHROMAPRINT
|
||||||
|
CHROMAPRINT_DIR=chromaprint
|
||||||
|
else
|
||||||
|
CHROMAPRINT_DIR=
|
||||||
|
endif
|
||||||
|
|
||||||
if USE_COG
|
if USE_COG
|
||||||
COG_DIR=cog
|
COG_DIR=cog
|
||||||
else
|
else
|
||||||
|
@ -397,6 +403,7 @@ SUBDIRS=\
|
||||||
$(BZ2_DIR) \
|
$(BZ2_DIR) \
|
||||||
$(CDAUDIO_DIR) \
|
$(CDAUDIO_DIR) \
|
||||||
$(CELT_DIR) \
|
$(CELT_DIR) \
|
||||||
|
$(CHROMAPRINT_DIR) \
|
||||||
$(COG_DIR) \
|
$(COG_DIR) \
|
||||||
$(CURL_DIR) \
|
$(CURL_DIR) \
|
||||||
$(DC1394_DIR) \
|
$(DC1394_DIR) \
|
||||||
|
@ -456,6 +463,7 @@ DIST_SUBDIRS = \
|
||||||
bz2 \
|
bz2 \
|
||||||
cdaudio \
|
cdaudio \
|
||||||
celt \
|
celt \
|
||||||
|
chromaprint \
|
||||||
cog \
|
cog \
|
||||||
curl \
|
curl \
|
||||||
dc1394 \
|
dc1394 \
|
||||||
|
|
14
ext/chromaprint/Makefile.am
Normal file
14
ext/chromaprint/Makefile.am
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
plugin_LTLIBRARIES = libgstchromaprint.la
|
||||||
|
|
||||||
|
libgstchromaprint_la_SOURCES = gstchromaprint.c gstchromaprint.h
|
||||||
|
|
||||||
|
libgstchromaprint_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) \
|
||||||
|
$(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \
|
||||||
|
$(CHROMAPRINT_CFLAGS)
|
||||||
|
libgstchromaprint_la_LIBADD = \
|
||||||
|
$(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) $(GST_LIBS) \
|
||||||
|
$(CHROMAPRINT_LIBS)
|
||||||
|
libgstchromaprint_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
|
libgstchromaprint_la_LIBTOOLFLAGS = --tag=disable-static
|
||||||
|
|
||||||
|
noinst_HEADERS = gstchromaprint.h
|
317
ext/chromaprint/gstchromaprint.c
Normal file
317
ext/chromaprint/gstchromaprint.c
Normal file
|
@ -0,0 +1,317 @@
|
||||||
|
/* GStreamer chromaprint audio fingerprinting element
|
||||||
|
* Copyright (C) 2006 M. Derezynski
|
||||||
|
* Copyright (C) 2008 Eric Buehl
|
||||||
|
* Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
|
||||||
|
* Copyright (C) 2011 Lukáš Lalinský <lalinsky@gmail.com>
|
||||||
|
*
|
||||||
|
* 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-chromaprint
|
||||||
|
*
|
||||||
|
* The chromaprint element calculates an acoustic fingerprint for an
|
||||||
|
* audio stream which can be used to identify a song and look up
|
||||||
|
* further metadata from the <ulink url="http://acoustid.org/">Acoustid</ulink>
|
||||||
|
* and Musicbrainz databases.
|
||||||
|
*
|
||||||
|
* <refsect2>
|
||||||
|
* <title>Example launch line</title>
|
||||||
|
* |[
|
||||||
|
* gst-launch -m uridecodebin uri=file:///path/to/song.ogg ! audioconvert ! chromaprint ! fakesink
|
||||||
|
* ]|
|
||||||
|
* </refsect2>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "gstchromaprint.h"
|
||||||
|
|
||||||
|
#define DEFAULT_MAX_DURATION 120
|
||||||
|
|
||||||
|
#define PAD_CAPS \
|
||||||
|
"audio/x-raw-int, " \
|
||||||
|
"rate = (int) [ 1, MAX ], " \
|
||||||
|
"channels = (int) [ 1, 2 ], " \
|
||||||
|
"endianness = (int) { BYTE_ORDER }, " \
|
||||||
|
"width = (int) { 16 }, " \
|
||||||
|
"depth = (int) { 16 }, " \
|
||||||
|
"signed = (boolean) true"
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_STATIC (gst_chromaprint_debug);
|
||||||
|
#define GST_CAT_DEFAULT gst_chromaprint_debug
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_0,
|
||||||
|
PROP_FINGERPRINT,
|
||||||
|
PROP_MAX_DURATION
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
GST_BOILERPLATE (GstChromaprint, gst_chromaprint, GstElement,
|
||||||
|
GST_TYPE_AUDIO_FILTER);
|
||||||
|
|
||||||
|
static void gst_chromaprint_finalize (GObject * object);
|
||||||
|
static void gst_chromaprint_set_property (GObject * object, guint prop_id,
|
||||||
|
const GValue * value, GParamSpec * pspec);
|
||||||
|
static void gst_chromaprint_get_property (GObject * object, guint prop_id,
|
||||||
|
GValue * value, GParamSpec * pspec);
|
||||||
|
static GstFlowReturn gst_chromaprint_transform_ip (GstBaseTransform * trans,
|
||||||
|
GstBuffer * buf);
|
||||||
|
static gboolean gst_chromaprint_event (GstBaseTransform * trans,
|
||||||
|
GstEvent * event);
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_chromaprint_base_init (gpointer g_class)
|
||||||
|
{
|
||||||
|
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
||||||
|
GstAudioFilterClass *audio_filter_class = (GstAudioFilterClass *) g_class;
|
||||||
|
GstCaps *caps;
|
||||||
|
|
||||||
|
gst_element_class_set_details_simple (element_class,
|
||||||
|
"Chromaprint fingerprinting element",
|
||||||
|
"Filter/Analyzer/Audio",
|
||||||
|
"Find an audio fingerprint using the Chromaprint library",
|
||||||
|
"Lukáš Lalinský <lalinsky@gmail.com>");
|
||||||
|
|
||||||
|
caps = gst_caps_from_string (PAD_CAPS);
|
||||||
|
gst_audio_filter_class_add_pad_templates (audio_filter_class, caps);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_chromaprint_class_init (GstChromaprintClass * klass)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class;
|
||||||
|
GstBaseTransformClass *gstbasetrans_class;
|
||||||
|
|
||||||
|
gobject_class = G_OBJECT_CLASS (klass);
|
||||||
|
gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass);
|
||||||
|
|
||||||
|
gobject_class->set_property = gst_chromaprint_set_property;
|
||||||
|
gobject_class->get_property = gst_chromaprint_get_property;
|
||||||
|
|
||||||
|
/* FIXME: do we need this in addition to the tag message ? */
|
||||||
|
g_object_class_install_property (gobject_class, PROP_FINGERPRINT,
|
||||||
|
g_param_spec_string ("fingerprint", "Resulting fingerprint",
|
||||||
|
"Resulting fingerprint", NULL, G_PARAM_READABLE));
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_MAX_DURATION,
|
||||||
|
g_param_spec_uint ("duration", "Duration limit",
|
||||||
|
"Number of seconds of audio to use for fingerprinting",
|
||||||
|
0, G_MAXUINT, DEFAULT_MAX_DURATION,
|
||||||
|
G_PARAM_READABLE | G_PARAM_WRITABLE));
|
||||||
|
|
||||||
|
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_chromaprint_finalize);
|
||||||
|
|
||||||
|
gstbasetrans_class->transform_ip =
|
||||||
|
GST_DEBUG_FUNCPTR (gst_chromaprint_transform_ip);
|
||||||
|
gstbasetrans_class->event = GST_DEBUG_FUNCPTR (gst_chromaprint_event);
|
||||||
|
gstbasetrans_class->passthrough_on_same_caps = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_chromaprint_reset (GstChromaprint * chromaprint)
|
||||||
|
{
|
||||||
|
if (chromaprint->fingerprint) {
|
||||||
|
chromaprint_dealloc (chromaprint->fingerprint);
|
||||||
|
chromaprint->fingerprint = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
chromaprint->nsamples = 0;
|
||||||
|
chromaprint->duration = 0;
|
||||||
|
chromaprint->record = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_chromaprint_create_fingerprint (GstChromaprint * chromaprint)
|
||||||
|
{
|
||||||
|
GstTagList *tags;
|
||||||
|
|
||||||
|
if (chromaprint->duration <= 3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (chromaprint,
|
||||||
|
"Generating fingerprint based on %d seconds of audio",
|
||||||
|
chromaprint->duration);
|
||||||
|
|
||||||
|
chromaprint_finish (chromaprint->context);
|
||||||
|
chromaprint_get_fingerprint (chromaprint->context, &chromaprint->fingerprint);
|
||||||
|
chromaprint->record = FALSE;
|
||||||
|
|
||||||
|
tags = gst_tag_list_new_full (GST_TAG_CHROMAPRINT_FINGERPRINT,
|
||||||
|
chromaprint->fingerprint, NULL);
|
||||||
|
|
||||||
|
gst_element_found_tags (GST_ELEMENT (chromaprint), tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_chromaprint_init (GstChromaprint * chromaprint,
|
||||||
|
GstChromaprintClass * gclass)
|
||||||
|
{
|
||||||
|
gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (chromaprint), TRUE);
|
||||||
|
|
||||||
|
chromaprint->context = chromaprint_new (CHROMAPRINT_ALGORITHM_DEFAULT);
|
||||||
|
chromaprint->fingerprint = NULL;
|
||||||
|
chromaprint->max_duration = DEFAULT_MAX_DURATION;
|
||||||
|
gst_chromaprint_reset (chromaprint);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_chromaprint_finalize (GObject * object)
|
||||||
|
{
|
||||||
|
GstChromaprint *chromaprint = GST_CHROMAPRINT (object);
|
||||||
|
|
||||||
|
chromaprint->record = FALSE;
|
||||||
|
|
||||||
|
if (chromaprint->context) {
|
||||||
|
chromaprint_free (chromaprint->context);
|
||||||
|
chromaprint->context = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chromaprint->fingerprint) {
|
||||||
|
chromaprint_dealloc (chromaprint->fingerprint);
|
||||||
|
chromaprint->fingerprint = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_chromaprint_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
|
||||||
|
{
|
||||||
|
GstChromaprint *chromaprint = GST_CHROMAPRINT (trans);
|
||||||
|
gint rate = GST_AUDIO_FILTER (chromaprint)->format.rate;
|
||||||
|
gint channels = GST_AUDIO_FILTER (chromaprint)->format.channels;
|
||||||
|
guint nsamples;
|
||||||
|
|
||||||
|
if (G_UNLIKELY (rate <= 0 || channels <= 0))
|
||||||
|
return GST_FLOW_NOT_NEGOTIATED;
|
||||||
|
|
||||||
|
if (!chromaprint->record)
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
|
nsamples = GST_BUFFER_SIZE (buf) / (channels * 2);
|
||||||
|
|
||||||
|
if (nsamples == 0)
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
|
if (chromaprint->nsamples == 0) {
|
||||||
|
chromaprint_start (chromaprint->context, rate, channels);
|
||||||
|
}
|
||||||
|
chromaprint->nsamples += nsamples;
|
||||||
|
chromaprint->duration = chromaprint->nsamples / rate;
|
||||||
|
|
||||||
|
chromaprint_feed (chromaprint->context, GST_BUFFER_DATA (buf),
|
||||||
|
GST_BUFFER_SIZE (buf) / 2);
|
||||||
|
|
||||||
|
if (chromaprint->duration >= chromaprint->max_duration
|
||||||
|
&& !chromaprint->fingerprint) {
|
||||||
|
gst_chromaprint_create_fingerprint (chromaprint);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_chromaprint_event (GstBaseTransform * trans, GstEvent * event)
|
||||||
|
{
|
||||||
|
GstChromaprint *chromaprint = GST_CHROMAPRINT (trans);
|
||||||
|
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_FLUSH_STOP:
|
||||||
|
case GST_EVENT_NEWSEGMENT:
|
||||||
|
GST_DEBUG_OBJECT (trans, "Got %s event, clearing buffer",
|
||||||
|
GST_EVENT_TYPE_NAME (event));
|
||||||
|
gst_chromaprint_reset (chromaprint);
|
||||||
|
break;
|
||||||
|
case GST_EVENT_EOS:
|
||||||
|
if (!chromaprint->fingerprint) {
|
||||||
|
gst_chromaprint_create_fingerprint (chromaprint);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_chromaprint_set_property (GObject * object, guint prop_id,
|
||||||
|
const GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
GstChromaprint *chromaprint = GST_CHROMAPRINT (object);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
case PROP_MAX_DURATION:
|
||||||
|
chromaprint->max_duration = g_value_get_uint (value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_chromaprint_get_property (GObject * object, guint prop_id,
|
||||||
|
GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
GstChromaprint *chromaprint = GST_CHROMAPRINT (object);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
case PROP_FINGERPRINT:
|
||||||
|
g_value_set_string (value, chromaprint->fingerprint);
|
||||||
|
break;
|
||||||
|
case PROP_MAX_DURATION:
|
||||||
|
g_value_set_uint (value, chromaprint->max_duration);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
plugin_init (GstPlugin * plugin)
|
||||||
|
{
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_chromaprint_debug, "chromaprint",
|
||||||
|
0, "chromaprint element");
|
||||||
|
|
||||||
|
GST_INFO ("libchromaprint %s", chromaprint_get_version ());
|
||||||
|
|
||||||
|
ret = gst_element_register (plugin, "chromaprint", GST_RANK_NONE,
|
||||||
|
GST_TYPE_CHROMAPRINT);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
gst_tag_register (GST_TAG_CHROMAPRINT_FINGERPRINT, GST_TAG_FLAG_META,
|
||||||
|
G_TYPE_STRING, "chromaprint fingerprint", "Chromaprint fingerprint",
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||||
|
GST_VERSION_MINOR,
|
||||||
|
"chromaprint",
|
||||||
|
"Calculate Chromaprint fingerprint from audio files",
|
||||||
|
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
|
77
ext/chromaprint/gstchromaprint.h
Normal file
77
ext/chromaprint/gstchromaprint.h
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/* GStreamer chromaprint audio fingerprinting element
|
||||||
|
* Copyright (C) 2006 M. Derezynski
|
||||||
|
* Copyright (C) 2008 Eric Buehl
|
||||||
|
* Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
|
||||||
|
* Copyright (C) 2011 Lukáš Lalinský <<user@hostname.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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GST_CHROMAPRINT_H__
|
||||||
|
#define __GST_CHROMAPRINT_H__
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
#include <gst/base/gstadapter.h>
|
||||||
|
#include <gst/audio/gstaudiofilter.h>
|
||||||
|
#include <gst/audio/audio.h>
|
||||||
|
#include <chromaprint.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define GST_TYPE_CHROMAPRINT \
|
||||||
|
(gst_chromaprint_get_type())
|
||||||
|
#define GST_CHROMAPRINT(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CHROMAPRINT,GstChromaprint))
|
||||||
|
#define GST_CHROMAPRINT_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CHROMAPRINT,GstChromaprintClass))
|
||||||
|
#define GST_IS_CHROMAPRINT(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CHROMAPRINT))
|
||||||
|
#define GST_IS_CHROMAPRINT_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CHROMAPRINT))
|
||||||
|
|
||||||
|
#define GST_TAG_CHROMAPRINT_FINGERPRINT "chromaprint-fingerprint"
|
||||||
|
|
||||||
|
typedef struct _GstChromaprint GstChromaprint;
|
||||||
|
typedef struct _GstChromaprintClass GstChromaprintClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstChromaprint:
|
||||||
|
*
|
||||||
|
* Opaque #GstChromaprint element structure
|
||||||
|
*/
|
||||||
|
struct _GstChromaprint
|
||||||
|
{
|
||||||
|
GstAudioFilter element;
|
||||||
|
|
||||||
|
/*< private >*/
|
||||||
|
ChromaprintContext * context;
|
||||||
|
char * fingerprint;
|
||||||
|
gboolean record;
|
||||||
|
guint64 nsamples;
|
||||||
|
guint duration;
|
||||||
|
guint max_duration;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstChromaprintClass
|
||||||
|
{
|
||||||
|
GstAudioFilterClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType gst_chromaprint_get_type (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __GST_CHROMAPRINT_H__ */
|
|
@ -208,6 +208,9 @@ gst_mse_finalize (GObject * object)
|
||||||
gst_object_unref (fs->sinkpad_test);
|
gst_object_unref (fs->sinkpad_test);
|
||||||
g_mutex_free (fs->lock);
|
g_mutex_free (fs->lock);
|
||||||
g_cond_free (fs->cond);
|
g_cond_free (fs->cond);
|
||||||
|
gst_buffer_replace (&fs->buffer_ref, NULL);
|
||||||
|
|
||||||
|
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstCaps *
|
static GstCaps *
|
||||||
|
@ -243,7 +246,7 @@ gst_mse_getcaps (GstPad * pad)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pad != fs->sinkpad_test) {
|
if (pad != fs->sinkpad_test) {
|
||||||
peercaps = gst_pad_peer_get_caps (fs->sinkpad_ref);
|
peercaps = gst_pad_peer_get_caps (fs->sinkpad_test);
|
||||||
if (peercaps) {
|
if (peercaps) {
|
||||||
icaps = gst_caps_intersect (caps, peercaps);
|
icaps = gst_caps_intersect (caps, peercaps);
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
|
@ -310,6 +313,7 @@ gst_mse_reset (GstMSE * fs)
|
||||||
fs->luma_mse_sum = 0;
|
fs->luma_mse_sum = 0;
|
||||||
fs->chroma_mse_sum = 0;
|
fs->chroma_mse_sum = 0;
|
||||||
fs->n_frames = 0;
|
fs->n_frames = 0;
|
||||||
|
fs->cancel = FALSE;
|
||||||
|
|
||||||
if (fs->buffer_ref) {
|
if (fs->buffer_ref) {
|
||||||
gst_buffer_unref (fs->buffer_ref);
|
gst_buffer_unref (fs->buffer_ref);
|
||||||
|
@ -435,9 +439,11 @@ gst_mse_sink_event (GstPad * pad, GstEvent * event)
|
||||||
break;
|
break;
|
||||||
case GST_EVENT_FLUSH_START:
|
case GST_EVENT_FLUSH_START:
|
||||||
GST_DEBUG ("flush start");
|
GST_DEBUG ("flush start");
|
||||||
|
fs->cancel = TRUE;
|
||||||
break;
|
break;
|
||||||
case GST_EVENT_FLUSH_STOP:
|
case GST_EVENT_FLUSH_STOP:
|
||||||
GST_DEBUG ("flush stop");
|
GST_DEBUG ("flush stop");
|
||||||
|
fs->cancel = FALSE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -161,6 +161,8 @@ gst_gme_dec_dispose (GObject * object)
|
||||||
g_object_unref (gme->adapter);
|
g_object_unref (gme->adapter);
|
||||||
gme->adapter = NULL;
|
gme->adapter = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
|
|
|
@ -43,43 +43,16 @@ enum
|
||||||
ARG_0
|
ARG_0
|
||||||
};
|
};
|
||||||
|
|
||||||
static void gst_gsmdec_base_init (gpointer g_class);
|
static gboolean gst_gsmdec_start (GstAudioDecoder * dec);
|
||||||
static void gst_gsmdec_class_init (GstGSMDec * klass);
|
static gboolean gst_gsmdec_stop (GstAudioDecoder * dec);
|
||||||
static void gst_gsmdec_init (GstGSMDec * gsmdec);
|
static gboolean gst_gsmdec_set_format (GstAudioDecoder * dec, GstCaps * caps);
|
||||||
static void gst_gsmdec_finalize (GObject * object);
|
static GstFlowReturn gst_gsmdec_parse (GstAudioDecoder * dec,
|
||||||
|
GstAdapter * adapter, gint * offset, gint * length);
|
||||||
static gboolean gst_gsmdec_sink_setcaps (GstPad * pad, GstCaps * caps);
|
static GstFlowReturn gst_gsmdec_handle_frame (GstAudioDecoder * dec,
|
||||||
static gboolean gst_gsmdec_sink_event (GstPad * pad, GstEvent * event);
|
GstBuffer * in_buf);
|
||||||
static GstFlowReturn gst_gsmdec_chain (GstPad * pad, GstBuffer * buf);
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
|
||||||
|
|
||||||
/*static guint gst_gsmdec_signals[LAST_SIGNAL] = { 0 }; */
|
/*static guint gst_gsmdec_signals[LAST_SIGNAL] = { 0 }; */
|
||||||
|
|
||||||
GType
|
|
||||||
gst_gsmdec_get_type (void)
|
|
||||||
{
|
|
||||||
static GType gsmdec_type = 0;
|
|
||||||
|
|
||||||
if (!gsmdec_type) {
|
|
||||||
static const GTypeInfo gsmdec_info = {
|
|
||||||
sizeof (GstGSMDecClass),
|
|
||||||
gst_gsmdec_base_init,
|
|
||||||
NULL,
|
|
||||||
(GClassInitFunc) gst_gsmdec_class_init,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
sizeof (GstGSMDec),
|
|
||||||
0,
|
|
||||||
(GInstanceInitFunc) gst_gsmdec_init,
|
|
||||||
};
|
|
||||||
|
|
||||||
gsmdec_type =
|
|
||||||
g_type_register_static (GST_TYPE_ELEMENT, "GstGSMDec", &gsmdec_info, 0);
|
|
||||||
}
|
|
||||||
return gsmdec_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ENCODED_SAMPLES 160
|
#define ENCODED_SAMPLES 160
|
||||||
|
|
||||||
static GstStaticPadTemplate gsmdec_sink_template =
|
static GstStaticPadTemplate gsmdec_sink_template =
|
||||||
|
@ -101,6 +74,9 @@ GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
"depth = (int) 16, " "rate = (int) [1, MAX], " "channels = (int) 1")
|
"depth = (int) 16, " "rate = (int) [1, MAX], " "channels = (int) 1")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
GST_BOILERPLATE (GstGSMDec, gst_gsmdec, GstAudioDecoder,
|
||||||
|
GST_TYPE_AUDIO_DECODER);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_gsmdec_base_init (gpointer g_class)
|
gst_gsmdec_base_init (gpointer g_class)
|
||||||
{
|
{
|
||||||
|
@ -116,63 +92,60 @@ gst_gsmdec_base_init (gpointer g_class)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_gsmdec_class_init (GstGSMDec * klass)
|
gst_gsmdec_class_init (GstGSMDecClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GstAudioDecoderClass *base_class;
|
||||||
|
|
||||||
gobject_class = (GObjectClass *) klass;
|
base_class = (GstAudioDecoderClass *) klass;
|
||||||
|
|
||||||
parent_class = g_type_class_peek_parent (klass);
|
base_class->start = GST_DEBUG_FUNCPTR (gst_gsmdec_start);
|
||||||
|
base_class->stop = GST_DEBUG_FUNCPTR (gst_gsmdec_stop);
|
||||||
gobject_class->finalize = gst_gsmdec_finalize;
|
base_class->set_format = GST_DEBUG_FUNCPTR (gst_gsmdec_set_format);
|
||||||
|
base_class->parse = GST_DEBUG_FUNCPTR (gst_gsmdec_parse);
|
||||||
|
base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_gsmdec_handle_frame);
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gsmdec_debug, "gsmdec", 0, "GSM Decoder");
|
GST_DEBUG_CATEGORY_INIT (gsmdec_debug, "gsmdec", 0, "GSM Decoder");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_gsmdec_init (GstGSMDec * gsmdec)
|
gst_gsmdec_init (GstGSMDec * gsmdec, GstGSMDecClass * klass)
|
||||||
{
|
{
|
||||||
/* create the sink and src pads */
|
|
||||||
gsmdec->sinkpad =
|
|
||||||
gst_pad_new_from_static_template (&gsmdec_sink_template, "sink");
|
|
||||||
gst_pad_set_setcaps_function (gsmdec->sinkpad, gst_gsmdec_sink_setcaps);
|
|
||||||
gst_pad_set_event_function (gsmdec->sinkpad, gst_gsmdec_sink_event);
|
|
||||||
gst_pad_set_chain_function (gsmdec->sinkpad, gst_gsmdec_chain);
|
|
||||||
gst_element_add_pad (GST_ELEMENT (gsmdec), gsmdec->sinkpad);
|
|
||||||
|
|
||||||
gsmdec->srcpad =
|
|
||||||
gst_pad_new_from_static_template (&gsmdec_src_template, "src");
|
|
||||||
gst_element_add_pad (GST_ELEMENT (gsmdec), gsmdec->srcpad);
|
|
||||||
|
|
||||||
gsmdec->state = gsm_create ();
|
|
||||||
|
|
||||||
gsmdec->adapter = gst_adapter_new ();
|
|
||||||
gsmdec->next_of = 0;
|
|
||||||
gsmdec->next_ts = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_gsmdec_finalize (GObject * object)
|
|
||||||
{
|
|
||||||
GstGSMDec *gsmdec;
|
|
||||||
|
|
||||||
gsmdec = GST_GSMDEC (object);
|
|
||||||
|
|
||||||
g_object_unref (gsmdec->adapter);
|
|
||||||
gsm_destroy (gsmdec->state);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_gsmdec_sink_setcaps (GstPad * pad, GstCaps * caps)
|
gst_gsmdec_start (GstAudioDecoder * dec)
|
||||||
|
{
|
||||||
|
GstGSMDec *gsmdec = GST_GSMDEC (dec);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dec, "start");
|
||||||
|
|
||||||
|
gsmdec->state = gsm_create ();
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_gsmdec_stop (GstAudioDecoder * dec)
|
||||||
|
{
|
||||||
|
GstGSMDec *gsmdec = GST_GSMDEC (dec);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dec, "stop");
|
||||||
|
|
||||||
|
gsm_destroy (gsmdec->state);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_gsmdec_set_format (GstAudioDecoder * dec, GstCaps * caps)
|
||||||
{
|
{
|
||||||
GstGSMDec *gsmdec;
|
GstGSMDec *gsmdec;
|
||||||
GstCaps *srccaps;
|
GstCaps *srccaps;
|
||||||
GstStructure *s;
|
GstStructure *s;
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
|
gint rate;
|
||||||
|
|
||||||
gsmdec = GST_GSMDEC (gst_pad_get_parent (pad));
|
gsmdec = GST_GSMDEC (dec);
|
||||||
|
|
||||||
s = gst_caps_get_structure (caps, 0);
|
s = gst_caps_get_structure (caps, 0);
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
|
@ -186,7 +159,9 @@ gst_gsmdec_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
else
|
else
|
||||||
goto wrong_caps;
|
goto wrong_caps;
|
||||||
|
|
||||||
if (!gst_structure_get_int (s, "rate", &gsmdec->rate)) {
|
gsmdec->needed = 33;
|
||||||
|
|
||||||
|
if (!gst_structure_get_int (s, "rate", &rate)) {
|
||||||
GST_WARNING_OBJECT (gsmdec, "missing sample rate parameter from sink caps");
|
GST_WARNING_OBJECT (gsmdec, "missing sample rate parameter from sink caps");
|
||||||
goto beach;
|
goto beach;
|
||||||
}
|
}
|
||||||
|
@ -194,21 +169,16 @@ gst_gsmdec_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
/* MSGSM needs different framing */
|
/* MSGSM needs different framing */
|
||||||
gsm_option (gsmdec->state, GSM_OPT_WAV49, &gsmdec->use_wav49);
|
gsm_option (gsmdec->state, GSM_OPT_WAV49, &gsmdec->use_wav49);
|
||||||
|
|
||||||
gsmdec->duration = gst_util_uint64_scale (ENCODED_SAMPLES,
|
|
||||||
GST_SECOND, gsmdec->rate);
|
|
||||||
|
|
||||||
/* Setting up src caps based on the input sample rate. */
|
/* Setting up src caps based on the input sample rate. */
|
||||||
srccaps = gst_caps_new_simple ("audio/x-raw-int",
|
srccaps = gst_caps_new_simple ("audio/x-raw-int",
|
||||||
"endianness", G_TYPE_INT, G_BYTE_ORDER,
|
"endianness", G_TYPE_INT, G_BYTE_ORDER,
|
||||||
"signed", G_TYPE_BOOLEAN, TRUE,
|
"signed", G_TYPE_BOOLEAN, TRUE,
|
||||||
"width", G_TYPE_INT, 16,
|
"width", G_TYPE_INT, 16,
|
||||||
"depth", G_TYPE_INT, 16,
|
"depth", G_TYPE_INT, 16,
|
||||||
"rate", G_TYPE_INT, gsmdec->rate, "channels", G_TYPE_INT, 1, NULL);
|
"rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, 1, NULL);
|
||||||
|
|
||||||
ret = gst_pad_set_caps (gsmdec->srcpad, srccaps);
|
|
||||||
|
|
||||||
|
ret = gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec), srccaps);
|
||||||
gst_caps_unref (srccaps);
|
gst_caps_unref (srccaps);
|
||||||
gst_object_unref (gsmdec);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -218,127 +188,66 @@ wrong_caps:
|
||||||
GST_ERROR_OBJECT (gsmdec, "invalid caps received");
|
GST_ERROR_OBJECT (gsmdec, "invalid caps received");
|
||||||
|
|
||||||
beach:
|
beach:
|
||||||
gst_object_unref (gsmdec);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static GstFlowReturn
|
||||||
gst_gsmdec_sink_event (GstPad * pad, GstEvent * event)
|
gst_gsmdec_parse (GstAudioDecoder * dec, GstAdapter * adapter,
|
||||||
|
gint * offset, gint * length)
|
||||||
{
|
{
|
||||||
gboolean res;
|
GstGSMDec *gsmdec = GST_GSMDEC (dec);
|
||||||
GstGSMDec *gsmdec;
|
guint size;
|
||||||
|
|
||||||
gsmdec = GST_GSMDEC (gst_pad_get_parent (pad));
|
size = gst_adapter_available (adapter);
|
||||||
|
g_return_val_if_fail (size > 0, GST_FLOW_ERROR);
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
/* WAV49 requires alternating 33 and 32 bytes of input */
|
||||||
case GST_EVENT_FLUSH_START:
|
if (gsmdec->use_wav49) {
|
||||||
res = gst_pad_push_event (gsmdec->srcpad, event);
|
gsmdec->needed = (gsmdec->needed == 33 ? 32 : 33);
|
||||||
break;
|
|
||||||
case GST_EVENT_FLUSH_STOP:
|
|
||||||
gst_segment_init (&gsmdec->segment, GST_FORMAT_UNDEFINED);
|
|
||||||
res = gst_pad_push_event (gsmdec->srcpad, event);
|
|
||||||
break;
|
|
||||||
case GST_EVENT_NEWSEGMENT:
|
|
||||||
{
|
|
||||||
gboolean update;
|
|
||||||
GstFormat format;
|
|
||||||
gdouble rate, arate;
|
|
||||||
gint64 start, stop, time;
|
|
||||||
|
|
||||||
gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
|
|
||||||
&start, &stop, &time);
|
|
||||||
|
|
||||||
/* now configure the values */
|
|
||||||
gst_segment_set_newsegment_full (&gsmdec->segment, update,
|
|
||||||
rate, arate, format, start, stop, time);
|
|
||||||
|
|
||||||
/* and forward */
|
|
||||||
res = gst_pad_push_event (gsmdec->srcpad, event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GST_EVENT_EOS:
|
|
||||||
default:
|
|
||||||
res = gst_pad_push_event (gsmdec->srcpad, event);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_object_unref (gsmdec);
|
if (size < gsmdec->needed)
|
||||||
|
return GST_FLOW_UNEXPECTED;
|
||||||
|
|
||||||
return res;
|
*offset = 0;
|
||||||
|
*length = gsmdec->needed;
|
||||||
|
|
||||||
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_gsmdec_chain (GstPad * pad, GstBuffer * buf)
|
gst_gsmdec_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstGSMDec *gsmdec;
|
GstGSMDec *gsmdec;
|
||||||
gsm_byte *data;
|
gsm_byte *data;
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
GstClockTime timestamp;
|
GstBuffer *outbuf;
|
||||||
gint needed;
|
|
||||||
|
|
||||||
gsmdec = GST_GSMDEC (gst_pad_get_parent (pad));
|
/* no fancy draining */
|
||||||
|
if (G_UNLIKELY (!buffer))
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
timestamp = GST_BUFFER_TIMESTAMP (buf);
|
gsmdec = GST_GSMDEC (dec);
|
||||||
|
|
||||||
if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
|
/* always the same amount of output samples */
|
||||||
gst_adapter_clear (gsmdec->adapter);
|
outbuf = gst_buffer_new_and_alloc (ENCODED_SAMPLES * sizeof (gsm_signal));
|
||||||
gsmdec->next_ts = GST_CLOCK_TIME_NONE;
|
|
||||||
/* FIXME, do some good offset */
|
|
||||||
gsmdec->next_of = 0;
|
|
||||||
}
|
|
||||||
gst_adapter_push (gsmdec->adapter, buf);
|
|
||||||
|
|
||||||
needed = 33;
|
/* now encode frame into the output buffer */
|
||||||
/* do we have enough bytes to read a frame */
|
data = (gsm_byte *) GST_BUFFER_DATA (buffer);
|
||||||
while (gst_adapter_available (gsmdec->adapter) >= needed) {
|
if (gsm_decode (gsmdec->state, data,
|
||||||
GstBuffer *outbuf;
|
(gsm_signal *) GST_BUFFER_DATA (outbuf)) < 0) {
|
||||||
|
/* invalid frame */
|
||||||
/* always the same amount of output samples */
|
GST_AUDIO_DECODER_ERROR (gsmdec, 1, STREAM, DECODE, (NULL),
|
||||||
outbuf = gst_buffer_new_and_alloc (ENCODED_SAMPLES * sizeof (gsm_signal));
|
("tried to decode an invalid frame"), ret);
|
||||||
|
if (ret != GST_FLOW_OK)
|
||||||
/* If we are not given any timestamp, interpolate from last seen
|
goto exit;
|
||||||
* timestamp (if any). */
|
gst_buffer_unref (outbuf);
|
||||||
if (timestamp == GST_CLOCK_TIME_NONE)
|
outbuf = NULL;
|
||||||
timestamp = gsmdec->next_ts;
|
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
|
|
||||||
|
|
||||||
/* interpolate in the next run */
|
|
||||||
if (timestamp != GST_CLOCK_TIME_NONE)
|
|
||||||
gsmdec->next_ts = timestamp + gsmdec->duration;
|
|
||||||
timestamp = GST_CLOCK_TIME_NONE;
|
|
||||||
|
|
||||||
GST_BUFFER_DURATION (outbuf) = gsmdec->duration;
|
|
||||||
GST_BUFFER_OFFSET (outbuf) = gsmdec->next_of;
|
|
||||||
if (gsmdec->next_of != -1)
|
|
||||||
gsmdec->next_of += ENCODED_SAMPLES;
|
|
||||||
GST_BUFFER_OFFSET_END (outbuf) = gsmdec->next_of;
|
|
||||||
|
|
||||||
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (gsmdec->srcpad));
|
|
||||||
|
|
||||||
/* now encode frame into the output buffer */
|
|
||||||
data = (gsm_byte *) gst_adapter_peek (gsmdec->adapter, needed);
|
|
||||||
if (gsm_decode (gsmdec->state, data,
|
|
||||||
(gsm_signal *) GST_BUFFER_DATA (outbuf)) < 0) {
|
|
||||||
/* invalid frame */
|
|
||||||
GST_WARNING_OBJECT (gsmdec, "tried to decode an invalid frame, skipping");
|
|
||||||
}
|
|
||||||
gst_adapter_flush (gsmdec->adapter, needed);
|
|
||||||
|
|
||||||
/* WAV49 requires alternating 33 and 32 bytes of input */
|
|
||||||
if (gsmdec->use_wav49)
|
|
||||||
needed = (needed == 33 ? 32 : 33);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (gsmdec, "Pushing buffer of size %d ts %" GST_TIME_FORMAT,
|
|
||||||
GST_BUFFER_SIZE (outbuf),
|
|
||||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
|
|
||||||
|
|
||||||
/* push */
|
|
||||||
ret = gst_pad_push (gsmdec->srcpad, outbuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_object_unref (gsmdec);
|
gst_audio_decoder_finish_frame (dec, outbuf, 1);
|
||||||
|
|
||||||
|
exit:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define __GST_GSMDEC_H__
|
#define __GST_GSMDEC_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/audio/gstaudiodecoder.h>
|
||||||
|
|
||||||
#ifdef GSM_HEADER_IN_SUBDIR
|
#ifdef GSM_HEADER_IN_SUBDIR
|
||||||
#include <gsm/gsm.h>
|
#include <gsm/gsm.h>
|
||||||
|
@ -47,28 +47,16 @@ typedef struct _GstGSMDecClass GstGSMDecClass;
|
||||||
|
|
||||||
struct _GstGSMDec
|
struct _GstGSMDec
|
||||||
{
|
{
|
||||||
GstElement element;
|
GstAudioDecoder element;
|
||||||
|
|
||||||
/* pads */
|
|
||||||
GstPad *sinkpad, *srcpad;
|
|
||||||
|
|
||||||
gsm state;
|
gsm state;
|
||||||
gint use_wav49;
|
gint use_wav49;
|
||||||
gint64 next_of;
|
gint needed;
|
||||||
GstClockTime next_ts;
|
|
||||||
|
|
||||||
GstAdapter *adapter;
|
|
||||||
|
|
||||||
GstSegment segment;
|
|
||||||
|
|
||||||
gint rate;
|
|
||||||
|
|
||||||
GstClockTime duration;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstGSMDecClass
|
struct _GstGSMDecClass
|
||||||
{
|
{
|
||||||
GstElementClass parent_class;
|
GstAudioDecoderClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_gsmdec_get_type (void);
|
GType gst_gsmdec_get_type (void);
|
||||||
|
|
|
@ -43,39 +43,12 @@ enum
|
||||||
ARG_0
|
ARG_0
|
||||||
};
|
};
|
||||||
|
|
||||||
static void gst_gsmenc_base_init (gpointer g_class);
|
static gboolean gst_gsmenc_start (GstAudioEncoder * enc);
|
||||||
static void gst_gsmenc_class_init (GstGSMEnc * klass);
|
static gboolean gst_gsmenc_stop (GstAudioEncoder * enc);
|
||||||
static void gst_gsmenc_init (GstGSMEnc * gsmenc);
|
static gboolean gst_gsmenc_set_format (GstAudioEncoder * enc,
|
||||||
static void gst_gsmenc_finalize (GObject * object);
|
GstAudioInfo * info);
|
||||||
|
static GstFlowReturn gst_gsmenc_handle_frame (GstAudioEncoder * enc,
|
||||||
static gboolean gst_gsmenc_setcaps (GstPad * pad, GstCaps * caps);
|
GstBuffer * in_buf);
|
||||||
static GstFlowReturn gst_gsmenc_chain (GstPad * pad, GstBuffer * buf);
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
|
||||||
|
|
||||||
GType
|
|
||||||
gst_gsmenc_get_type (void)
|
|
||||||
{
|
|
||||||
static GType gsmenc_type = 0;
|
|
||||||
|
|
||||||
if (!gsmenc_type) {
|
|
||||||
static const GTypeInfo gsmenc_info = {
|
|
||||||
sizeof (GstGSMEncClass),
|
|
||||||
gst_gsmenc_base_init,
|
|
||||||
NULL,
|
|
||||||
(GClassInitFunc) gst_gsmenc_class_init,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
sizeof (GstGSMEnc),
|
|
||||||
0,
|
|
||||||
(GInstanceInitFunc) gst_gsmenc_init,
|
|
||||||
};
|
|
||||||
|
|
||||||
gsmenc_type =
|
|
||||||
g_type_register_static (GST_TYPE_ELEMENT, "GstGSMEnc", &gsmenc_info, 0);
|
|
||||||
}
|
|
||||||
return gsmenc_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstStaticPadTemplate gsmenc_src_template =
|
static GstStaticPadTemplate gsmenc_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
|
@ -95,6 +68,9 @@ GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
"depth = (int) 16, " "rate = (int) 8000, " "channels = (int) 1")
|
"depth = (int) 16, " "rate = (int) 8000, " "channels = (int) 1")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
GST_BOILERPLATE (GstGSMEnc, gst_gsmenc, GstAudioEncoder,
|
||||||
|
GST_TYPE_AUDIO_ENCODER);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_gsmenc_base_init (gpointer g_class)
|
gst_gsmenc_base_init (gpointer g_class)
|
||||||
{
|
{
|
||||||
|
@ -110,34 +86,32 @@ gst_gsmenc_base_init (gpointer g_class)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_gsmenc_class_init (GstGSMEnc * klass)
|
gst_gsmenc_class_init (GstGSMEncClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GstAudioEncoderClass *base_class;
|
||||||
|
|
||||||
gobject_class = (GObjectClass *) klass;
|
base_class = (GstAudioEncoderClass *) klass;
|
||||||
|
|
||||||
parent_class = g_type_class_peek_parent (klass);
|
base_class->start = GST_DEBUG_FUNCPTR (gst_gsmenc_start);
|
||||||
|
base_class->stop = GST_DEBUG_FUNCPTR (gst_gsmenc_stop);
|
||||||
gobject_class->finalize = gst_gsmenc_finalize;
|
base_class->set_format = GST_DEBUG_FUNCPTR (gst_gsmenc_set_format);
|
||||||
|
base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_gsmenc_handle_frame);
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gsmenc_debug, "gsmenc", 0, "GSM Encoder");
|
GST_DEBUG_CATEGORY_INIT (gsmenc_debug, "gsmenc", 0, "GSM Encoder");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_gsmenc_init (GstGSMEnc * gsmenc)
|
gst_gsmenc_init (GstGSMEnc * gsmenc, GstGSMEncClass * klass)
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_gsmenc_start (GstAudioEncoder * enc)
|
||||||
|
{
|
||||||
|
GstGSMEnc *gsmenc = GST_GSMENC (enc);
|
||||||
gint use_wav49;
|
gint use_wav49;
|
||||||
|
|
||||||
/* create the sink and src pads */
|
GST_DEBUG_OBJECT (enc, "start");
|
||||||
gsmenc->sinkpad =
|
|
||||||
gst_pad_new_from_static_template (&gsmenc_sink_template, "sink");
|
|
||||||
gst_pad_set_chain_function (gsmenc->sinkpad, gst_gsmenc_chain);
|
|
||||||
gst_pad_set_setcaps_function (gsmenc->sinkpad, gst_gsmenc_setcaps);
|
|
||||||
gst_element_add_pad (GST_ELEMENT (gsmenc), gsmenc->sinkpad);
|
|
||||||
|
|
||||||
gsmenc->srcpad =
|
|
||||||
gst_pad_new_from_static_template (&gsmenc_src_template, "src");
|
|
||||||
gst_element_add_pad (GST_ELEMENT (gsmenc), gsmenc->srcpad);
|
|
||||||
|
|
||||||
gsmenc->state = gsm_create ();
|
gsmenc->state = gsm_create ();
|
||||||
|
|
||||||
|
@ -145,78 +119,69 @@ gst_gsmenc_init (GstGSMEnc * gsmenc)
|
||||||
use_wav49 = 0;
|
use_wav49 = 0;
|
||||||
gsm_option (gsmenc->state, GSM_OPT_WAV49, &use_wav49);
|
gsm_option (gsmenc->state, GSM_OPT_WAV49, &use_wav49);
|
||||||
|
|
||||||
gsmenc->adapter = gst_adapter_new ();
|
return TRUE;
|
||||||
gsmenc->next_ts = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_gsmenc_finalize (GObject * object)
|
|
||||||
{
|
|
||||||
GstGSMEnc *gsmenc;
|
|
||||||
|
|
||||||
gsmenc = GST_GSMENC (object);
|
|
||||||
|
|
||||||
g_object_unref (gsmenc->adapter);
|
|
||||||
gsm_destroy (gsmenc->state);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_gsmenc_setcaps (GstPad * pad, GstCaps * caps)
|
gst_gsmenc_stop (GstAudioEncoder * enc)
|
||||||
{
|
{
|
||||||
GstGSMEnc *gsmenc;
|
GstGSMEnc *gsmenc = GST_GSMENC (enc);
|
||||||
GstCaps *srccaps;
|
|
||||||
|
|
||||||
gsmenc = GST_GSMENC (gst_pad_get_parent (pad));
|
GST_DEBUG_OBJECT (enc, "stop");
|
||||||
|
gsm_destroy (gsmenc->state);
|
||||||
srccaps = gst_static_pad_template_get_caps (&gsmenc_src_template);
|
|
||||||
|
|
||||||
gst_pad_set_caps (gsmenc->srcpad, srccaps);
|
|
||||||
|
|
||||||
gst_object_unref (gsmenc);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_gsmenc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
|
||||||
|
{
|
||||||
|
GstCaps *srccaps;
|
||||||
|
|
||||||
|
srccaps = gst_static_pad_template_get_caps (&gsmenc_src_template);
|
||||||
|
gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (benc), srccaps);
|
||||||
|
|
||||||
|
/* report needs to base class */
|
||||||
|
gst_audio_encoder_set_frame_samples_min (benc, 160);
|
||||||
|
gst_audio_encoder_set_frame_samples_max (benc, 160);
|
||||||
|
gst_audio_encoder_set_frame_max (benc, 1);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_gsmenc_chain (GstPad * pad, GstBuffer * buf)
|
gst_gsmenc_handle_frame (GstAudioEncoder * benc, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstGSMEnc *gsmenc;
|
GstGSMEnc *gsmenc;
|
||||||
gsm_signal *data;
|
gsm_signal *data;
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
GstBuffer *outbuf;
|
||||||
|
|
||||||
gsmenc = GST_GSMENC (gst_pad_get_parent (pad));
|
gsmenc = GST_GSMENC (benc);
|
||||||
|
|
||||||
if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
|
/* we don't deal with squeezing remnants, so simply discard those */
|
||||||
gst_adapter_clear (gsmenc->adapter);
|
if (G_UNLIKELY (buffer == NULL)) {
|
||||||
}
|
GST_DEBUG_OBJECT (gsmenc, "no data");
|
||||||
gst_adapter_push (gsmenc->adapter, buf);
|
goto done;
|
||||||
|
|
||||||
while (gst_adapter_available (gsmenc->adapter) >= 320) {
|
|
||||||
GstBuffer *outbuf;
|
|
||||||
|
|
||||||
outbuf = gst_buffer_new_and_alloc (33 * sizeof (gsm_byte));
|
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = gsmenc->next_ts;
|
|
||||||
GST_BUFFER_DURATION (outbuf) = 20 * GST_MSECOND;
|
|
||||||
gsmenc->next_ts += 20 * GST_MSECOND;
|
|
||||||
|
|
||||||
/* encode 160 16-bit samples into 33 bytes */
|
|
||||||
data = (gsm_signal *) gst_adapter_peek (gsmenc->adapter, 320);
|
|
||||||
gsm_encode (gsmenc->state, data, (gsm_byte *) GST_BUFFER_DATA (outbuf));
|
|
||||||
gst_adapter_flush (gsmenc->adapter, 320);
|
|
||||||
|
|
||||||
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (gsmenc->srcpad));
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (gsmenc, "Pushing buffer of size %d",
|
|
||||||
GST_BUFFER_SIZE (outbuf));
|
|
||||||
|
|
||||||
ret = gst_pad_push (gsmenc->srcpad, outbuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_object_unref (gsmenc);
|
if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 320)) {
|
||||||
|
GST_DEBUG_OBJECT (gsmenc, "discarding trailing data %d",
|
||||||
|
GST_BUFFER_SIZE (buffer));
|
||||||
|
ret = gst_audio_encoder_finish_frame (benc, NULL, -1);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
outbuf = gst_buffer_new_and_alloc (33 * sizeof (gsm_byte));
|
||||||
|
|
||||||
|
/* encode 160 16-bit samples into 33 bytes */
|
||||||
|
data = (gsm_signal *) GST_BUFFER_DATA (buffer);
|
||||||
|
gsm_encode (gsmenc->state, data, (gsm_byte *) GST_BUFFER_DATA (outbuf));
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (gsmenc, "encoded to %d bytes", GST_BUFFER_SIZE (outbuf));
|
||||||
|
|
||||||
|
ret = gst_audio_encoder_finish_frame (benc, outbuf, 160);
|
||||||
|
|
||||||
|
done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define __GST_GSMENC_H__
|
#define __GST_GSMENC_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/audio/gstaudioencoder.h>
|
||||||
|
|
||||||
#ifdef GSM_HEADER_IN_SUBDIR
|
#ifdef GSM_HEADER_IN_SUBDIR
|
||||||
#include <gsm/gsm.h>
|
#include <gsm/gsm.h>
|
||||||
|
@ -47,20 +47,14 @@ typedef struct _GstGSMEncClass GstGSMEncClass;
|
||||||
|
|
||||||
struct _GstGSMEnc
|
struct _GstGSMEnc
|
||||||
{
|
{
|
||||||
GstElement element;
|
GstAudioEncoder element;
|
||||||
|
|
||||||
/* pads */
|
|
||||||
GstPad *sinkpad, *srcpad;
|
|
||||||
GstAdapter *adapter;
|
|
||||||
|
|
||||||
gsm state;
|
gsm state;
|
||||||
GstClockTime next_ts;
|
|
||||||
gboolean firstBuf;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstGSMEncClass
|
struct _GstGSMEncClass
|
||||||
{
|
{
|
||||||
GstElementClass parent_class;
|
GstAudioEncoderClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_gsmenc_get_type (void);
|
GType gst_gsmenc_get_type (void);
|
||||||
|
|
|
@ -924,33 +924,32 @@ gst_kate_enc_chain_text (GstKateEnc * ke, GstBuffer * buf,
|
||||||
("kate_encode_set_markup_type: %d", ret));
|
("kate_encode_set_markup_type: %d", ret));
|
||||||
rflow = GST_FLOW_ERROR;
|
rflow = GST_FLOW_ERROR;
|
||||||
} else {
|
} else {
|
||||||
char *text;
|
const char *text;
|
||||||
gsize text_len;
|
size_t text_len;
|
||||||
|
gboolean need_unmap = TRUE;
|
||||||
|
kate_float t0 = start / (double) GST_SECOND;
|
||||||
|
kate_float t1 = stop / (double) GST_SECOND;
|
||||||
|
|
||||||
text = gst_buffer_map (buf, &text_len, NULL, GST_MAP_READ);
|
text = gst_buffer_map (buf, &text_len, NULL, GST_MAP_READ);
|
||||||
if (text) {
|
if (text == NULL) {
|
||||||
kate_float t0 = start / (double) GST_SECOND;
|
text = "";
|
||||||
kate_float t1 = stop / (double) GST_SECOND;
|
text_len = 0;
|
||||||
GST_LOG_OBJECT (ke, "Encoding text: %*.*s (%u bytes) from %f to %f",
|
need_unmap = FALSE;
|
||||||
(int) text_len, (int) text_len, text, text_len, t0, t1);
|
|
||||||
|
|
||||||
ret = kate_encode_text (&ke->k, t0, t1, text, text_len, &kp);
|
|
||||||
|
|
||||||
if (G_UNLIKELY (ret < 0)) {
|
|
||||||
GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
|
|
||||||
("Failed to encode text: %d", ret));
|
|
||||||
rflow = GST_FLOW_ERROR;
|
|
||||||
} else {
|
|
||||||
rflow =
|
|
||||||
gst_kate_enc_chain_push_packet (ke, &kp, start, stop - start + 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* FIXME: this should not be an error, we should ignore it and move on */
|
|
||||||
GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
|
|
||||||
("no text in text packet"));
|
|
||||||
rflow = GST_FLOW_ERROR;
|
|
||||||
}
|
}
|
||||||
gst_buffer_unmap (buf, text, text_len);
|
|
||||||
|
GST_LOG_OBJECT (ke, "Encoding text: %*.*s (%u bytes) from %f to %f",
|
||||||
|
(int) text_len, (int) text_len, GST_BUFFER_DATA (buf),
|
||||||
|
GST_BUFFER_SIZE (buf), t0, t1);
|
||||||
|
ret = kate_encode_text (&ke->k, t0, t1, text, text_len, &kp);
|
||||||
|
if (G_UNLIKELY (ret < 0)) {
|
||||||
|
GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
|
||||||
|
("Failed to encode text: %d", ret));
|
||||||
|
rflow = GST_FLOW_ERROR;
|
||||||
|
} else {
|
||||||
|
rflow = gst_kate_enc_chain_push_packet (ke, &kp, start, stop - start + 1);
|
||||||
|
}
|
||||||
|
if (need_unmap)
|
||||||
|
gst_buffer_unmap (buf, text, text_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rflow;
|
return rflow;
|
||||||
|
|
|
@ -296,6 +296,8 @@ gst_template_match_finalize (GObject * object)
|
||||||
if (filter->cvTemplateImage) {
|
if (filter->cvTemplateImage) {
|
||||||
cvReleaseImage (&filter->cvTemplateImage);
|
cvReleaseImage (&filter->cvTemplateImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* chain function
|
/* chain function
|
||||||
|
|
|
@ -470,16 +470,25 @@ create_elements (RsnDvdBin * dvdbin)
|
||||||
RSN_TYPE_STREAM_SELECTOR, "audioselect", "Audio stream selector"))
|
RSN_TYPE_STREAM_SELECTOR, "audioselect", "Audio stream selector"))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
if (!try_create_piece (dvdbin, DVD_ELEM_AUD_MUNGE, NULL,
|
||||||
|
RSN_TYPE_AUDIOMUNGE, "audioearlymunge", "Audio output filter"))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
if (!try_create_piece (dvdbin, DVD_ELEM_AUDDEC, NULL,
|
if (!try_create_piece (dvdbin, DVD_ELEM_AUDDEC, NULL,
|
||||||
RSN_TYPE_AUDIODEC, "auddec", "audio decoder"))
|
RSN_TYPE_AUDIODEC, "auddec", "audio decoder"))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* rsnaudiomunge goes after the audio decoding to regulate the stream */
|
src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUD_MUNGE], "src");
|
||||||
if (!try_create_piece (dvdbin, DVD_ELEM_AUD_MUNGE, NULL,
|
sink = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUDDEC], "sink");
|
||||||
RSN_TYPE_AUDIOMUNGE, "audiomunge", "Audio output filter"))
|
if (src == NULL || sink == NULL)
|
||||||
return FALSE;
|
goto failed_aud_connect;
|
||||||
|
if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
|
||||||
|
goto failed_aud_connect;
|
||||||
|
gst_object_unref (sink);
|
||||||
|
gst_object_unref (src);
|
||||||
|
src = sink = NULL;
|
||||||
|
|
||||||
src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUDDEC], "src");
|
src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUD_SELECT], "src");
|
||||||
sink =
|
sink =
|
||||||
gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUD_MUNGE], "sink");
|
gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUD_MUNGE], "sink");
|
||||||
if (src == NULL || sink == NULL)
|
if (src == NULL || sink == NULL)
|
||||||
|
@ -490,18 +499,8 @@ create_elements (RsnDvdBin * dvdbin)
|
||||||
gst_object_unref (src);
|
gst_object_unref (src);
|
||||||
src = sink = NULL;
|
src = sink = NULL;
|
||||||
|
|
||||||
src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUD_SELECT], "src");
|
|
||||||
sink = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUDDEC], "sink");
|
|
||||||
if (src == NULL || sink == NULL)
|
|
||||||
goto failed_aud_connect;
|
|
||||||
if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
|
|
||||||
goto failed_aud_connect;
|
|
||||||
gst_object_unref (sink);
|
|
||||||
gst_object_unref (src);
|
|
||||||
src = sink = NULL;
|
|
||||||
|
|
||||||
/* ghost audio munge output pad onto bin */
|
/* ghost audio munge output pad onto bin */
|
||||||
src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUD_MUNGE], "src");
|
src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUDDEC], "src");
|
||||||
if (src == NULL)
|
if (src == NULL)
|
||||||
goto failed_aud_ghost;
|
goto failed_aud_ghost;
|
||||||
src_templ = gst_static_pad_template_get (&audio_src_template);
|
src_templ = gst_static_pad_template_get (&audio_src_template);
|
||||||
|
@ -701,7 +700,7 @@ demux_pad_added (GstElement * element, GstPad * pad, RsnDvdBin * dvdbin)
|
||||||
gst_element_get_request_pad (dvdbin->pieces[DVD_ELEM_SPU_SELECT],
|
gst_element_get_request_pad (dvdbin->pieces[DVD_ELEM_SPU_SELECT],
|
||||||
"sink_%u");
|
"sink_%u");
|
||||||
skip_mq = TRUE;
|
skip_mq = TRUE;
|
||||||
} else if (can_sink_caps (dvdbin->pieces[DVD_ELEM_AUDDEC], caps)) {
|
} else if (can_sink_caps (dvdbin->pieces[DVD_ELEM_AUD_MUNGE], caps)) {
|
||||||
GST_LOG_OBJECT (dvdbin, "Found audio pad w/ caps %" GST_PTR_FORMAT, caps);
|
GST_LOG_OBJECT (dvdbin, "Found audio pad w/ caps %" GST_PTR_FORMAT, caps);
|
||||||
dest_pad =
|
dest_pad =
|
||||||
gst_element_get_request_pad (dvdbin->pieces[DVD_ELEM_AUD_SELECT],
|
gst_element_get_request_pad (dvdbin->pieces[DVD_ELEM_AUD_SELECT],
|
||||||
|
@ -720,7 +719,7 @@ demux_pad_added (GstElement * element, GstPad * pad, RsnDvdBin * dvdbin)
|
||||||
("No MPEG video decoder found"));
|
("No MPEG video decoder found"));
|
||||||
} else {
|
} else {
|
||||||
GST_ELEMENT_WARNING (dvdbin, STREAM, CODEC_NOT_FOUND, (NULL),
|
GST_ELEMENT_WARNING (dvdbin, STREAM, CODEC_NOT_FOUND, (NULL),
|
||||||
("No MPEG video decoder found"));
|
("No MPEG audio decoder found"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -269,6 +269,7 @@ rsn_dvdsrc_finalize (GObject * object)
|
||||||
g_mutex_free (src->dvd_lock);
|
g_mutex_free (src->dvd_lock);
|
||||||
g_mutex_free (src->branch_lock);
|
g_mutex_free (src->branch_lock);
|
||||||
g_cond_free (src->still_cond);
|
g_cond_free (src->still_cond);
|
||||||
|
g_free (src->device);
|
||||||
|
|
||||||
gst_buffer_replace (&src->alloc_buf, NULL);
|
gst_buffer_replace (&src->alloc_buf, NULL);
|
||||||
gst_buffer_replace (&src->next_buf, NULL);
|
gst_buffer_replace (&src->next_buf, NULL);
|
||||||
|
|
|
@ -155,9 +155,9 @@ rsn_audiomunge_set_caps (GstPad * pad, GstCaps * caps)
|
||||||
g_return_val_if_fail (munge != NULL, FALSE);
|
g_return_val_if_fail (munge != NULL, FALSE);
|
||||||
|
|
||||||
otherpad = (pad == munge->srcpad) ? munge->sinkpad : munge->srcpad;
|
otherpad = (pad == munge->srcpad) ? munge->sinkpad : munge->srcpad;
|
||||||
gst_object_unref (munge);
|
|
||||||
|
|
||||||
ret = gst_pad_set_caps (otherpad, caps);
|
ret = gst_pad_set_caps (otherpad, caps);
|
||||||
|
gst_object_unref (munge);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -247,18 +247,50 @@ _get_decoder_factories (gpointer arg)
|
||||||
GstPadTemplate *templ = gst_element_class_get_pad_template (klass,
|
GstPadTemplate *templ = gst_element_class_get_pad_template (klass,
|
||||||
"sink");
|
"sink");
|
||||||
RsnDecFactoryFilterCtx ctx = { NULL, };
|
RsnDecFactoryFilterCtx ctx = { NULL, };
|
||||||
|
GstCaps *raw;
|
||||||
|
gboolean raw_audio;
|
||||||
|
|
||||||
ctx.desired_caps = gst_pad_template_get_caps (templ);
|
ctx.desired_caps = gst_pad_template_get_caps (templ);
|
||||||
|
|
||||||
|
raw = gst_caps_from_string ("audio/x-raw-float");
|
||||||
|
raw_audio = gst_caps_can_intersect (raw, ctx.desired_caps);
|
||||||
|
if (raw_audio) {
|
||||||
|
GstCaps *sub = gst_caps_subtract (ctx.desired_caps, raw);
|
||||||
|
ctx.desired_caps = sub;
|
||||||
|
} else {
|
||||||
|
gst_caps_ref (ctx.desired_caps);
|
||||||
|
}
|
||||||
|
gst_caps_unref (raw);
|
||||||
|
|
||||||
/* Set decoder caps to empty. Will be filled by the factory_filter */
|
/* Set decoder caps to empty. Will be filled by the factory_filter */
|
||||||
ctx.decoder_caps = gst_caps_new_empty ();
|
ctx.decoder_caps = gst_caps_new_empty ();
|
||||||
|
GST_DEBUG ("Finding factories for caps: %" GST_PTR_FORMAT, ctx.desired_caps);
|
||||||
|
|
||||||
factories = gst_default_registry_feature_filter (
|
factories = gst_default_registry_feature_filter (
|
||||||
(GstPluginFeatureFilter) rsndec_factory_filter, FALSE, &ctx);
|
(GstPluginFeatureFilter) rsndec_factory_filter, FALSE, &ctx);
|
||||||
|
|
||||||
|
/* If these are audio caps, we add audioconvert, which is not a decoder,
|
||||||
|
but allows raw audio to go through relatively unmolested - this will
|
||||||
|
come handy when we have to send placeholder silence to allow preroll
|
||||||
|
for those DVDs which have titles with no audio track. */
|
||||||
|
if (raw_audio) {
|
||||||
|
GstPluginFeature *feature;
|
||||||
|
GST_DEBUG ("These are audio caps, adding audioconvert");
|
||||||
|
feature =
|
||||||
|
gst_default_registry_find_feature ("audioconvert",
|
||||||
|
GST_TYPE_ELEMENT_FACTORY);
|
||||||
|
if (feature) {
|
||||||
|
factories = g_list_append (factories, feature);
|
||||||
|
} else {
|
||||||
|
GST_WARNING ("Could not find feature audioconvert");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
factories = g_list_sort (factories, (GCompareFunc) sort_by_ranks);
|
factories = g_list_sort (factories, (GCompareFunc) sort_by_ranks);
|
||||||
|
|
||||||
GST_DEBUG ("Available decoder caps %" GST_PTR_FORMAT, ctx.decoder_caps);
|
GST_DEBUG ("Available decoder caps %" GST_PTR_FORMAT, ctx.decoder_caps);
|
||||||
gst_caps_unref (ctx.decoder_caps);
|
gst_caps_unref (ctx.decoder_caps);
|
||||||
|
gst_caps_unref (ctx.desired_caps);
|
||||||
|
|
||||||
return factories;
|
return factories;
|
||||||
}
|
}
|
||||||
|
@ -343,7 +375,7 @@ static GstStaticPadTemplate audio_sink_template =
|
||||||
GST_STATIC_CAPS ("audio/mpeg,mpegversion=(int)1;"
|
GST_STATIC_CAPS ("audio/mpeg,mpegversion=(int)1;"
|
||||||
"audio/x-private1-lpcm;"
|
"audio/x-private1-lpcm;"
|
||||||
"audio/x-private1-ac3;" "audio/ac3;" "audio/x-ac3;"
|
"audio/x-private1-ac3;" "audio/ac3;" "audio/x-ac3;"
|
||||||
"audio/x-private1-dts;")
|
"audio/x-private1-dts; audio/x-raw-float")
|
||||||
);
|
);
|
||||||
|
|
||||||
static GstStaticPadTemplate audio_src_template = GST_STATIC_PAD_TEMPLATE ("src",
|
static GstStaticPadTemplate audio_src_template = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
|
|
|
@ -123,6 +123,8 @@ static GstStaticPadTemplate data_sink_template =
|
||||||
GST_BOILERPLATE (GstRsvgOverlay, gst_rsvg_overlay, GstVideoFilter,
|
GST_BOILERPLATE (GstRsvgOverlay, gst_rsvg_overlay, GstVideoFilter,
|
||||||
GST_TYPE_VIDEO_FILTER);
|
GST_TYPE_VIDEO_FILTER);
|
||||||
|
|
||||||
|
static void gst_rsvg_overlay_finalize (GObject * object);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rsvg_overlay_set_svg_data (GstRsvgOverlay * overlay, const gchar * data,
|
gst_rsvg_overlay_set_svg_data (GstRsvgOverlay * overlay, const gchar * data,
|
||||||
gboolean consider_as_filename)
|
gboolean consider_as_filename)
|
||||||
|
@ -467,6 +469,7 @@ gst_rsvg_overlay_class_init (GstRsvgOverlayClass * klass)
|
||||||
|
|
||||||
gobject_class->set_property = gst_rsvg_overlay_set_property;
|
gobject_class->set_property = gst_rsvg_overlay_set_property;
|
||||||
gobject_class->get_property = gst_rsvg_overlay_get_property;
|
gobject_class->get_property = gst_rsvg_overlay_get_property;
|
||||||
|
gobject_class->finalize = gst_rsvg_overlay_finalize;
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DATA,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DATA,
|
||||||
g_param_spec_string ("data", "data", "SVG data.", "",
|
g_param_spec_string ("data", "data", "SVG data.", "",
|
||||||
|
@ -542,3 +545,13 @@ gst_rsvg_overlay_init (GstRsvgOverlay * overlay, GstRsvgOverlayClass * klass)
|
||||||
GST_DEBUG_FUNCPTR (gst_rsvg_overlay_data_sink_event));
|
GST_DEBUG_FUNCPTR (gst_rsvg_overlay_data_sink_event));
|
||||||
gst_element_add_pad (GST_ELEMENT (overlay), overlay->data_sinkpad);
|
gst_element_add_pad (GST_ELEMENT (overlay), overlay->data_sinkpad);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_rsvg_overlay_finalize (GObject * object)
|
||||||
|
{
|
||||||
|
GstRsvgOverlay *overlay = GST_RSVG_OVERLAY (object);
|
||||||
|
|
||||||
|
g_object_unref (overlay->adapter);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ static GstStaticPadTemplate gst_schro_dec_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ I420, YUY2, AYUV }"))
|
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV (GST_SCHRO_YUV_LIST))
|
||||||
);
|
);
|
||||||
|
|
||||||
GST_BOILERPLATE (GstSchroDec, gst_schro_dec, GstBaseVideoDecoder,
|
GST_BOILERPLATE (GstSchroDec, gst_schro_dec, GstBaseVideoDecoder,
|
||||||
|
@ -313,12 +313,25 @@ parse_sequence_header (GstSchroDec * schro_dec, guint8 * data, int size)
|
||||||
ret = schro_parse_decode_sequence_header (data + 13, size - 13,
|
ret = schro_parse_decode_sequence_header (data + 13, size - 13,
|
||||||
&video_format);
|
&video_format);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (video_format.chroma_format == SCHRO_CHROMA_444) {
|
int bit_depth;
|
||||||
state->format = GST_VIDEO_FORMAT_AYUV;
|
|
||||||
} else if (video_format.chroma_format == SCHRO_CHROMA_422) {
|
bit_depth = schro_video_format_get_bit_depth (&video_format);
|
||||||
state->format = GST_VIDEO_FORMAT_YUY2;
|
|
||||||
} else if (video_format.chroma_format == SCHRO_CHROMA_420) {
|
if (bit_depth == 8) {
|
||||||
state->format = GST_VIDEO_FORMAT_I420;
|
if (video_format.chroma_format == SCHRO_CHROMA_444) {
|
||||||
|
state->format = GST_VIDEO_FORMAT_AYUV;
|
||||||
|
} else if (video_format.chroma_format == SCHRO_CHROMA_422) {
|
||||||
|
state->format = GST_VIDEO_FORMAT_UYVY;
|
||||||
|
} else if (video_format.chroma_format == SCHRO_CHROMA_420) {
|
||||||
|
state->format = GST_VIDEO_FORMAT_I420;
|
||||||
|
}
|
||||||
|
} else if (bit_depth <= 10) {
|
||||||
|
state->format = GST_VIDEO_FORMAT_v210;
|
||||||
|
} else if (bit_depth <= 16) {
|
||||||
|
state->format = GST_VIDEO_FORMAT_AYUV64;
|
||||||
|
} else {
|
||||||
|
GST_ERROR ("bit depth too large (%d > 16)", bit_depth);
|
||||||
|
state->format = GST_VIDEO_FORMAT_AYUV64;
|
||||||
}
|
}
|
||||||
state->fps_n = video_format.frame_rate_numerator;
|
state->fps_n = video_format.frame_rate_numerator;
|
||||||
state->fps_d = video_format.frame_rate_denominator;
|
state->fps_d = video_format.frame_rate_denominator;
|
||||||
|
|
|
@ -107,7 +107,7 @@ static GstStaticPadTemplate gst_schro_enc_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ I420, YV12, YUY2, UYVY, AYUV }"))
|
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV (GST_SCHRO_YUV_LIST))
|
||||||
);
|
);
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_schro_enc_src_template =
|
static GstStaticPadTemplate gst_schro_enc_src_template =
|
||||||
|
@ -271,13 +271,18 @@ gst_schro_enc_set_format (GstBaseVideoEncoder * base_video_encoder,
|
||||||
switch (state->format) {
|
switch (state->format) {
|
||||||
case GST_VIDEO_FORMAT_I420:
|
case GST_VIDEO_FORMAT_I420:
|
||||||
case GST_VIDEO_FORMAT_YV12:
|
case GST_VIDEO_FORMAT_YV12:
|
||||||
|
case GST_VIDEO_FORMAT_Y42B:
|
||||||
schro_enc->video_format->chroma_format = SCHRO_CHROMA_420;
|
schro_enc->video_format->chroma_format = SCHRO_CHROMA_420;
|
||||||
break;
|
break;
|
||||||
case GST_VIDEO_FORMAT_YUY2:
|
case GST_VIDEO_FORMAT_YUY2:
|
||||||
case GST_VIDEO_FORMAT_UYVY:
|
case GST_VIDEO_FORMAT_UYVY:
|
||||||
|
case GST_VIDEO_FORMAT_v216:
|
||||||
|
case GST_VIDEO_FORMAT_v210:
|
||||||
schro_enc->video_format->chroma_format = SCHRO_CHROMA_422;
|
schro_enc->video_format->chroma_format = SCHRO_CHROMA_422;
|
||||||
break;
|
break;
|
||||||
case GST_VIDEO_FORMAT_AYUV:
|
case GST_VIDEO_FORMAT_AYUV:
|
||||||
|
case GST_VIDEO_FORMAT_Y444:
|
||||||
|
case GST_VIDEO_FORMAT_AYUV64:
|
||||||
schro_enc->video_format->chroma_format = SCHRO_CHROMA_444;
|
schro_enc->video_format->chroma_format = SCHRO_CHROMA_444;
|
||||||
break;
|
break;
|
||||||
case GST_VIDEO_FORMAT_ARGB:
|
case GST_VIDEO_FORMAT_ARGB:
|
||||||
|
@ -300,8 +305,24 @@ gst_schro_enc_set_format (GstBaseVideoEncoder * base_video_encoder,
|
||||||
schro_enc->video_format->aspect_ratio_numerator = state->par_n;
|
schro_enc->video_format->aspect_ratio_numerator = state->par_n;
|
||||||
schro_enc->video_format->aspect_ratio_denominator = state->par_d;
|
schro_enc->video_format->aspect_ratio_denominator = state->par_d;
|
||||||
|
|
||||||
schro_video_format_set_std_signal_range (schro_enc->video_format,
|
switch (state->format) {
|
||||||
SCHRO_SIGNAL_RANGE_8BIT_VIDEO);
|
default:
|
||||||
|
schro_video_format_set_std_signal_range (schro_enc->video_format,
|
||||||
|
SCHRO_SIGNAL_RANGE_8BIT_VIDEO);
|
||||||
|
break;
|
||||||
|
case GST_VIDEO_FORMAT_v210:
|
||||||
|
schro_video_format_set_std_signal_range (schro_enc->video_format,
|
||||||
|
SCHRO_SIGNAL_RANGE_10BIT_VIDEO);
|
||||||
|
break;
|
||||||
|
case GST_VIDEO_FORMAT_v216:
|
||||||
|
case GST_VIDEO_FORMAT_AYUV64:
|
||||||
|
schro_enc->video_format->luma_offset = 64 << 8;
|
||||||
|
schro_enc->video_format->luma_excursion = 219 << 8;
|
||||||
|
schro_enc->video_format->chroma_offset = 128 << 8;
|
||||||
|
schro_enc->video_format->chroma_excursion = 224 << 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
schro_video_format_set_std_colour_spec (schro_enc->video_format,
|
schro_video_format_set_std_colour_spec (schro_enc->video_format,
|
||||||
SCHRO_COLOUR_SPEC_HDTV);
|
SCHRO_COLOUR_SPEC_HDTV);
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,29 @@ gst_schro_buffer_wrap (GstBuffer * buf, GstVideoFormat format, int width,
|
||||||
frame =
|
frame =
|
||||||
schro_frame_new_from_data_AYUV (GST_BUFFER_DATA (buf), width, height);
|
schro_frame_new_from_data_AYUV (GST_BUFFER_DATA (buf), width, height);
|
||||||
break;
|
break;
|
||||||
|
case GST_VIDEO_FORMAT_Y42B:
|
||||||
|
frame =
|
||||||
|
schro_frame_new_from_data_Y42B (GST_BUFFER_DATA (buf), width, height);
|
||||||
|
break;
|
||||||
|
case GST_VIDEO_FORMAT_Y444:
|
||||||
|
frame =
|
||||||
|
schro_frame_new_from_data_Y444 (GST_BUFFER_DATA (buf), width, height);
|
||||||
|
break;
|
||||||
|
case GST_VIDEO_FORMAT_v210:
|
||||||
|
frame =
|
||||||
|
schro_frame_new_from_data_v210 (GST_BUFFER_DATA (buf), width, height);
|
||||||
|
break;
|
||||||
|
case GST_VIDEO_FORMAT_v216:
|
||||||
|
frame =
|
||||||
|
schro_frame_new_from_data_v216 (GST_BUFFER_DATA (buf), width, height);
|
||||||
|
break;
|
||||||
|
#ifdef SCHRO_FRAME_FORMAT_AY64
|
||||||
|
/* Added in 1.0.11 */
|
||||||
|
case GST_VIDEO_FORMAT_AYUV64:
|
||||||
|
frame =
|
||||||
|
schro_frame_new_from_data_AY64 (GST_BUFFER_DATA (buf), width, height);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
#if 0
|
#if 0
|
||||||
case GST_VIDEO_FORMAT_ARGB:
|
case GST_VIDEO_FORMAT_ARGB:
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,6 +24,12 @@
|
||||||
#include <gst/video/video.h>
|
#include <gst/video/video.h>
|
||||||
#include <schroedinger/schro.h>
|
#include <schroedinger/schro.h>
|
||||||
|
|
||||||
|
#ifdef SCHRO_FRAME_FORMAT_AY64
|
||||||
|
#define GST_SCHRO_YUV_LIST "{ I420, YV12, YUY2, UYVY, AYUV, Y42B, Y444, v216, v210, AY64 }"
|
||||||
|
#else
|
||||||
|
#define GST_SCHRO_YUV_LIST "{ I420, YV12, YUY2, UYVY, AYUV, Y42B, Y444 }"
|
||||||
|
#endif
|
||||||
|
|
||||||
SchroFrame *
|
SchroFrame *
|
||||||
gst_schro_buffer_wrap (GstBuffer *buf, GstVideoFormat format, int width,
|
gst_schro_buffer_wrap (GstBuffer *buf, GstVideoFormat format, int width,
|
||||||
int height);
|
int height);
|
||||||
|
|
|
@ -169,6 +169,8 @@ gst_spc_dec_dispose (GObject * object)
|
||||||
}
|
}
|
||||||
|
|
||||||
spc_tag_free (&spc->tag_info);
|
spc_tag_free (&spc->tag_info);
|
||||||
|
|
||||||
|
GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
|
|
|
@ -1174,6 +1174,9 @@ gst_vp8_enc_shape_output (GstBaseVideoEncoder * base_video_encoder,
|
||||||
gst_util_uint64_scale (frame->presentation_frame_number + 1,
|
gst_util_uint64_scale (frame->presentation_frame_number + 1,
|
||||||
GST_SECOND * state->fps_d, state->fps_n);
|
GST_SECOND * state->fps_d, state->fps_n);
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (base_video_encoder, "src ts: %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
|
||||||
|
|
||||||
ret = gst_pad_push (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), buf);
|
ret = gst_pad_push (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), buf);
|
||||||
if (ret != GST_FLOW_OK) {
|
if (ret != GST_FLOW_OK) {
|
||||||
GST_WARNING_OBJECT (encoder, "flow error %d", ret);
|
GST_WARNING_OBJECT (encoder, "flow error %d", ret);
|
||||||
|
|
|
@ -518,6 +518,7 @@ gst_h264_parse_hrd_parameters (GstH264HRDParams * hrd, NalReader * nr)
|
||||||
for (sched_sel_idx = 0; sched_sel_idx <= hrd->cpb_cnt_minus1; sched_sel_idx++) {
|
for (sched_sel_idx = 0; sched_sel_idx <= hrd->cpb_cnt_minus1; sched_sel_idx++) {
|
||||||
READ_UE (nr, hrd->bit_rate_value_minus1[sched_sel_idx]);
|
READ_UE (nr, hrd->bit_rate_value_minus1[sched_sel_idx]);
|
||||||
READ_UE (nr, hrd->cpb_size_value_minus1[sched_sel_idx]);
|
READ_UE (nr, hrd->cpb_size_value_minus1[sched_sel_idx]);
|
||||||
|
READ_UINT8 (nr, hrd->cbr_flag[sched_sel_idx], 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
READ_UINT8 (nr, hrd->initial_cpb_removal_delay_length_minus1, 5);
|
READ_UINT8 (nr, hrd->initial_cpb_removal_delay_length_minus1, 5);
|
||||||
|
@ -747,22 +748,26 @@ slice_parse_ref_pic_list_modification_1 (GstH264SliceHdr * slice,
|
||||||
NalReader * nr, guint list)
|
NalReader * nr, guint list)
|
||||||
{
|
{
|
||||||
GstH264RefPicListModification *entries;
|
GstH264RefPicListModification *entries;
|
||||||
guint8 *ref_pic_list_modification_flag;
|
guint8 *ref_pic_list_modification_flag, *n_ref_pic_list_modification;
|
||||||
guint32 modification_of_pic_nums_idc;
|
guint32 modification_of_pic_nums_idc;
|
||||||
guint i = 0;
|
guint i = 0;
|
||||||
|
|
||||||
if (list == 0) {
|
if (list == 0) {
|
||||||
entries = slice->ref_pic_list_modification_l0;
|
entries = slice->ref_pic_list_modification_l0;
|
||||||
ref_pic_list_modification_flag = &slice->ref_pic_list_modification_flag_l0;
|
ref_pic_list_modification_flag = &slice->ref_pic_list_modification_flag_l0;
|
||||||
|
n_ref_pic_list_modification = &slice->n_ref_pic_list_modification_l0;
|
||||||
} else {
|
} else {
|
||||||
entries = slice->ref_pic_list_modification_l1;
|
entries = slice->ref_pic_list_modification_l1;
|
||||||
ref_pic_list_modification_flag = &slice->ref_pic_list_modification_flag_l1;
|
ref_pic_list_modification_flag = &slice->ref_pic_list_modification_flag_l1;
|
||||||
|
n_ref_pic_list_modification = &slice->n_ref_pic_list_modification_l1;
|
||||||
}
|
}
|
||||||
|
|
||||||
READ_UINT8 (nr, *ref_pic_list_modification_flag, 1);
|
READ_UINT8 (nr, *ref_pic_list_modification_flag, 1);
|
||||||
if (*ref_pic_list_modification_flag) {
|
if (*ref_pic_list_modification_flag) {
|
||||||
do {
|
while (1) {
|
||||||
READ_UE (nr, modification_of_pic_nums_idc);
|
READ_UE (nr, modification_of_pic_nums_idc);
|
||||||
|
if (modification_of_pic_nums_idc == 3)
|
||||||
|
break;
|
||||||
if (modification_of_pic_nums_idc == 0 ||
|
if (modification_of_pic_nums_idc == 0 ||
|
||||||
modification_of_pic_nums_idc == 1) {
|
modification_of_pic_nums_idc == 1) {
|
||||||
READ_UE_ALLOWED (nr, entries[i].value.abs_diff_pic_num_minus1, 0,
|
READ_UE_ALLOWED (nr, entries[i].value.abs_diff_pic_num_minus1, 0,
|
||||||
|
@ -770,9 +775,10 @@ slice_parse_ref_pic_list_modification_1 (GstH264SliceHdr * slice,
|
||||||
} else if (modification_of_pic_nums_idc == 2) {
|
} else if (modification_of_pic_nums_idc == 2) {
|
||||||
READ_UE (nr, entries[i].value.long_term_pic_num);
|
READ_UE (nr, entries[i].value.long_term_pic_num);
|
||||||
}
|
}
|
||||||
} while (modification_of_pic_nums_idc != 3);
|
entries[i++].modification_of_pic_nums_idc = modification_of_pic_nums_idc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
*n_ref_pic_list_modification = i;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
@ -1050,6 +1056,8 @@ gst_h264_parse_clock_timestamp (GstH264ClockTimestamp * tim,
|
||||||
if (time_offset_length > 0)
|
if (time_offset_length > 0)
|
||||||
READ_UINT32 (nr, tim->time_offset, time_offset_length);
|
READ_UINT32 (nr, tim->time_offset, time_offset_length);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
GST_WARNING ("error parsing \"Clock timestamp\"");
|
GST_WARNING ("error parsing \"Clock timestamp\"");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
|
@ -573,8 +573,10 @@ struct _GstH264SliceHdr
|
||||||
guint8 num_ref_idx_l1_active_minus1;
|
guint8 num_ref_idx_l1_active_minus1;
|
||||||
|
|
||||||
guint8 ref_pic_list_modification_flag_l0;
|
guint8 ref_pic_list_modification_flag_l0;
|
||||||
|
guint8 n_ref_pic_list_modification_l0;
|
||||||
GstH264RefPicListModification ref_pic_list_modification_l0[32];
|
GstH264RefPicListModification ref_pic_list_modification_l0[32];
|
||||||
guint8 ref_pic_list_modification_flag_l1;
|
guint8 ref_pic_list_modification_flag_l1;
|
||||||
|
guint8 n_ref_pic_list_modification_l1;
|
||||||
GstH264RefPicListModification ref_pic_list_modification_l1[32];
|
GstH264RefPicListModification ref_pic_list_modification_l1[32];
|
||||||
|
|
||||||
GstH264PredWeightTable pred_weight_table;
|
GstH264PredWeightTable pred_weight_table;
|
||||||
|
|
|
@ -1132,7 +1132,7 @@ void
|
||||||
gst_base_video_encoder_set_latency (GstBaseVideoEncoder * base_video_encoder,
|
gst_base_video_encoder_set_latency (GstBaseVideoEncoder * base_video_encoder,
|
||||||
GstClockTime min_latency, GstClockTime max_latency)
|
GstClockTime min_latency, GstClockTime max_latency)
|
||||||
{
|
{
|
||||||
g_return_if_fail (min_latency >= 0);
|
g_return_if_fail (GST_CLOCK_TIME_IS_VALID (min_latency));
|
||||||
g_return_if_fail (max_latency >= min_latency);
|
g_return_if_fail (max_latency >= min_latency);
|
||||||
|
|
||||||
GST_OBJECT_LOCK (base_video_encoder);
|
GST_OBJECT_LOCK (base_video_encoder);
|
||||||
|
|
|
@ -5,8 +5,9 @@ libgstadpcmdec_la_SOURCES = adpcmdec.c
|
||||||
|
|
||||||
# flags used to compile this plugin
|
# flags used to compile this plugin
|
||||||
# add other _CFLAGS and _LIBS as needed
|
# add other _CFLAGS and _LIBS as needed
|
||||||
libgstadpcmdec_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS)
|
libgstadpcmdec_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
|
||||||
libgstadpcmdec_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS)
|
libgstadpcmdec_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-@GST_MAJORMINOR@ \
|
||||||
|
$(GST_LIBS)
|
||||||
libgstadpcmdec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
libgstadpcmdec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
libgstadpcmdec_la_LIBTOOLFLAGS = --tag=disable-static
|
libgstadpcmdec_la_LIBTOOLFLAGS = --tag=disable-static
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/audio/gstaudiodecoder.h>
|
||||||
|
|
||||||
#define GST_TYPE_ADPCM_DEC \
|
#define GST_TYPE_ADPCM_DEC \
|
||||||
(adpcmdec_get_type ())
|
(adpcmdec_get_type ())
|
||||||
|
@ -69,80 +69,29 @@ enum adpcm_layout
|
||||||
|
|
||||||
typedef struct _ADPCMDecClass
|
typedef struct _ADPCMDecClass
|
||||||
{
|
{
|
||||||
GstElementClass parent_class;
|
GstAudioDecoderClass parent_class;
|
||||||
} ADPCMDecClass;
|
} ADPCMDecClass;
|
||||||
|
|
||||||
typedef struct _ADPCMDec
|
typedef struct _ADPCMDec
|
||||||
{
|
{
|
||||||
GstElement parent;
|
GstAudioDecoder parent;
|
||||||
|
|
||||||
GstPad *sinkpad;
|
|
||||||
GstPad *srcpad;
|
|
||||||
|
|
||||||
GstCaps *output_caps;
|
|
||||||
|
|
||||||
enum adpcm_layout layout;
|
enum adpcm_layout layout;
|
||||||
int rate;
|
int rate;
|
||||||
int channels;
|
int channels;
|
||||||
int blocksize;
|
int blocksize;
|
||||||
|
|
||||||
gboolean is_setup;
|
|
||||||
|
|
||||||
GstClockTime timestamp;
|
|
||||||
GstClockTime base_timestamp;
|
|
||||||
|
|
||||||
guint64 out_samples;
|
|
||||||
|
|
||||||
GstAdapter *adapter;
|
|
||||||
|
|
||||||
} ADPCMDec;
|
} ADPCMDec;
|
||||||
|
|
||||||
GType adpcmdec_get_type (void);
|
GType adpcmdec_get_type (void);
|
||||||
GST_BOILERPLATE (ADPCMDec, adpcmdec, GstElement, GST_TYPE_ELEMENT);
|
GST_BOILERPLATE (ADPCMDec, adpcmdec, GstAudioDecoder, GST_TYPE_AUDIO_DECODER);
|
||||||
static gboolean
|
|
||||||
adpcmdec_setup (ADPCMDec * dec)
|
|
||||||
{
|
|
||||||
dec->output_caps = gst_caps_new_simple ("audio/x-raw-int",
|
|
||||||
"rate", G_TYPE_INT, dec->rate,
|
|
||||||
"channels", G_TYPE_INT, dec->channels,
|
|
||||||
"width", G_TYPE_INT, 16,
|
|
||||||
"depth", G_TYPE_INT, 16,
|
|
||||||
"endianness", G_TYPE_INT, G_BYTE_ORDER,
|
|
||||||
"signed", G_TYPE_BOOLEAN, TRUE, NULL);
|
|
||||||
|
|
||||||
if (dec->output_caps) {
|
|
||||||
gst_pad_set_caps (dec->srcpad, dec->output_caps);
|
|
||||||
}
|
|
||||||
|
|
||||||
dec->is_setup = TRUE;
|
|
||||||
dec->timestamp = GST_CLOCK_TIME_NONE;
|
|
||||||
dec->base_timestamp = GST_CLOCK_TIME_NONE;
|
|
||||||
dec->adapter = gst_adapter_new ();
|
|
||||||
dec->out_samples = 0;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
adpcmdec_teardown (ADPCMDec * dec)
|
|
||||||
{
|
|
||||||
if (dec->output_caps) {
|
|
||||||
gst_caps_unref (dec->output_caps);
|
|
||||||
dec->output_caps = NULL;
|
|
||||||
}
|
|
||||||
if (dec->adapter) {
|
|
||||||
g_object_unref (dec->adapter);
|
|
||||||
dec->adapter = NULL;
|
|
||||||
}
|
|
||||||
dec->is_setup = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
adpcmdec_sink_setcaps (GstPad * pad, GstCaps * caps)
|
adpcmdec_set_format (GstAudioDecoder * bdec, GstCaps * in_caps)
|
||||||
{
|
{
|
||||||
ADPCMDec *dec = (ADPCMDec *) gst_pad_get_parent (pad);
|
ADPCMDec *dec = (ADPCMDec *) (bdec);
|
||||||
GstStructure *structure = gst_caps_get_structure (caps, 0);
|
GstStructure *structure = gst_caps_get_structure (in_caps, 0);
|
||||||
const gchar *layout;
|
const gchar *layout;
|
||||||
|
GstCaps *caps;
|
||||||
|
|
||||||
layout = gst_structure_get_string (structure, "layout");
|
layout = gst_structure_get_string (structure, "layout");
|
||||||
if (!layout)
|
if (!layout)
|
||||||
|
@ -163,9 +112,16 @@ adpcmdec_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
if (!gst_structure_get_int (structure, "channels", &dec->channels))
|
if (!gst_structure_get_int (structure, "channels", &dec->channels))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (dec->is_setup)
|
caps = gst_caps_new_simple ("audio/x-raw-int",
|
||||||
adpcmdec_teardown (dec);
|
"rate", G_TYPE_INT, dec->rate,
|
||||||
gst_object_unref (dec);
|
"channels", G_TYPE_INT, dec->channels,
|
||||||
|
"width", G_TYPE_INT, 16,
|
||||||
|
"depth", G_TYPE_INT, 16,
|
||||||
|
"endianness", G_TYPE_INT, G_BYTE_ORDER,
|
||||||
|
"signed", G_TYPE_BOOLEAN, TRUE, NULL);
|
||||||
|
|
||||||
|
gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (bdec), caps);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -377,10 +333,10 @@ adpcmdec_decode_ima_block (ADPCMDec * dec, int n_samples, const guint8 * data,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstBuffer *
|
||||||
adpcmdec_decode_block (ADPCMDec * dec, const guint8 * data, int blocksize)
|
adpcmdec_decode_block (ADPCMDec * dec, const guint8 * data, int blocksize)
|
||||||
{
|
{
|
||||||
gboolean res;
|
gboolean res = FALSE;
|
||||||
GstBuffer *outbuf = NULL;
|
GstBuffer *outbuf = NULL;
|
||||||
int outsize;
|
int outsize;
|
||||||
int samples;
|
int samples;
|
||||||
|
@ -390,7 +346,7 @@ adpcmdec_decode_block (ADPCMDec * dec, const guint8 * data, int blocksize)
|
||||||
give two initial sample values per channel. Then the remainder gives
|
give two initial sample values per channel. Then the remainder gives
|
||||||
two samples per byte */
|
two samples per byte */
|
||||||
if (blocksize < 7 * dec->channels)
|
if (blocksize < 7 * dec->channels)
|
||||||
return GST_FLOW_ERROR;
|
goto exit;
|
||||||
samples = (blocksize - 7 * dec->channels) * 2 + 2 * dec->channels;
|
samples = (blocksize - 7 * dec->channels) * 2 + 2 * dec->channels;
|
||||||
outsize = 2 * samples;
|
outsize = 2 * samples;
|
||||||
outbuf = gst_buffer_new_and_alloc (outsize);
|
outbuf = gst_buffer_new_and_alloc (outsize);
|
||||||
|
@ -401,7 +357,7 @@ adpcmdec_decode_block (ADPCMDec * dec, const guint8 * data, int blocksize)
|
||||||
/* Each block has a 4 byte header per channel, include an initial sample.
|
/* Each block has a 4 byte header per channel, include an initial sample.
|
||||||
Then the remainder gives two samples per byte */
|
Then the remainder gives two samples per byte */
|
||||||
if (blocksize < 4 * dec->channels)
|
if (blocksize < 4 * dec->channels)
|
||||||
return GST_FLOW_ERROR;
|
goto exit;
|
||||||
samples = (blocksize - 4 * dec->channels) * 2 + dec->channels;
|
samples = (blocksize - 4 * dec->channels) * 2 + dec->channels;
|
||||||
outsize = 2 * samples;
|
outsize = 2 * samples;
|
||||||
outbuf = gst_buffer_new_and_alloc (outsize);
|
outbuf = gst_buffer_new_and_alloc (outsize);
|
||||||
|
@ -410,155 +366,114 @@ adpcmdec_decode_block (ADPCMDec * dec, const guint8 * data, int blocksize)
|
||||||
(gint16 *) (GST_BUFFER_DATA (outbuf)));
|
(gint16 *) (GST_BUFFER_DATA (outbuf)));
|
||||||
} else {
|
} else {
|
||||||
GST_WARNING_OBJECT (dec, "Unknown layout");
|
GST_WARNING_OBJECT (dec, "Unknown layout");
|
||||||
return GST_FLOW_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
gst_buffer_unref (outbuf);
|
if (outbuf)
|
||||||
|
gst_buffer_unref (outbuf);
|
||||||
|
outbuf = NULL;
|
||||||
GST_WARNING_OBJECT (dec, "Decode of block failed");
|
GST_WARNING_OBJECT (dec, "Decode of block failed");
|
||||||
return GST_FLOW_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_buffer_set_caps (outbuf, dec->output_caps);
|
exit:
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = dec->timestamp;
|
return outbuf;
|
||||||
dec->out_samples += samples / dec->channels;
|
|
||||||
dec->timestamp = dec->base_timestamp +
|
|
||||||
gst_util_uint64_scale_int (dec->out_samples, GST_SECOND, dec->rate);
|
|
||||||
GST_BUFFER_DURATION (outbuf) = dec->timestamp - GST_BUFFER_TIMESTAMP (outbuf);
|
|
||||||
|
|
||||||
return gst_pad_push (dec->srcpad, outbuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
adpcmdec_chain (GstPad * pad, GstBuffer * buf)
|
adpcmdec_parse (GstAudioDecoder * bdec, GstAdapter * adapter,
|
||||||
|
gint * offset, gint * length)
|
||||||
{
|
{
|
||||||
ADPCMDec *dec = (ADPCMDec *) gst_pad_get_parent (pad);
|
ADPCMDec *dec = (ADPCMDec *) (bdec);
|
||||||
|
guint size;
|
||||||
|
|
||||||
|
size = gst_adapter_available (adapter);
|
||||||
|
g_return_val_if_fail (size > 0, GST_FLOW_ERROR);
|
||||||
|
|
||||||
|
if (dec->blocksize < 0) {
|
||||||
|
/* No explicit blocksize; we just process one input buffer at a time */
|
||||||
|
*offset = 0;
|
||||||
|
*length = size;
|
||||||
|
} else {
|
||||||
|
if (size >= dec->blocksize) {
|
||||||
|
*offset = 0;
|
||||||
|
*length = dec->blocksize;
|
||||||
|
} else {
|
||||||
|
return GST_FLOW_UNEXPECTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
adpcmdec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
ADPCMDec *dec = (ADPCMDec *) (bdec);
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
guint8 *data;
|
guint8 *data;
|
||||||
GstBuffer *databuf = NULL;
|
GstBuffer *outbuf = NULL;
|
||||||
|
|
||||||
if (!dec->is_setup)
|
/* no fancy draining */
|
||||||
adpcmdec_setup (dec);
|
if (G_UNLIKELY (!buffer))
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
if (dec->base_timestamp == GST_CLOCK_TIME_NONE) {
|
if (!dec->blocksize)
|
||||||
dec->base_timestamp = GST_BUFFER_TIMESTAMP (buf);
|
return GST_FLOW_NOT_NEGOTIATED;
|
||||||
if (dec->base_timestamp == GST_CLOCK_TIME_NONE)
|
|
||||||
dec->base_timestamp = 0;
|
data = GST_BUFFER_DATA (buffer);
|
||||||
dec->timestamp = dec->base_timestamp;
|
outbuf = adpcmdec_decode_block (dec, data, dec->blocksize);
|
||||||
|
|
||||||
|
if (outbuf == NULL) {
|
||||||
|
GST_AUDIO_DECODER_ERROR (bdec, 1, STREAM, DECODE, (NULL),
|
||||||
|
("frame decode failed"), ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dec->blocksize > 0) {
|
if (ret == GST_FLOW_OK)
|
||||||
gst_adapter_push (dec->adapter, buf);
|
ret = gst_audio_decoder_finish_frame (bdec, outbuf, 1);
|
||||||
|
|
||||||
while (gst_adapter_available (dec->adapter) >= dec->blocksize) {
|
|
||||||
databuf = gst_adapter_take_buffer (dec->adapter, dec->blocksize);
|
|
||||||
data = GST_BUFFER_DATA (databuf);
|
|
||||||
|
|
||||||
ret = adpcmdec_decode_block (dec, data, dec->blocksize);
|
|
||||||
|
|
||||||
/* Done with input data, free it */
|
|
||||||
gst_buffer_unref (databuf);
|
|
||||||
|
|
||||||
if (ret != GST_FLOW_OK)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* No explicit blocksize; we just process one input buffer at a time */
|
|
||||||
ret = adpcmdec_decode_block (dec, GST_BUFFER_DATA (buf),
|
|
||||||
GST_BUFFER_SIZE (buf));
|
|
||||||
gst_buffer_unref (buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
gst_object_unref (dec);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
adpcmdec_sink_event (GstPad * pad, GstEvent * event)
|
adpcmdec_start (GstAudioDecoder * bdec)
|
||||||
{
|
{
|
||||||
ADPCMDec *dec = (ADPCMDec *) gst_pad_get_parent (pad);
|
ADPCMDec *dec = (ADPCMDec *) bdec;
|
||||||
gboolean res;
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
GST_DEBUG_OBJECT (dec, "start");
|
||||||
case GST_EVENT_FLUSH_STOP:
|
|
||||||
dec->out_samples = 0;
|
dec->blocksize = 0;
|
||||||
dec->timestamp = GST_CLOCK_TIME_NONE;
|
dec->rate = 0;
|
||||||
dec->base_timestamp = GST_CLOCK_TIME_NONE;
|
dec->channels = 0;
|
||||||
gst_adapter_clear (dec->adapter);
|
|
||||||
/* Fall through */
|
return TRUE;
|
||||||
default:
|
|
||||||
res = gst_pad_push_event (dec->srcpad, event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gst_object_unref (dec);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstStateChangeReturn
|
static gboolean
|
||||||
adpcmdec_change_state (GstElement * element, GstStateChange transition)
|
adpcmdec_stop (GstAudioDecoder * dec)
|
||||||
{
|
{
|
||||||
GstStateChangeReturn ret;
|
GST_DEBUG_OBJECT (dec, "stop");
|
||||||
ADPCMDec *dec = (ADPCMDec *) element;
|
|
||||||
|
|
||||||
switch (transition) {
|
return TRUE;
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
|
||||||
adpcmdec_teardown (dec);
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
adpcmdec_dispose (GObject * obj)
|
|
||||||
{
|
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
adpcmdec_init (ADPCMDec * dec, ADPCMDecClass * klass)
|
adpcmdec_init (ADPCMDec * dec, ADPCMDecClass * klass)
|
||||||
{
|
{
|
||||||
dec->sinkpad =
|
|
||||||
gst_pad_new_from_static_template (&adpcmdec_sink_template, "sink");
|
|
||||||
gst_pad_set_setcaps_function (dec->sinkpad,
|
|
||||||
GST_DEBUG_FUNCPTR (adpcmdec_sink_setcaps));
|
|
||||||
gst_pad_set_chain_function (dec->sinkpad, GST_DEBUG_FUNCPTR (adpcmdec_chain));
|
|
||||||
gst_pad_set_event_function (dec->sinkpad,
|
|
||||||
GST_DEBUG_FUNCPTR (adpcmdec_sink_event));
|
|
||||||
gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
|
|
||||||
dec->srcpad =
|
|
||||||
gst_pad_new_from_static_template (&adpcmdec_src_template, "src");
|
|
||||||
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
adpcmdec_class_init (ADPCMDecClass * klass)
|
adpcmdec_class_init (ADPCMDecClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobjectclass = (GObjectClass *) klass;
|
GstAudioDecoderClass *base_class = (GstAudioDecoderClass *) klass;
|
||||||
GstElementClass *gstelement_class = (GstElementClass *) klass;
|
|
||||||
gobjectclass->dispose = adpcmdec_dispose;
|
|
||||||
gstelement_class->change_state = adpcmdec_change_state;
|
|
||||||
} static void
|
|
||||||
|
|
||||||
|
base_class->start = GST_DEBUG_FUNCPTR (adpcmdec_start);
|
||||||
|
base_class->stop = GST_DEBUG_FUNCPTR (adpcmdec_stop);
|
||||||
|
base_class->set_format = GST_DEBUG_FUNCPTR (adpcmdec_set_format);
|
||||||
|
base_class->parse = GST_DEBUG_FUNCPTR (adpcmdec_parse);
|
||||||
|
base_class->handle_frame = GST_DEBUG_FUNCPTR (adpcmdec_handle_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
adpcmdec_base_init (gpointer klass)
|
adpcmdec_base_init (gpointer klass)
|
||||||
{
|
{
|
||||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||||
|
|
|
@ -5,8 +5,9 @@ libgstadpcmenc_la_SOURCES = adpcmenc.c
|
||||||
|
|
||||||
# flags used to compile this plugin
|
# flags used to compile this plugin
|
||||||
# add other _CFLAGS and _LIBS as needed
|
# add other _CFLAGS and _LIBS as needed
|
||||||
libgstadpcmenc_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS)
|
libgstadpcmenc_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
|
||||||
libgstadpcmenc_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS)
|
libgstadpcmenc_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-@GST_MAJORMINOR@ \
|
||||||
|
$(GST_LIBS)
|
||||||
libgstadpcmenc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
libgstadpcmenc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
libgstadpcmenc_la_LIBTOOLFLAGS = --tag=disable-static
|
libgstadpcmenc_la_LIBTOOLFLAGS = --tag=disable-static
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/audio/gstaudioencoder.h>
|
||||||
|
|
||||||
#define GST_TYPE_ADPCM_ENC \
|
#define GST_TYPE_ADPCM_ENC \
|
||||||
(adpcmenc_get_type ())
|
(adpcmenc_get_type ())
|
||||||
|
@ -113,17 +113,12 @@ adpcmenc_layout_get_type (void)
|
||||||
|
|
||||||
typedef struct _ADPCMEncClass
|
typedef struct _ADPCMEncClass
|
||||||
{
|
{
|
||||||
GstElementClass parent_class;
|
GstAudioEncoderClass parent_class;
|
||||||
} ADPCMEncClass;
|
} ADPCMEncClass;
|
||||||
|
|
||||||
typedef struct _ADPCMEnc
|
typedef struct _ADPCMEnc
|
||||||
{
|
{
|
||||||
GstElement parent;
|
GstAudioEncoder parent;
|
||||||
|
|
||||||
GstPad *sinkpad;
|
|
||||||
GstPad *srcpad;
|
|
||||||
|
|
||||||
GstCaps *output_caps;
|
|
||||||
|
|
||||||
enum adpcm_layout layout;
|
enum adpcm_layout layout;
|
||||||
int rate;
|
int rate;
|
||||||
|
@ -133,19 +128,11 @@ typedef struct _ADPCMEnc
|
||||||
|
|
||||||
guint8 step_index[2];
|
guint8 step_index[2];
|
||||||
|
|
||||||
gboolean is_setup;
|
|
||||||
|
|
||||||
GstClockTime timestamp;
|
|
||||||
GstClockTime base_timestamp;
|
|
||||||
|
|
||||||
guint64 out_samples;
|
|
||||||
|
|
||||||
GstAdapter *adapter;
|
|
||||||
|
|
||||||
} ADPCMEnc;
|
} ADPCMEnc;
|
||||||
|
|
||||||
GType adpcmenc_get_type (void);
|
GType adpcmenc_get_type (void);
|
||||||
GST_BOILERPLATE (ADPCMEnc, adpcmenc, GstElement, GST_TYPE_ELEMENT);
|
GST_BOILERPLATE (ADPCMEnc, adpcmenc, GstAudioEncoder, GST_TYPE_AUDIO_ENCODER);
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
adpcmenc_setup (ADPCMEnc * enc)
|
adpcmenc_setup (ADPCMEnc * enc)
|
||||||
{
|
{
|
||||||
|
@ -153,6 +140,7 @@ adpcmenc_setup (ADPCMEnc * enc)
|
||||||
const int ADPCM_SAMPLES_PER_BYTE = 2;
|
const int ADPCM_SAMPLES_PER_BYTE = 2;
|
||||||
guint64 sample_bytes;
|
guint64 sample_bytes;
|
||||||
const char *layout;
|
const char *layout;
|
||||||
|
GstCaps *caps;
|
||||||
|
|
||||||
switch (enc->layout) {
|
switch (enc->layout) {
|
||||||
case LAYOUT_ADPCM_DVI:
|
case LAYOUT_ADPCM_DVI:
|
||||||
|
@ -168,21 +156,14 @@ adpcmenc_setup (ADPCMEnc * enc)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
enc->output_caps = gst_caps_new_simple ("audio/x-adpcm",
|
caps = gst_caps_new_simple ("audio/x-adpcm",
|
||||||
"rate", G_TYPE_INT, enc->rate,
|
"rate", G_TYPE_INT, enc->rate,
|
||||||
"channels", G_TYPE_INT, enc->channels,
|
"channels", G_TYPE_INT, enc->channels,
|
||||||
"layout", G_TYPE_STRING, layout,
|
"layout", G_TYPE_STRING, layout,
|
||||||
"block_align", G_TYPE_INT, enc->blocksize, NULL);
|
"block_align", G_TYPE_INT, enc->blocksize, NULL);
|
||||||
|
|
||||||
if (enc->output_caps) {
|
gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps);
|
||||||
gst_pad_set_caps (enc->srcpad, enc->output_caps);
|
gst_caps_unref (caps);
|
||||||
}
|
|
||||||
|
|
||||||
enc->is_setup = TRUE;
|
|
||||||
enc->timestamp = GST_CLOCK_TIME_NONE;
|
|
||||||
enc->base_timestamp = GST_CLOCK_TIME_NONE;
|
|
||||||
enc->adapter = gst_adapter_new ();
|
|
||||||
enc->out_samples = 0;
|
|
||||||
|
|
||||||
/* Step index state is carried between blocks. */
|
/* Step index state is carried between blocks. */
|
||||||
enc->step_index[0] = 0;
|
enc->step_index[0] = 0;
|
||||||
|
@ -191,37 +172,21 @@ adpcmenc_setup (ADPCMEnc * enc)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
adpcmenc_teardown (ADPCMEnc * enc)
|
|
||||||
{
|
|
||||||
if (enc->output_caps) {
|
|
||||||
gst_caps_unref (enc->output_caps);
|
|
||||||
enc->output_caps = NULL;
|
|
||||||
}
|
|
||||||
if (enc->adapter) {
|
|
||||||
g_object_unref (enc->adapter);
|
|
||||||
enc->adapter = NULL;
|
|
||||||
}
|
|
||||||
enc->is_setup = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
adpcmenc_sink_setcaps (GstPad * pad, GstCaps * caps)
|
adpcmenc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
|
||||||
{
|
{
|
||||||
ADPCMEnc *enc = (ADPCMEnc *) gst_pad_get_parent (pad);
|
ADPCMEnc *enc = (ADPCMEnc *) (benc);
|
||||||
GstStructure *structure = gst_caps_get_structure (caps, 0);
|
|
||||||
|
|
||||||
if (!gst_structure_get_int (structure, "rate", &enc->rate))
|
enc->rate = GST_AUDIO_INFO_RATE (info);
|
||||||
return FALSE;
|
enc->channels = GST_AUDIO_INFO_CHANNELS (info);
|
||||||
if (!gst_structure_get_int (structure, "channels", &enc->channels))
|
|
||||||
|
if (!adpcmenc_setup (enc))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (enc->is_setup) {
|
/* report needs to base class */
|
||||||
adpcmenc_teardown (enc);
|
gst_audio_encoder_set_frame_samples_min (benc, enc->samples_per_block);
|
||||||
}
|
gst_audio_encoder_set_frame_samples_max (benc, enc->samples_per_block);
|
||||||
adpcmenc_setup (enc);
|
gst_audio_encoder_set_frame_max (benc, 1);
|
||||||
|
|
||||||
gst_object_unref (enc);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -368,148 +333,86 @@ adpcmenc_encode_ima_block (ADPCMEnc * enc, const gint16 * samples,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstBuffer *
|
||||||
adpcmenc_encode_block (ADPCMEnc * enc, const gint16 * samples, int blocksize)
|
adpcmenc_encode_block (ADPCMEnc * enc, const gint16 * samples, int blocksize)
|
||||||
{
|
{
|
||||||
gboolean res;
|
gboolean res = FALSE;
|
||||||
GstBuffer *outbuf = NULL;
|
GstBuffer *outbuf = NULL;
|
||||||
|
|
||||||
if (enc->layout == LAYOUT_ADPCM_DVI) {
|
if (enc->layout == LAYOUT_ADPCM_DVI) {
|
||||||
outbuf = gst_buffer_new_and_alloc (enc->blocksize);
|
outbuf = gst_buffer_new_and_alloc (enc->blocksize);
|
||||||
res = adpcmenc_encode_ima_block (enc, samples, GST_BUFFER_DATA (outbuf));
|
res = adpcmenc_encode_ima_block (enc, samples, GST_BUFFER_DATA (outbuf));
|
||||||
} else {
|
} else {
|
||||||
|
/* should not happen afaics */
|
||||||
|
g_assert_not_reached ();
|
||||||
GST_WARNING_OBJECT (enc, "Unknown layout");
|
GST_WARNING_OBJECT (enc, "Unknown layout");
|
||||||
return GST_FLOW_ERROR;
|
res = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
gst_buffer_unref (outbuf);
|
if (outbuf)
|
||||||
|
gst_buffer_unref (outbuf);
|
||||||
|
outbuf = NULL;
|
||||||
GST_WARNING_OBJECT (enc, "Encode of block failed");
|
GST_WARNING_OBJECT (enc, "Encode of block failed");
|
||||||
return GST_FLOW_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_buffer_set_caps (outbuf, enc->output_caps);
|
return outbuf;
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = enc->timestamp;
|
|
||||||
|
|
||||||
enc->out_samples += enc->samples_per_block;
|
|
||||||
enc->timestamp = enc->base_timestamp +
|
|
||||||
gst_util_uint64_scale_int (enc->out_samples, GST_SECOND, enc->rate);
|
|
||||||
GST_BUFFER_DURATION (outbuf) = enc->timestamp - GST_BUFFER_TIMESTAMP (outbuf);
|
|
||||||
|
|
||||||
return gst_pad_push (enc->srcpad, outbuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
adpcmenc_chain (GstPad * pad, GstBuffer * buf)
|
adpcmenc_handle_frame (GstAudioEncoder * benc, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
ADPCMEnc *enc = (ADPCMEnc *) gst_pad_get_parent (pad);
|
ADPCMEnc *enc = (ADPCMEnc *) (benc);
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
gint16 *samples;
|
gint16 *samples;
|
||||||
GstBuffer *databuf = NULL;
|
GstBuffer *outbuf;
|
||||||
int input_bytes_per_block;
|
int input_bytes_per_block;
|
||||||
const int BYTES_PER_SAMPLE = 2;
|
const int BYTES_PER_SAMPLE = 2;
|
||||||
|
|
||||||
if (enc->base_timestamp == GST_CLOCK_TIME_NONE) {
|
/* we don't deal with squeezing remnants, so simply discard those */
|
||||||
enc->base_timestamp = GST_BUFFER_TIMESTAMP (buf);
|
if (G_UNLIKELY (buffer == NULL)) {
|
||||||
if (enc->base_timestamp == GST_CLOCK_TIME_NONE)
|
GST_DEBUG_OBJECT (benc, "no data");
|
||||||
enc->base_timestamp = 0;
|
goto done;
|
||||||
enc->timestamp = enc->base_timestamp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_adapter_push (enc->adapter, buf);
|
|
||||||
|
|
||||||
input_bytes_per_block =
|
input_bytes_per_block =
|
||||||
enc->samples_per_block * BYTES_PER_SAMPLE * enc->channels;
|
enc->samples_per_block * BYTES_PER_SAMPLE * enc->channels;
|
||||||
|
|
||||||
while (gst_adapter_available (enc->adapter) >= input_bytes_per_block) {
|
if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < input_bytes_per_block)) {
|
||||||
databuf = gst_adapter_take_buffer (enc->adapter, input_bytes_per_block);
|
GST_DEBUG_OBJECT (enc, "discarding trailing data %d",
|
||||||
samples = (gint16 *) GST_BUFFER_DATA (databuf);
|
GST_BUFFER_SIZE (buffer));
|
||||||
ret = adpcmenc_encode_block (enc, samples, enc->blocksize);
|
ret = gst_audio_encoder_finish_frame (benc, NULL, -1);
|
||||||
gst_buffer_unref (databuf);
|
goto done;
|
||||||
if (ret != GST_FLOW_OK)
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
samples = (gint16 *) GST_BUFFER_DATA (buffer);
|
||||||
|
outbuf = adpcmenc_encode_block (enc, samples, enc->blocksize);
|
||||||
|
|
||||||
|
ret = gst_audio_encoder_finish_frame (benc, outbuf, enc->samples_per_block);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
gst_object_unref (enc);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
adpcmenc_sink_event (GstPad * pad, GstEvent * event)
|
adpcmenc_start (GstAudioEncoder * enc)
|
||||||
{
|
{
|
||||||
ADPCMEnc *enc = (ADPCMEnc *) gst_pad_get_parent (pad);
|
GST_DEBUG_OBJECT (enc, "start");
|
||||||
gboolean res;
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
return TRUE;
|
||||||
case GST_EVENT_FLUSH_STOP:
|
|
||||||
enc->out_samples = 0;
|
|
||||||
enc->timestamp = GST_CLOCK_TIME_NONE;
|
|
||||||
enc->base_timestamp = GST_CLOCK_TIME_NONE;
|
|
||||||
gst_adapter_clear (enc->adapter);
|
|
||||||
/* Fall through */
|
|
||||||
default:
|
|
||||||
res = gst_pad_push_event (enc->srcpad, event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gst_object_unref (enc);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstStateChangeReturn
|
static gboolean
|
||||||
adpcmenc_change_state (GstElement * element, GstStateChange transition)
|
adpcmenc_stop (GstAudioEncoder * enc)
|
||||||
{
|
{
|
||||||
GstStateChangeReturn ret;
|
GST_DEBUG_OBJECT (enc, "stop");
|
||||||
ADPCMEnc *enc = (ADPCMEnc *) element;
|
|
||||||
|
|
||||||
switch (transition) {
|
return TRUE;
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
|
||||||
adpcmenc_teardown (enc);
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
adpcmenc_dispose (GObject * obj)
|
|
||||||
{
|
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
adpcmenc_init (ADPCMEnc * enc, ADPCMEncClass * klass)
|
adpcmenc_init (ADPCMEnc * enc, ADPCMEncClass * klass)
|
||||||
{
|
{
|
||||||
enc->sinkpad =
|
|
||||||
gst_pad_new_from_static_template (&adpcmenc_sink_template, "sink");
|
|
||||||
gst_pad_set_setcaps_function (enc->sinkpad,
|
|
||||||
GST_DEBUG_FUNCPTR (adpcmenc_sink_setcaps));
|
|
||||||
gst_pad_set_chain_function (enc->sinkpad, GST_DEBUG_FUNCPTR (adpcmenc_chain));
|
|
||||||
gst_pad_set_event_function (enc->sinkpad,
|
|
||||||
GST_DEBUG_FUNCPTR (adpcmenc_sink_event));
|
|
||||||
gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
|
|
||||||
|
|
||||||
enc->srcpad =
|
|
||||||
gst_pad_new_from_static_template (&adpcmenc_src_template, "src");
|
|
||||||
gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
|
|
||||||
|
|
||||||
/* Set defaults. */
|
/* Set defaults. */
|
||||||
enc->blocksize = DEFAULT_ADPCM_BLOCK_SIZE;
|
enc->blocksize = DEFAULT_ADPCM_BLOCK_SIZE;
|
||||||
enc->layout = DEFAULT_ADPCM_LAYOUT;
|
enc->layout = DEFAULT_ADPCM_LAYOUT;
|
||||||
|
@ -519,11 +422,16 @@ static void
|
||||||
adpcmenc_class_init (ADPCMEncClass * klass)
|
adpcmenc_class_init (ADPCMEncClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobjectclass = (GObjectClass *) klass;
|
GObjectClass *gobjectclass = (GObjectClass *) klass;
|
||||||
GstElementClass *gstelement_class = (GstElementClass *) klass;
|
GstAudioEncoderClass *base_class = (GstAudioEncoderClass *) klass;
|
||||||
|
|
||||||
gobjectclass->set_property = adpcmenc_set_property;
|
gobjectclass->set_property = adpcmenc_set_property;
|
||||||
gobjectclass->get_property = adpcmenc_get_property;
|
gobjectclass->get_property = adpcmenc_get_property;
|
||||||
|
|
||||||
|
base_class->start = GST_DEBUG_FUNCPTR (adpcmenc_start);
|
||||||
|
base_class->stop = GST_DEBUG_FUNCPTR (adpcmenc_stop);
|
||||||
|
base_class->set_format = GST_DEBUG_FUNCPTR (adpcmenc_set_format);
|
||||||
|
base_class->handle_frame = GST_DEBUG_FUNCPTR (adpcmenc_handle_frame);
|
||||||
|
|
||||||
g_object_class_install_property (gobjectclass, ARG_LAYOUT,
|
g_object_class_install_property (gobjectclass, ARG_LAYOUT,
|
||||||
g_param_spec_enum ("layout", "Layout",
|
g_param_spec_enum ("layout", "Layout",
|
||||||
"Layout for output stream",
|
"Layout for output stream",
|
||||||
|
@ -537,10 +445,9 @@ adpcmenc_class_init (ADPCMEncClass * klass)
|
||||||
DEFAULT_ADPCM_BLOCK_SIZE,
|
DEFAULT_ADPCM_BLOCK_SIZE,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
gobjectclass->dispose = adpcmenc_dispose;
|
}
|
||||||
gstelement_class->change_state = adpcmenc_change_state;
|
|
||||||
} static void
|
|
||||||
|
|
||||||
|
static void
|
||||||
adpcmenc_base_init (gpointer klass)
|
adpcmenc_base_init (gpointer klass)
|
||||||
{
|
{
|
||||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||||
|
|
|
@ -227,6 +227,8 @@ gst_debug_spy_transform_ip (GstBaseTransform * transform, GstBuffer * buf)
|
||||||
"size", G_TYPE_UINT, GST_BUFFER_SIZE (buf),
|
"size", G_TYPE_UINT, GST_BUFFER_SIZE (buf),
|
||||||
"caps", GST_TYPE_CAPS, GST_BUFFER_CAPS (buf), NULL);
|
"caps", GST_TYPE_CAPS, GST_BUFFER_CAPS (buf), NULL);
|
||||||
|
|
||||||
|
g_free (checksum);
|
||||||
|
|
||||||
message =
|
message =
|
||||||
gst_message_new_element (GST_OBJECT (transform), message_structure);
|
gst_message_new_element (GST_OBJECT (transform), message_structure);
|
||||||
|
|
||||||
|
|
|
@ -297,22 +297,29 @@ gst_festival_chain (GstPad * pad, GstBuffer * buf)
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
GstFestival *festival;
|
GstFestival *festival;
|
||||||
guint8 *p, *ep;
|
guint8 *p, *ep;
|
||||||
|
gint f;
|
||||||
FILE *fd;
|
FILE *fd;
|
||||||
|
|
||||||
festival = GST_FESTIVAL (GST_PAD_PARENT (pad));
|
festival = GST_FESTIVAL (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
GST_LOG_OBJECT (festival, "Got text buffer, %u bytes", GST_BUFFER_SIZE (buf));
|
GST_LOG_OBJECT (festival, "Got text buffer, %u bytes", GST_BUFFER_SIZE (buf));
|
||||||
|
|
||||||
fd = fdopen (dup (festival->info->server_fd), "wb");
|
f = dup (festival->info->server_fd);
|
||||||
|
if (f < 0)
|
||||||
|
goto fail_open;
|
||||||
|
fd = fdopen (f, "wb");
|
||||||
|
if (fd == NULL) {
|
||||||
|
close (f);
|
||||||
|
goto fail_open;
|
||||||
|
}
|
||||||
|
|
||||||
/* Copy text over to server, escaping any quotes */
|
/* Copy text over to server, escaping any quotes */
|
||||||
fprintf (fd, "(Parameter.set 'Audio_Required_Rate 16000)\n");
|
fprintf (fd, "(Parameter.set 'Audio_Required_Rate 16000)\n");
|
||||||
fflush (fd);
|
fflush (fd);
|
||||||
GST_DEBUG_OBJECT (festival, "issued Parameter.set command");
|
GST_DEBUG_OBJECT (festival, "issued Parameter.set command");
|
||||||
if (read_response (festival) == FALSE) {
|
if (read_response (festival) == FALSE) {
|
||||||
ret = GST_FLOW_ERROR;
|
|
||||||
fclose (fd);
|
fclose (fd);
|
||||||
goto out;
|
goto fail_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf (fd, "(tts_textall \"");
|
fprintf (fd, "(tts_textall \"");
|
||||||
|
@ -332,11 +339,25 @@ gst_festival_chain (GstPad * pad, GstBuffer * buf)
|
||||||
|
|
||||||
/* Read back info from server */
|
/* Read back info from server */
|
||||||
if (read_response (festival) == FALSE)
|
if (read_response (festival) == FALSE)
|
||||||
ret = GST_FLOW_ERROR;
|
goto fail_read;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
fail_open:
|
||||||
|
{
|
||||||
|
GST_ELEMENT_ERROR (festival, RESOURCE, OPEN_WRITE, (NULL), (NULL));
|
||||||
|
ret = GST_FLOW_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
fail_read:
|
||||||
|
{
|
||||||
|
GST_ELEMENT_ERROR (festival, RESOURCE, READ, (NULL), (NULL));
|
||||||
|
ret = GST_FLOW_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static FT_Info *
|
static FT_Info *
|
||||||
|
|
|
@ -5,6 +5,8 @@ noinst_PROGRAMS = gstintertest
|
||||||
libgstinter_la_SOURCES = \
|
libgstinter_la_SOURCES = \
|
||||||
gstinteraudiosink.c \
|
gstinteraudiosink.c \
|
||||||
gstinteraudiosrc.c \
|
gstinteraudiosrc.c \
|
||||||
|
gstintersubsink.c \
|
||||||
|
gstintersubsrc.c \
|
||||||
gstintervideosink.c \
|
gstintervideosink.c \
|
||||||
gstintervideosrc.c \
|
gstintervideosrc.c \
|
||||||
gstinter.c \
|
gstinter.c \
|
||||||
|
@ -13,6 +15,8 @@ libgstinter_la_SOURCES = \
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
gstinteraudiosink.h \
|
gstinteraudiosink.h \
|
||||||
gstinteraudiosrc.h \
|
gstinteraudiosrc.h \
|
||||||
|
gstintersubsink.h \
|
||||||
|
gstintersubsrc.h \
|
||||||
gstintervideosink.h \
|
gstintervideosink.h \
|
||||||
gstintervideosrc.h \
|
gstintervideosrc.h \
|
||||||
gstintersurface.h
|
gstintersurface.h
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) 2011 David A. Schleef <ds@schleef.org>
|
* Copyright (C) 2011 David Schleef <ds@entropywave.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
#include "gstinteraudiosrc.h"
|
#include "gstinteraudiosrc.h"
|
||||||
#include "gstinteraudiosink.h"
|
#include "gstinteraudiosink.h"
|
||||||
|
#include "gstintersubsrc.h"
|
||||||
|
#include "gstintersubsink.h"
|
||||||
#include "gstintervideosrc.h"
|
#include "gstintervideosrc.h"
|
||||||
#include "gstintervideosink.h"
|
#include "gstintervideosink.h"
|
||||||
#include "gstintersurface.h"
|
#include "gstintersurface.h"
|
||||||
|
@ -34,13 +36,15 @@ plugin_init (GstPlugin * plugin)
|
||||||
GST_TYPE_INTER_AUDIO_SRC);
|
GST_TYPE_INTER_AUDIO_SRC);
|
||||||
gst_element_register (plugin, "interaudiosink", GST_RANK_NONE,
|
gst_element_register (plugin, "interaudiosink", GST_RANK_NONE,
|
||||||
GST_TYPE_INTER_AUDIO_SINK);
|
GST_TYPE_INTER_AUDIO_SINK);
|
||||||
|
gst_element_register (plugin, "intersubsrc", GST_RANK_NONE,
|
||||||
|
GST_TYPE_INTER_SUB_SRC);
|
||||||
|
gst_element_register (plugin, "intersubsink", GST_RANK_NONE,
|
||||||
|
GST_TYPE_INTER_SUB_SINK);
|
||||||
gst_element_register (plugin, "intervideosrc", GST_RANK_NONE,
|
gst_element_register (plugin, "intervideosrc", GST_RANK_NONE,
|
||||||
GST_TYPE_INTER_VIDEO_SRC);
|
GST_TYPE_INTER_VIDEO_SRC);
|
||||||
gst_element_register (plugin, "intervideosink", GST_RANK_NONE,
|
gst_element_register (plugin, "intervideosink", GST_RANK_NONE,
|
||||||
GST_TYPE_INTER_VIDEO_SINK);
|
GST_TYPE_INTER_VIDEO_SINK);
|
||||||
|
|
||||||
gst_inter_surface_init ();
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,8 @@ static gboolean gst_inter_audio_sink_unlock_stop (GstBaseSink * sink);
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0
|
PROP_0,
|
||||||
|
PROP_CHANNEL
|
||||||
};
|
};
|
||||||
|
|
||||||
/* pad templates */
|
/* pad templates */
|
||||||
|
@ -150,6 +151,10 @@ gst_inter_audio_sink_class_init (GstInterAudioSinkClass * klass)
|
||||||
base_sink_class->unlock_stop =
|
base_sink_class->unlock_stop =
|
||||||
GST_DEBUG_FUNCPTR (gst_inter_audio_sink_unlock_stop);
|
GST_DEBUG_FUNCPTR (gst_inter_audio_sink_unlock_stop);
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_CHANNEL,
|
||||||
|
g_param_spec_string ("channel", "Channel",
|
||||||
|
"Channel name to match inter src and sink elements",
|
||||||
|
"default", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -79,7 +79,8 @@ gst_inter_audio_src_prepare_seek_segment (GstBaseSrc * src, GstEvent * seek,
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0
|
PROP_0,
|
||||||
|
PROP_CHANNEL
|
||||||
};
|
};
|
||||||
|
|
||||||
/* pad templates */
|
/* pad templates */
|
||||||
|
@ -158,6 +159,10 @@ gst_inter_audio_src_class_init (GstInterAudioSrcClass * klass)
|
||||||
base_src_class->prepare_seek_segment =
|
base_src_class->prepare_seek_segment =
|
||||||
GST_DEBUG_FUNCPTR (gst_inter_audio_src_prepare_seek_segment);
|
GST_DEBUG_FUNCPTR (gst_inter_audio_src_prepare_seek_segment);
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_CHANNEL,
|
||||||
|
g_param_spec_string ("channel", "Channel",
|
||||||
|
"Channel name to match inter src and sink elements",
|
||||||
|
"default", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
325
gst/inter/gstintersubsink.c
Normal file
325
gst/inter/gstintersubsink.c
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2011 David Schleef <ds@entropywave.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Suite 500,
|
||||||
|
* Boston, MA 02110-1335, USA.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* SECTION:element-gstintersubsink
|
||||||
|
*
|
||||||
|
* The intersubsink element does FIXME stuff.
|
||||||
|
*
|
||||||
|
* <refsect2>
|
||||||
|
* <title>Example launch line</title>
|
||||||
|
* |[
|
||||||
|
* gst-launch -v fakesrc ! intersubsink ! FIXME ! fakesink
|
||||||
|
* ]|
|
||||||
|
* FIXME Describe what the pipeline does.
|
||||||
|
* </refsect2>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
#include <gst/base/gstbasesink.h>
|
||||||
|
#include "gstintersubsink.h"
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_STATIC (gst_inter_sub_sink_debug_category);
|
||||||
|
#define GST_CAT_DEFAULT gst_inter_sub_sink_debug_category
|
||||||
|
|
||||||
|
/* prototypes */
|
||||||
|
|
||||||
|
|
||||||
|
static void gst_inter_sub_sink_set_property (GObject * object,
|
||||||
|
guint property_id, const GValue * value, GParamSpec * pspec);
|
||||||
|
static void gst_inter_sub_sink_get_property (GObject * object,
|
||||||
|
guint property_id, GValue * value, GParamSpec * pspec);
|
||||||
|
static void gst_inter_sub_sink_dispose (GObject * object);
|
||||||
|
static void gst_inter_sub_sink_finalize (GObject * object);
|
||||||
|
|
||||||
|
static GstCaps *gst_inter_sub_sink_get_caps (GstBaseSink * sink);
|
||||||
|
static gboolean gst_inter_sub_sink_set_caps (GstBaseSink * sink,
|
||||||
|
GstCaps * caps);
|
||||||
|
static GstFlowReturn gst_inter_sub_sink_buffer_alloc (GstBaseSink * sink,
|
||||||
|
guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
|
||||||
|
static void gst_inter_sub_sink_get_times (GstBaseSink * sink,
|
||||||
|
GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
|
||||||
|
static gboolean gst_inter_sub_sink_start (GstBaseSink * sink);
|
||||||
|
static gboolean gst_inter_sub_sink_stop (GstBaseSink * sink);
|
||||||
|
static gboolean gst_inter_sub_sink_unlock (GstBaseSink * sink);
|
||||||
|
static gboolean gst_inter_sub_sink_event (GstBaseSink * sink, GstEvent * event);
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_inter_sub_sink_preroll (GstBaseSink * sink, GstBuffer * buffer);
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_inter_sub_sink_render (GstBaseSink * sink, GstBuffer * buffer);
|
||||||
|
static GstStateChangeReturn gst_inter_sub_sink_async_play (GstBaseSink * sink);
|
||||||
|
static gboolean gst_inter_sub_sink_activate_pull (GstBaseSink * sink,
|
||||||
|
gboolean active);
|
||||||
|
static gboolean gst_inter_sub_sink_unlock_stop (GstBaseSink * sink);
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_0
|
||||||
|
};
|
||||||
|
|
||||||
|
/* pad templates */
|
||||||
|
|
||||||
|
static GstStaticPadTemplate gst_inter_sub_sink_sink_template =
|
||||||
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
|
GST_PAD_SINK,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
GST_STATIC_CAPS ("text/plain")
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/* class initialization */
|
||||||
|
|
||||||
|
#define DEBUG_INIT(bla) \
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_inter_sub_sink_debug_category, "intersubsink", 0, \
|
||||||
|
"debug category for intersubsink element");
|
||||||
|
|
||||||
|
GST_BOILERPLATE_FULL (GstInterSubSink, gst_inter_sub_sink, GstBaseSink,
|
||||||
|
GST_TYPE_BASE_SINK, DEBUG_INIT);
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_inter_sub_sink_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_inter_sub_sink_sink_template));
|
||||||
|
|
||||||
|
gst_element_class_set_details_simple (element_class, "FIXME Long name",
|
||||||
|
"Generic", "FIXME Description", "FIXME <fixme@example.com>");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_inter_sub_sink_class_init (GstInterSubSinkClass * klass)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||||
|
GstBaseSinkClass *base_sink_class = GST_BASE_SINK_CLASS (klass);
|
||||||
|
|
||||||
|
gobject_class->set_property = gst_inter_sub_sink_set_property;
|
||||||
|
gobject_class->get_property = gst_inter_sub_sink_get_property;
|
||||||
|
gobject_class->dispose = gst_inter_sub_sink_dispose;
|
||||||
|
gobject_class->finalize = gst_inter_sub_sink_finalize;
|
||||||
|
base_sink_class->get_caps = GST_DEBUG_FUNCPTR (gst_inter_sub_sink_get_caps);
|
||||||
|
base_sink_class->set_caps = GST_DEBUG_FUNCPTR (gst_inter_sub_sink_set_caps);
|
||||||
|
if (0)
|
||||||
|
base_sink_class->buffer_alloc =
|
||||||
|
GST_DEBUG_FUNCPTR (gst_inter_sub_sink_buffer_alloc);
|
||||||
|
base_sink_class->get_times = GST_DEBUG_FUNCPTR (gst_inter_sub_sink_get_times);
|
||||||
|
base_sink_class->start = GST_DEBUG_FUNCPTR (gst_inter_sub_sink_start);
|
||||||
|
base_sink_class->stop = GST_DEBUG_FUNCPTR (gst_inter_sub_sink_stop);
|
||||||
|
base_sink_class->unlock = GST_DEBUG_FUNCPTR (gst_inter_sub_sink_unlock);
|
||||||
|
if (0)
|
||||||
|
base_sink_class->event = GST_DEBUG_FUNCPTR (gst_inter_sub_sink_event);
|
||||||
|
base_sink_class->preroll = GST_DEBUG_FUNCPTR (gst_inter_sub_sink_preroll);
|
||||||
|
base_sink_class->render = GST_DEBUG_FUNCPTR (gst_inter_sub_sink_render);
|
||||||
|
if (0)
|
||||||
|
base_sink_class->async_play =
|
||||||
|
GST_DEBUG_FUNCPTR (gst_inter_sub_sink_async_play);
|
||||||
|
if (0)
|
||||||
|
base_sink_class->activate_pull =
|
||||||
|
GST_DEBUG_FUNCPTR (gst_inter_sub_sink_activate_pull);
|
||||||
|
base_sink_class->unlock_stop =
|
||||||
|
GST_DEBUG_FUNCPTR (gst_inter_sub_sink_unlock_stop);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_inter_sub_sink_init (GstInterSubSink * intersubsink,
|
||||||
|
GstInterSubSinkClass * intersubsink_class)
|
||||||
|
{
|
||||||
|
|
||||||
|
intersubsink->surface = gst_inter_surface_get ("default");
|
||||||
|
|
||||||
|
intersubsink->fps_n = 1;
|
||||||
|
intersubsink->fps_d = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_inter_sub_sink_set_property (GObject * object, guint property_id,
|
||||||
|
const GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
/* GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (object); */
|
||||||
|
|
||||||
|
switch (property_id) {
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_inter_sub_sink_get_property (GObject * object, guint property_id,
|
||||||
|
GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
/* GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (object); */
|
||||||
|
|
||||||
|
switch (property_id) {
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_inter_sub_sink_dispose (GObject * object)
|
||||||
|
{
|
||||||
|
/* GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (object); */
|
||||||
|
|
||||||
|
/* clean up as possible. may be called multiple times */
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_inter_sub_sink_finalize (GObject * object)
|
||||||
|
{
|
||||||
|
/* GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (object); */
|
||||||
|
|
||||||
|
/* clean up object here */
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static GstCaps *
|
||||||
|
gst_inter_sub_sink_get_caps (GstBaseSink * sink)
|
||||||
|
{
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
|
||||||
|
{
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_inter_sub_sink_buffer_alloc (GstBaseSink * sink, guint64 offset, guint size,
|
||||||
|
GstCaps * caps, GstBuffer ** buf)
|
||||||
|
{
|
||||||
|
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_inter_sub_sink_get_times (GstBaseSink * sink, GstBuffer * buffer,
|
||||||
|
GstClockTime * start, GstClockTime * end)
|
||||||
|
{
|
||||||
|
GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (sink);
|
||||||
|
|
||||||
|
if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
|
||||||
|
*start = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
|
if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
|
||||||
|
*end = *start + GST_BUFFER_DURATION (buffer);
|
||||||
|
} else {
|
||||||
|
if (intersubsink->fps_n > 0) {
|
||||||
|
*end = *start +
|
||||||
|
gst_util_uint64_scale_int (GST_SECOND, intersubsink->fps_d,
|
||||||
|
intersubsink->fps_n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_sink_start (GstBaseSink * sink)
|
||||||
|
{
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_sink_stop (GstBaseSink * sink)
|
||||||
|
{
|
||||||
|
GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (sink);
|
||||||
|
|
||||||
|
g_mutex_lock (intersubsink->surface->mutex);
|
||||||
|
if (intersubsink->surface->sub_buffer) {
|
||||||
|
gst_buffer_unref (intersubsink->surface->sub_buffer);
|
||||||
|
}
|
||||||
|
intersubsink->surface->sub_buffer = NULL;
|
||||||
|
g_mutex_unlock (intersubsink->surface->mutex);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_sink_unlock (GstBaseSink * sink)
|
||||||
|
{
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_sink_event (GstBaseSink * sink, GstEvent * event)
|
||||||
|
{
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_inter_sub_sink_preroll (GstBaseSink * sink, GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_inter_sub_sink_render (GstBaseSink * sink, GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (sink);
|
||||||
|
|
||||||
|
g_mutex_lock (intersubsink->surface->mutex);
|
||||||
|
if (intersubsink->surface->sub_buffer) {
|
||||||
|
gst_buffer_unref (intersubsink->surface->sub_buffer);
|
||||||
|
}
|
||||||
|
intersubsink->surface->sub_buffer = gst_buffer_ref (buffer);
|
||||||
|
//intersubsink->surface->sub_buffer_count = 0;
|
||||||
|
g_mutex_unlock (intersubsink->surface->mutex);
|
||||||
|
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstStateChangeReturn
|
||||||
|
gst_inter_sub_sink_async_play (GstBaseSink * sink)
|
||||||
|
{
|
||||||
|
|
||||||
|
return GST_STATE_CHANGE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_sink_activate_pull (GstBaseSink * sink, gboolean active)
|
||||||
|
{
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_sink_unlock_stop (GstBaseSink * sink)
|
||||||
|
{
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
57
gst/inter/gstintersubsink.h
Normal file
57
gst/inter/gstintersubsink.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2011 David Schleef <ds@entropywave.com>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GST_INTER_SUB_SINK_H_
|
||||||
|
#define _GST_INTER_SUB_SINK_H_
|
||||||
|
|
||||||
|
#include <gst/base/gstbasesink.h>
|
||||||
|
#include "gstintersurface.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define GST_TYPE_INTER_SUB_SINK (gst_inter_sub_sink_get_type())
|
||||||
|
#define GST_INTER_SUB_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_INTER_SUB_SINK,GstInterSubSink))
|
||||||
|
#define GST_INTER_SUB_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_INTER_SUB_SINK,GstInterSubSinkClass))
|
||||||
|
#define GST_IS_INTER_SUB_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_INTER_SUB_SINK))
|
||||||
|
#define GST_IS_INTER_SUB_SINK_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_INTER_SUB_SINK))
|
||||||
|
|
||||||
|
typedef struct _GstInterSubSink GstInterSubSink;
|
||||||
|
typedef struct _GstInterSubSinkClass GstInterSubSinkClass;
|
||||||
|
|
||||||
|
struct _GstInterSubSink
|
||||||
|
{
|
||||||
|
GstBaseSink base_intersubsink;
|
||||||
|
|
||||||
|
GstPad *sinkpad;
|
||||||
|
GstInterSurface *surface;
|
||||||
|
|
||||||
|
int fps_n;
|
||||||
|
int fps_d;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstInterSubSinkClass
|
||||||
|
{
|
||||||
|
GstBaseSinkClass base_intersubsink_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType gst_inter_sub_sink_get_type (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
455
gst/inter/gstintersubsrc.c
Normal file
455
gst/inter/gstintersubsrc.c
Normal file
|
@ -0,0 +1,455 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2011 David Schleef <ds@entropywave.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Suite 500,
|
||||||
|
* Boston, MA 02110-1335, USA.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* SECTION:element-gstintersubsrc
|
||||||
|
*
|
||||||
|
* The intersubsrc element is a subtitle source element. It is used
|
||||||
|
* in connection with a intersubsink element in a different pipeline,
|
||||||
|
* similar to interaudiosink and interaudiosrc.
|
||||||
|
*
|
||||||
|
* <refsect2>
|
||||||
|
* <title>Example launch line</title>
|
||||||
|
* |[
|
||||||
|
* gst-launch -v intersubsrc ! kateenc ! oggmux ! filesink location=out.ogv
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
|
* The intersubsrc element cannot be used effectively with gst-launch,
|
||||||
|
* as it requires a second pipeline in the application to send subtitles.
|
||||||
|
* </refsect2>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
#include <gst/base/gstbasesrc.h>
|
||||||
|
#include "gstintersubsrc.h"
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_STATIC (gst_inter_sub_src_debug_category);
|
||||||
|
#define GST_CAT_DEFAULT gst_inter_sub_src_debug_category
|
||||||
|
|
||||||
|
/* prototypes */
|
||||||
|
|
||||||
|
|
||||||
|
static void gst_inter_sub_src_set_property (GObject * object,
|
||||||
|
guint property_id, const GValue * value, GParamSpec * pspec);
|
||||||
|
static void gst_inter_sub_src_get_property (GObject * object,
|
||||||
|
guint property_id, GValue * value, GParamSpec * pspec);
|
||||||
|
static void gst_inter_sub_src_dispose (GObject * object);
|
||||||
|
static void gst_inter_sub_src_finalize (GObject * object);
|
||||||
|
|
||||||
|
static GstCaps *gst_inter_sub_src_get_caps (GstBaseSrc * src);
|
||||||
|
static gboolean gst_inter_sub_src_set_caps (GstBaseSrc * src, GstCaps * caps);
|
||||||
|
static gboolean gst_inter_sub_src_negotiate (GstBaseSrc * src);
|
||||||
|
static gboolean gst_inter_sub_src_newsegment (GstBaseSrc * src);
|
||||||
|
static gboolean gst_inter_sub_src_start (GstBaseSrc * src);
|
||||||
|
static gboolean gst_inter_sub_src_stop (GstBaseSrc * src);
|
||||||
|
static void
|
||||||
|
gst_inter_sub_src_get_times (GstBaseSrc * src, GstBuffer * buffer,
|
||||||
|
GstClockTime * start, GstClockTime * end);
|
||||||
|
static gboolean gst_inter_sub_src_is_seekable (GstBaseSrc * src);
|
||||||
|
static gboolean gst_inter_sub_src_unlock (GstBaseSrc * src);
|
||||||
|
static gboolean gst_inter_sub_src_event (GstBaseSrc * src, GstEvent * event);
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_inter_sub_src_create (GstBaseSrc * src, guint64 offset, guint size,
|
||||||
|
GstBuffer ** buf);
|
||||||
|
static gboolean gst_inter_sub_src_do_seek (GstBaseSrc * src,
|
||||||
|
GstSegment * segment);
|
||||||
|
static gboolean gst_inter_sub_src_query (GstBaseSrc * src, GstQuery * query);
|
||||||
|
static gboolean gst_inter_sub_src_check_get_range (GstBaseSrc * src);
|
||||||
|
static void gst_inter_sub_src_fixate (GstBaseSrc * src, GstCaps * caps);
|
||||||
|
static gboolean gst_inter_sub_src_unlock_stop (GstBaseSrc * src);
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_src_prepare_seek_segment (GstBaseSrc * src, GstEvent * seek,
|
||||||
|
GstSegment * segment);
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_0
|
||||||
|
};
|
||||||
|
|
||||||
|
/* pad templates */
|
||||||
|
|
||||||
|
static GstStaticPadTemplate gst_inter_sub_src_src_template =
|
||||||
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
|
GST_PAD_SRC,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
GST_STATIC_CAPS ("application/unknown")
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/* class initialization */
|
||||||
|
|
||||||
|
#define DEBUG_INIT(bla) \
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_inter_sub_src_debug_category, "intersubsrc", 0, \
|
||||||
|
"debug category for intersubsrc element");
|
||||||
|
|
||||||
|
GST_BOILERPLATE_FULL (GstInterSubSrc, gst_inter_sub_src, GstBaseSrc,
|
||||||
|
GST_TYPE_BASE_SRC, DEBUG_INIT);
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_inter_sub_src_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_inter_sub_src_src_template));
|
||||||
|
|
||||||
|
gst_element_class_set_details_simple (element_class,
|
||||||
|
"Inter-pipeline subtitle source",
|
||||||
|
"Source/Subtitle", "Inter-pipeline subtitle source",
|
||||||
|
"David Schleef <ds@entropywave.com>");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_inter_sub_src_class_init (GstInterSubSrcClass * klass)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||||
|
GstBaseSrcClass *base_src_class = GST_BASE_SRC_CLASS (klass);
|
||||||
|
|
||||||
|
gobject_class->set_property = gst_inter_sub_src_set_property;
|
||||||
|
gobject_class->get_property = gst_inter_sub_src_get_property;
|
||||||
|
gobject_class->dispose = gst_inter_sub_src_dispose;
|
||||||
|
gobject_class->finalize = gst_inter_sub_src_finalize;
|
||||||
|
if (0)
|
||||||
|
base_src_class->get_caps = GST_DEBUG_FUNCPTR (gst_inter_sub_src_get_caps);
|
||||||
|
base_src_class->set_caps = GST_DEBUG_FUNCPTR (gst_inter_sub_src_set_caps);
|
||||||
|
if (0)
|
||||||
|
base_src_class->negotiate = GST_DEBUG_FUNCPTR (gst_inter_sub_src_negotiate);
|
||||||
|
if (0)
|
||||||
|
base_src_class->newsegment =
|
||||||
|
GST_DEBUG_FUNCPTR (gst_inter_sub_src_newsegment);
|
||||||
|
base_src_class->start = GST_DEBUG_FUNCPTR (gst_inter_sub_src_start);
|
||||||
|
base_src_class->stop = GST_DEBUG_FUNCPTR (gst_inter_sub_src_stop);
|
||||||
|
base_src_class->get_times = GST_DEBUG_FUNCPTR (gst_inter_sub_src_get_times);
|
||||||
|
if (0)
|
||||||
|
base_src_class->is_seekable =
|
||||||
|
GST_DEBUG_FUNCPTR (gst_inter_sub_src_is_seekable);
|
||||||
|
base_src_class->unlock = GST_DEBUG_FUNCPTR (gst_inter_sub_src_unlock);
|
||||||
|
base_src_class->event = GST_DEBUG_FUNCPTR (gst_inter_sub_src_event);
|
||||||
|
base_src_class->create = GST_DEBUG_FUNCPTR (gst_inter_sub_src_create);
|
||||||
|
if (0)
|
||||||
|
base_src_class->do_seek = GST_DEBUG_FUNCPTR (gst_inter_sub_src_do_seek);
|
||||||
|
base_src_class->query = GST_DEBUG_FUNCPTR (gst_inter_sub_src_query);
|
||||||
|
if (0)
|
||||||
|
base_src_class->check_get_range =
|
||||||
|
GST_DEBUG_FUNCPTR (gst_inter_sub_src_check_get_range);
|
||||||
|
base_src_class->fixate = GST_DEBUG_FUNCPTR (gst_inter_sub_src_fixate);
|
||||||
|
if (0)
|
||||||
|
base_src_class->unlock_stop =
|
||||||
|
GST_DEBUG_FUNCPTR (gst_inter_sub_src_unlock_stop);
|
||||||
|
if (0)
|
||||||
|
base_src_class->prepare_seek_segment =
|
||||||
|
GST_DEBUG_FUNCPTR (gst_inter_sub_src_prepare_seek_segment);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_inter_sub_src_init (GstInterSubSrc * intersubsrc,
|
||||||
|
GstInterSubSrcClass * intersubsrc_class)
|
||||||
|
{
|
||||||
|
|
||||||
|
intersubsrc->srcpad =
|
||||||
|
gst_pad_new_from_static_template (&gst_inter_sub_src_src_template, "src");
|
||||||
|
|
||||||
|
gst_base_src_set_format (GST_BASE_SRC (intersubsrc), GST_FORMAT_TIME);
|
||||||
|
gst_base_src_set_live (GST_BASE_SRC (intersubsrc), TRUE);
|
||||||
|
|
||||||
|
intersubsrc->surface = gst_inter_surface_get ("default");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_inter_sub_src_set_property (GObject * object, guint property_id,
|
||||||
|
const GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
/* GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (object); */
|
||||||
|
|
||||||
|
switch (property_id) {
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_inter_sub_src_get_property (GObject * object, guint property_id,
|
||||||
|
GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
/* GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (object); */
|
||||||
|
|
||||||
|
switch (property_id) {
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_inter_sub_src_dispose (GObject * object)
|
||||||
|
{
|
||||||
|
/* GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (object); */
|
||||||
|
|
||||||
|
/* clean up as possible. may be called multiple times */
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_inter_sub_src_finalize (GObject * object)
|
||||||
|
{
|
||||||
|
/* GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (object); */
|
||||||
|
|
||||||
|
/* clean up object here */
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static GstCaps *
|
||||||
|
gst_inter_sub_src_get_caps (GstBaseSrc * src)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "get_caps");
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_src_set_caps (GstBaseSrc * src, GstCaps * caps)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "set_caps");
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_src_negotiate (GstBaseSrc * src)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "negotiate");
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_src_newsegment (GstBaseSrc * src)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "newsegment");
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_src_start (GstBaseSrc * src)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "start");
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_src_stop (GstBaseSrc * src)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "stop");
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_inter_sub_src_get_times (GstBaseSrc * src, GstBuffer * buffer,
|
||||||
|
GstClockTime * start, GstClockTime * end)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "get_times");
|
||||||
|
|
||||||
|
/* for live sources, sync on the timestamp of the buffer */
|
||||||
|
if (gst_base_src_is_live (src)) {
|
||||||
|
GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
|
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
|
||||||
|
/* get duration to calculate end time */
|
||||||
|
GstClockTime duration = GST_BUFFER_DURATION (buffer);
|
||||||
|
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID (duration)) {
|
||||||
|
*end = timestamp + duration;
|
||||||
|
}
|
||||||
|
*start = timestamp;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*start = -1;
|
||||||
|
*end = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_src_is_seekable (GstBaseSrc * src)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "is_seekable");
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_src_unlock (GstBaseSrc * src)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "unlock");
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_src_event (GstBaseSrc * src, GstEvent * event)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "event");
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_inter_sub_src_create (GstBaseSrc * src, guint64 offset, guint size,
|
||||||
|
GstBuffer ** buf)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
GstBuffer *buffer;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "create");
|
||||||
|
|
||||||
|
buffer = NULL;
|
||||||
|
|
||||||
|
g_mutex_lock (intersubsrc->surface->mutex);
|
||||||
|
if (intersubsrc->surface->sub_buffer) {
|
||||||
|
buffer = gst_buffer_ref (intersubsrc->surface->sub_buffer);
|
||||||
|
//intersubsrc->surface->sub_buffer_count++;
|
||||||
|
//if (intersubsrc->surface->sub_buffer_count >= 30) {
|
||||||
|
gst_buffer_unref (intersubsrc->surface->sub_buffer);
|
||||||
|
intersubsrc->surface->sub_buffer = NULL;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
g_mutex_unlock (intersubsrc->surface->mutex);
|
||||||
|
|
||||||
|
if (buffer == NULL) {
|
||||||
|
guint8 *data;
|
||||||
|
|
||||||
|
buffer = gst_buffer_new_and_alloc (1);
|
||||||
|
|
||||||
|
data = GST_BUFFER_DATA (buffer);
|
||||||
|
data[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = gst_buffer_make_metadata_writable (buffer);
|
||||||
|
|
||||||
|
GST_BUFFER_TIMESTAMP (buffer) =
|
||||||
|
gst_util_uint64_scale_int (GST_SECOND, intersubsrc->n_frames,
|
||||||
|
intersubsrc->rate);
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "create ts %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
|
||||||
|
GST_BUFFER_DURATION (buffer) =
|
||||||
|
gst_util_uint64_scale_int (GST_SECOND, (intersubsrc->n_frames + 1),
|
||||||
|
intersubsrc->rate) - GST_BUFFER_TIMESTAMP (buffer);
|
||||||
|
GST_BUFFER_OFFSET (buffer) = intersubsrc->n_frames;
|
||||||
|
GST_BUFFER_OFFSET_END (buffer) = -1;
|
||||||
|
GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);
|
||||||
|
if (intersubsrc->n_frames == 0) {
|
||||||
|
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
|
||||||
|
}
|
||||||
|
gst_buffer_set_caps (buffer, GST_PAD_CAPS (GST_BASE_SRC_PAD (intersubsrc)));
|
||||||
|
intersubsrc->n_frames++;
|
||||||
|
|
||||||
|
*buf = buffer;
|
||||||
|
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_src_do_seek (GstBaseSrc * src, GstSegment * segment)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "do_seek");
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_src_query (GstBaseSrc * src, GstQuery * query)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "query");
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_src_check_get_range (GstBaseSrc * src)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "get_range");
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_inter_sub_src_fixate (GstBaseSrc * src, GstCaps * caps)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "fixate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_src_unlock_stop (GstBaseSrc * src)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "stop");
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_inter_sub_src_prepare_seek_segment (GstBaseSrc * src, GstEvent * seek,
|
||||||
|
GstSegment * segment)
|
||||||
|
{
|
||||||
|
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (intersubsrc, "seek_segment");
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
57
gst/inter/gstintersubsrc.h
Normal file
57
gst/inter/gstintersubsrc.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2011 David Schleef <ds@entropywave.com>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GST_INTER_SUB_SRC_H_
|
||||||
|
#define _GST_INTER_SUB_SRC_H_
|
||||||
|
|
||||||
|
#include <gst/base/gstbasesrc.h>
|
||||||
|
#include "gstintersurface.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define GST_TYPE_INTER_SUB_SRC (gst_inter_sub_src_get_type())
|
||||||
|
#define GST_INTER_SUB_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_INTER_SUB_SRC,GstInterSubSrc))
|
||||||
|
#define GST_INTER_SUB_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_INTER_SUB_SRC,GstInterSubSrcClass))
|
||||||
|
#define GST_IS_INTER_SUB_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_INTER_SUB_SRC))
|
||||||
|
#define GST_IS_INTER_SUB_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_INTER_SUB_SRC))
|
||||||
|
|
||||||
|
typedef struct _GstInterSubSrc GstInterSubSrc;
|
||||||
|
typedef struct _GstInterSubSrcClass GstInterSubSrcClass;
|
||||||
|
|
||||||
|
struct _GstInterSubSrc
|
||||||
|
{
|
||||||
|
GstBaseSrc base_intersubsrc;
|
||||||
|
|
||||||
|
GstPad *srcpad;
|
||||||
|
GstInterSurface *surface;
|
||||||
|
|
||||||
|
int rate;
|
||||||
|
int n_frames;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstInterSubSrcClass
|
||||||
|
{
|
||||||
|
GstBaseSrcClass base_intersubsrc_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType gst_inter_sub_src_get_type (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -21,22 +21,43 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "gstintersurface.h"
|
#include "gstintersurface.h"
|
||||||
|
|
||||||
static GstInterSurface *surface;
|
static GList *list;
|
||||||
|
static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
|
||||||
|
|
||||||
|
|
||||||
GstInterSurface *
|
GstInterSurface *
|
||||||
gst_inter_surface_get (const char *name)
|
gst_inter_surface_get (const char *name)
|
||||||
{
|
{
|
||||||
return surface;
|
GList *g;
|
||||||
|
GstInterSurface *surface;
|
||||||
|
|
||||||
|
g_static_mutex_lock (&mutex);
|
||||||
|
|
||||||
|
for (g = list; g; g = g_list_next (g)) {
|
||||||
|
surface = (GstInterSurface *) g->data;
|
||||||
|
if (strcmp (name, surface->name) == 0) {
|
||||||
|
g_static_mutex_unlock (&mutex);
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
surface = g_malloc0 (sizeof (GstInterSurface));
|
||||||
|
surface->name = g_strdup (name);
|
||||||
|
surface->mutex = g_mutex_new ();
|
||||||
|
surface->audio_adapter = gst_adapter_new ();
|
||||||
|
|
||||||
|
list = g_list_append (list, surface);
|
||||||
|
g_static_mutex_unlock (&mutex);
|
||||||
|
|
||||||
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gst_inter_surface_init (void)
|
gst_inter_surface_unref (GstInterSurface * surface)
|
||||||
{
|
{
|
||||||
surface = g_malloc0 (sizeof (GstInterSurface));
|
|
||||||
surface->mutex = g_mutex_new ();
|
|
||||||
surface->audio_adapter = gst_adapter_new ();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ typedef struct _GstInterSurface GstInterSurface;
|
||||||
struct _GstInterSurface
|
struct _GstInterSurface
|
||||||
{
|
{
|
||||||
GMutex *mutex;
|
GMutex *mutex;
|
||||||
|
char *name;
|
||||||
|
|
||||||
/* video */
|
/* video */
|
||||||
GstVideoFormat format;
|
GstVideoFormat format;
|
||||||
|
@ -45,12 +46,13 @@ struct _GstInterSurface
|
||||||
int n_channels;
|
int n_channels;
|
||||||
|
|
||||||
GstBuffer *video_buffer;
|
GstBuffer *video_buffer;
|
||||||
|
GstBuffer *sub_buffer;
|
||||||
GstAdapter *audio_adapter;
|
GstAdapter *audio_adapter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
GstInterSurface * gst_inter_surface_get (const char *name);
|
GstInterSurface * gst_inter_surface_get (const char *name);
|
||||||
void gst_inter_surface_init (void);
|
void gst_inter_surface_unref (GstInterSurface *surface);
|
||||||
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
|
@ -76,7 +76,8 @@ static gboolean gst_inter_video_sink_unlock_stop (GstBaseSink * sink);
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0
|
PROP_0,
|
||||||
|
PROP_CHANNEL
|
||||||
};
|
};
|
||||||
|
|
||||||
/* pad templates */
|
/* pad templates */
|
||||||
|
@ -144,6 +145,10 @@ gst_inter_video_sink_class_init (GstInterVideoSinkClass * klass)
|
||||||
base_sink_class->unlock_stop =
|
base_sink_class->unlock_stop =
|
||||||
GST_DEBUG_FUNCPTR (gst_inter_video_sink_unlock_stop);
|
GST_DEBUG_FUNCPTR (gst_inter_video_sink_unlock_stop);
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_CHANNEL,
|
||||||
|
g_param_spec_string ("channel", "Channel",
|
||||||
|
"Channel name to match inter src and sink elements",
|
||||||
|
"default", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -151,15 +156,21 @@ gst_inter_video_sink_init (GstInterVideoSink * intervideosink,
|
||||||
GstInterVideoSinkClass * intervideosink_class)
|
GstInterVideoSinkClass * intervideosink_class)
|
||||||
{
|
{
|
||||||
intervideosink->surface = gst_inter_surface_get ("default");
|
intervideosink->surface = gst_inter_surface_get ("default");
|
||||||
|
|
||||||
|
intervideosink->channel = g_strdup ("default");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gst_inter_video_sink_set_property (GObject * object, guint property_id,
|
gst_inter_video_sink_set_property (GObject * object, guint property_id,
|
||||||
const GValue * value, GParamSpec * pspec)
|
const GValue * value, GParamSpec * pspec)
|
||||||
{
|
{
|
||||||
/* GstInterVideoSink *intervideosink = GST_INTER_VIDEO_SINK (object); */
|
GstInterVideoSink *intervideosink = GST_INTER_VIDEO_SINK (object);
|
||||||
|
|
||||||
switch (property_id) {
|
switch (property_id) {
|
||||||
|
case PROP_CHANNEL:
|
||||||
|
g_free (intervideosink->channel);
|
||||||
|
intervideosink->channel = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -170,9 +181,12 @@ void
|
||||||
gst_inter_video_sink_get_property (GObject * object, guint property_id,
|
gst_inter_video_sink_get_property (GObject * object, guint property_id,
|
||||||
GValue * value, GParamSpec * pspec)
|
GValue * value, GParamSpec * pspec)
|
||||||
{
|
{
|
||||||
/* GstInterVideoSink *intervideosink = GST_INTER_VIDEO_SINK (object); */
|
GstInterVideoSink *intervideosink = GST_INTER_VIDEO_SINK (object);
|
||||||
|
|
||||||
switch (property_id) {
|
switch (property_id) {
|
||||||
|
case PROP_CHANNEL:
|
||||||
|
g_value_set_string (value, intervideosink->channel);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -192,9 +206,10 @@ gst_inter_video_sink_dispose (GObject * object)
|
||||||
void
|
void
|
||||||
gst_inter_video_sink_finalize (GObject * object)
|
gst_inter_video_sink_finalize (GObject * object)
|
||||||
{
|
{
|
||||||
/* GstInterVideoSink *intervideosink = GST_INTER_VIDEO_SINK (object); */
|
GstInterVideoSink *intervideosink = GST_INTER_VIDEO_SINK (object);
|
||||||
|
|
||||||
/* clean up object here */
|
/* clean up object here */
|
||||||
|
g_free (intervideosink->channel);
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
@ -248,6 +263,9 @@ gst_inter_video_sink_get_times (GstBaseSink * sink, GstBuffer * buffer,
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_inter_video_sink_start (GstBaseSink * sink)
|
gst_inter_video_sink_start (GstBaseSink * sink)
|
||||||
{
|
{
|
||||||
|
GstInterVideoSink *intervideosink = GST_INTER_VIDEO_SINK (sink);
|
||||||
|
|
||||||
|
intervideosink->surface = gst_inter_surface_get (intervideosink->channel);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -264,6 +282,9 @@ gst_inter_video_sink_stop (GstBaseSink * sink)
|
||||||
intervideosink->surface->video_buffer = NULL;
|
intervideosink->surface->video_buffer = NULL;
|
||||||
g_mutex_unlock (intervideosink->surface->mutex);
|
g_mutex_unlock (intervideosink->surface->mutex);
|
||||||
|
|
||||||
|
gst_inter_surface_unref (intervideosink->surface);
|
||||||
|
intervideosink->surface = NULL;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ struct _GstInterVideoSink
|
||||||
GstBaseSink base_intervideosink;
|
GstBaseSink base_intervideosink;
|
||||||
|
|
||||||
GstInterSurface *surface;
|
GstInterSurface *surface;
|
||||||
|
char *channel;
|
||||||
|
|
||||||
int fps_n;
|
int fps_n;
|
||||||
int fps_d;
|
int fps_d;
|
||||||
|
|
|
@ -80,7 +80,8 @@ gst_inter_video_src_prepare_seek_segment (GstBaseSrc * src, GstEvent * seek,
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0
|
PROP_0,
|
||||||
|
PROP_CHANNEL
|
||||||
};
|
};
|
||||||
|
|
||||||
/* pad templates */
|
/* pad templates */
|
||||||
|
@ -156,6 +157,10 @@ gst_inter_video_src_class_init (GstInterVideoSrcClass * klass)
|
||||||
base_src_class->prepare_seek_segment =
|
base_src_class->prepare_seek_segment =
|
||||||
GST_DEBUG_FUNCPTR (gst_inter_video_src_prepare_seek_segment);
|
GST_DEBUG_FUNCPTR (gst_inter_video_src_prepare_seek_segment);
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_CHANNEL,
|
||||||
|
g_param_spec_string ("channel", "Channel",
|
||||||
|
"Channel name to match inter src and sink elements",
|
||||||
|
"default", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,16 +171,20 @@ gst_inter_video_src_init (GstInterVideoSrc * intervideosrc,
|
||||||
gst_base_src_set_format (GST_BASE_SRC (intervideosrc), GST_FORMAT_TIME);
|
gst_base_src_set_format (GST_BASE_SRC (intervideosrc), GST_FORMAT_TIME);
|
||||||
gst_base_src_set_live (GST_BASE_SRC (intervideosrc), TRUE);
|
gst_base_src_set_live (GST_BASE_SRC (intervideosrc), TRUE);
|
||||||
|
|
||||||
intervideosrc->surface = gst_inter_surface_get ("default");
|
intervideosrc->channel = g_strdup ("default");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gst_inter_video_src_set_property (GObject * object, guint property_id,
|
gst_inter_video_src_set_property (GObject * object, guint property_id,
|
||||||
const GValue * value, GParamSpec * pspec)
|
const GValue * value, GParamSpec * pspec)
|
||||||
{
|
{
|
||||||
/* GstInterVideoSrc *intervideosrc = GST_INTER_VIDEO_SRC (object); */
|
GstInterVideoSrc *intervideosrc = GST_INTER_VIDEO_SRC (object);
|
||||||
|
|
||||||
switch (property_id) {
|
switch (property_id) {
|
||||||
|
case PROP_CHANNEL:
|
||||||
|
g_free (intervideosrc->channel);
|
||||||
|
intervideosrc->channel = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -186,9 +195,12 @@ void
|
||||||
gst_inter_video_src_get_property (GObject * object, guint property_id,
|
gst_inter_video_src_get_property (GObject * object, guint property_id,
|
||||||
GValue * value, GParamSpec * pspec)
|
GValue * value, GParamSpec * pspec)
|
||||||
{
|
{
|
||||||
/* GstInterVideoSrc *intervideosrc = GST_INTER_VIDEO_SRC (object); */
|
GstInterVideoSrc *intervideosrc = GST_INTER_VIDEO_SRC (object);
|
||||||
|
|
||||||
switch (property_id) {
|
switch (property_id) {
|
||||||
|
case PROP_CHANNEL:
|
||||||
|
g_value_set_string (value, intervideosrc->channel);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -208,9 +220,10 @@ gst_inter_video_src_dispose (GObject * object)
|
||||||
void
|
void
|
||||||
gst_inter_video_src_finalize (GObject * object)
|
gst_inter_video_src_finalize (GObject * object)
|
||||||
{
|
{
|
||||||
/* GstInterVideoSrc *intervideosrc = GST_INTER_VIDEO_SRC (object); */
|
GstInterVideoSrc *intervideosrc = GST_INTER_VIDEO_SRC (object);
|
||||||
|
|
||||||
/* clean up object here */
|
/* clean up object here */
|
||||||
|
g_free (intervideosrc->channel);
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
@ -279,6 +292,8 @@ gst_inter_video_src_start (GstBaseSrc * src)
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (intervideosrc, "start");
|
GST_DEBUG_OBJECT (intervideosrc, "start");
|
||||||
|
|
||||||
|
intervideosrc->surface = gst_inter_surface_get (intervideosrc->channel);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,6 +304,9 @@ gst_inter_video_src_stop (GstBaseSrc * src)
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (intervideosrc, "stop");
|
GST_DEBUG_OBJECT (intervideosrc, "stop");
|
||||||
|
|
||||||
|
gst_inter_surface_unref (intervideosrc->surface);
|
||||||
|
intervideosrc->surface = NULL;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,15 +409,6 @@ gst_inter_video_src_create (GstBaseSrc * src, guint64 offset, guint size,
|
||||||
intervideosrc->width) *
|
intervideosrc->width) *
|
||||||
gst_video_format_get_component_height (intervideosrc->format, 1,
|
gst_video_format_get_component_height (intervideosrc->format, 1,
|
||||||
intervideosrc->height));
|
intervideosrc->height));
|
||||||
|
|
||||||
#if 0
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 10000; i++) {
|
|
||||||
data[i] = g_random_int () & 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer = gst_buffer_make_metadata_writable (buffer);
|
buffer = gst_buffer_make_metadata_writable (buffer);
|
||||||
|
|
|
@ -41,6 +41,8 @@ struct _GstInterVideoSrc
|
||||||
|
|
||||||
GstInterSurface *surface;
|
GstInterSurface *surface;
|
||||||
|
|
||||||
|
char *channel;
|
||||||
|
|
||||||
GstVideoFormat format;
|
GstVideoFormat format;
|
||||||
int fps_n;
|
int fps_n;
|
||||||
int fps_d;
|
int fps_d;
|
||||||
|
|
|
@ -122,6 +122,8 @@ mpegts_pmt_stream_info_finalize (GObject * object)
|
||||||
|
|
||||||
g_value_array_free (info->languages);
|
g_value_array_free (info->languages);
|
||||||
g_value_array_free (info->descriptors);
|
g_value_array_free (info->descriptors);
|
||||||
|
|
||||||
|
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
|
||||||
}
|
}
|
||||||
|
|
||||||
MpegTsPmtStreamInfo *
|
MpegTsPmtStreamInfo *
|
||||||
|
|
|
@ -60,6 +60,8 @@
|
||||||
#define SEGMENT_THRESHOLD (300*GST_MSECOND)
|
#define SEGMENT_THRESHOLD (300*GST_MSECOND)
|
||||||
#define VIDEO_SEGMENT_THRESHOLD (500*GST_MSECOND)
|
#define VIDEO_SEGMENT_THRESHOLD (500*GST_MSECOND)
|
||||||
|
|
||||||
|
#define DURATION_SCAN_LIMIT 4 * 1024 * 1024
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
SCAN_SCR,
|
SCAN_SCR,
|
||||||
|
@ -154,9 +156,9 @@ static GstStateChangeReturn gst_flups_demux_change_state (GstElement * element,
|
||||||
GstStateChange transition);
|
GstStateChange transition);
|
||||||
|
|
||||||
static inline gboolean gst_flups_demux_scan_forward_ts (GstFluPSDemux * demux,
|
static inline gboolean gst_flups_demux_scan_forward_ts (GstFluPSDemux * demux,
|
||||||
guint64 * pos, SCAN_MODE mode, guint64 * rts);
|
guint64 * pos, SCAN_MODE mode, guint64 * rts, gint limit);
|
||||||
static inline gboolean gst_flups_demux_scan_backward_ts (GstFluPSDemux * demux,
|
static inline gboolean gst_flups_demux_scan_backward_ts (GstFluPSDemux * demux,
|
||||||
guint64 * pos, SCAN_MODE mode, guint64 * rts);
|
guint64 * pos, SCAN_MODE mode, guint64 * rts, gint limit);
|
||||||
|
|
||||||
static inline void gst_flups_demux_send_segment_updates (GstFluPSDemux * demux,
|
static inline void gst_flups_demux_send_segment_updates (GstFluPSDemux * demux,
|
||||||
GstClockTime new_time);
|
GstClockTime new_time);
|
||||||
|
@ -399,8 +401,13 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name == NULL || template == NULL || caps == NULL)
|
if (name == NULL || template == NULL || caps == NULL) {
|
||||||
return NULL;
|
if (name)
|
||||||
|
g_free (name);
|
||||||
|
if (caps)
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
stream = g_new0 (GstFluPSStream, 1);
|
stream = g_new0 (GstFluPSStream, 1);
|
||||||
stream->id = id;
|
stream->id = id;
|
||||||
|
@ -1046,19 +1053,22 @@ gst_flups_demux_do_seek (GstFluPSDemux * demux, GstSegment * seeksegment)
|
||||||
MIN (gst_util_uint64_scale (scr - demux->first_scr, scr_rate_n,
|
MIN (gst_util_uint64_scale (scr - demux->first_scr, scr_rate_n,
|
||||||
scr_rate_d), demux->sink_segment.stop);
|
scr_rate_d), demux->sink_segment.stop);
|
||||||
|
|
||||||
found = gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &fscr);
|
found = gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &fscr, 0);
|
||||||
if (!found) {
|
if (!found) {
|
||||||
found = gst_flups_demux_scan_backward_ts (demux, &offset, SCAN_SCR, &fscr);
|
found =
|
||||||
|
gst_flups_demux_scan_backward_ts (demux, &offset, SCAN_SCR, &fscr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (found && fscr < scr) {
|
while (found && fscr < scr) {
|
||||||
offset++;
|
offset++;
|
||||||
found = gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &fscr);
|
found =
|
||||||
|
gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &fscr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (found && fscr > scr && offset > 0) {
|
while (found && fscr > scr && offset > 0) {
|
||||||
offset--;
|
offset--;
|
||||||
found = gst_flups_demux_scan_backward_ts (demux, &offset, SCAN_SCR, &fscr);
|
found =
|
||||||
|
gst_flups_demux_scan_backward_ts (demux, &offset, SCAN_SCR, &fscr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_INFO_OBJECT (demux, "doing seek at offset %" G_GUINT64_FORMAT
|
GST_INFO_OBJECT (demux, "doing seek at offset %" G_GUINT64_FORMAT
|
||||||
|
@ -2377,7 +2387,7 @@ beach:
|
||||||
|
|
||||||
static inline gboolean
|
static inline gboolean
|
||||||
gst_flups_demux_scan_forward_ts (GstFluPSDemux * demux, guint64 * pos,
|
gst_flups_demux_scan_forward_ts (GstFluPSDemux * demux, guint64 * pos,
|
||||||
SCAN_MODE mode, guint64 * rts)
|
SCAN_MODE mode, guint64 * rts, gint limit)
|
||||||
{
|
{
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
GstBuffer *buffer = NULL;
|
GstBuffer *buffer = NULL;
|
||||||
|
@ -2387,12 +2397,15 @@ gst_flups_demux_scan_forward_ts (GstFluPSDemux * demux, guint64 * pos,
|
||||||
guint scan_sz = (mode == SCAN_SCR ? SCAN_SCR_SZ : SCAN_PTS_SZ);
|
guint scan_sz = (mode == SCAN_SCR ? SCAN_SCR_SZ : SCAN_PTS_SZ);
|
||||||
guint cursor, to_read = BLOCK_SZ;
|
guint cursor, to_read = BLOCK_SZ;
|
||||||
guint8 *data;
|
guint8 *data;
|
||||||
guint end_scan;
|
guint end_scan, data_size;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (offset + scan_sz > demux->sink_segment.stop)
|
if (offset + scan_sz > demux->sink_segment.stop)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
if (limit && offset > *pos + limit)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
if (offset + to_read > demux->sink_segment.stop)
|
if (offset + to_read > demux->sink_segment.stop)
|
||||||
to_read = demux->sink_segment.stop - offset;
|
to_read = demux->sink_segment.stop - offset;
|
||||||
|
|
||||||
|
@ -2401,8 +2414,14 @@ gst_flups_demux_scan_forward_ts (GstFluPSDemux * demux, guint64 * pos,
|
||||||
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
/* may get a short buffer at the end of the file */
|
||||||
|
data_size = GST_BUFFER_SIZE (buffer);
|
||||||
|
if (G_UNLIKELY (data_size <= scan_sz))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
data = GST_BUFFER_DATA (buffer);
|
data = GST_BUFFER_DATA (buffer);
|
||||||
end_scan = GST_BUFFER_SIZE (buffer) - scan_sz;
|
end_scan = data_size - scan_sz;
|
||||||
|
|
||||||
/* scan the block */
|
/* scan the block */
|
||||||
for (cursor = 0; !found && cursor <= end_scan; cursor++) {
|
for (cursor = 0; !found && cursor <= end_scan; cursor++) {
|
||||||
found = gst_flups_demux_scan_ts (demux, data++, mode, &ts);
|
found = gst_flups_demux_scan_ts (demux, data++, mode, &ts);
|
||||||
|
@ -2424,7 +2443,7 @@ gst_flups_demux_scan_forward_ts (GstFluPSDemux * demux, guint64 * pos,
|
||||||
|
|
||||||
static inline gboolean
|
static inline gboolean
|
||||||
gst_flups_demux_scan_backward_ts (GstFluPSDemux * demux, guint64 * pos,
|
gst_flups_demux_scan_backward_ts (GstFluPSDemux * demux, guint64 * pos,
|
||||||
SCAN_MODE mode, guint64 * rts)
|
SCAN_MODE mode, guint64 * rts, gint limit)
|
||||||
{
|
{
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
GstBuffer *buffer = NULL;
|
GstBuffer *buffer = NULL;
|
||||||
|
@ -2433,13 +2452,16 @@ gst_flups_demux_scan_backward_ts (GstFluPSDemux * demux, guint64 * pos,
|
||||||
guint64 ts = 0;
|
guint64 ts = 0;
|
||||||
guint scan_sz = (mode == SCAN_SCR ? SCAN_SCR_SZ : SCAN_PTS_SZ);
|
guint scan_sz = (mode == SCAN_SCR ? SCAN_SCR_SZ : SCAN_PTS_SZ);
|
||||||
guint cursor, to_read = BLOCK_SZ;
|
guint cursor, to_read = BLOCK_SZ;
|
||||||
guint start_scan;
|
guint start_scan, data_size;
|
||||||
guint8 *data;
|
guint8 *data;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (offset < scan_sz - 1)
|
if (offset < scan_sz - 1)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
if (limit && offset < *pos - limit)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
if (offset > BLOCK_SZ)
|
if (offset > BLOCK_SZ)
|
||||||
offset -= BLOCK_SZ;
|
offset -= BLOCK_SZ;
|
||||||
else {
|
else {
|
||||||
|
@ -2451,8 +2473,14 @@ gst_flups_demux_scan_backward_ts (GstFluPSDemux * demux, guint64 * pos,
|
||||||
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
start_scan = GST_BUFFER_SIZE (buffer) - scan_sz;
|
/* may get a short buffer at the end of the file */
|
||||||
|
data_size = GST_BUFFER_SIZE (buffer);
|
||||||
|
if (G_UNLIKELY (data_size <= scan_sz))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
start_scan = data_size - scan_sz;
|
||||||
data = GST_BUFFER_DATA (buffer) + start_scan;
|
data = GST_BUFFER_DATA (buffer) + start_scan;
|
||||||
|
|
||||||
/* scan the block */
|
/* scan the block */
|
||||||
for (cursor = (start_scan + 1); !found && cursor > 0; cursor--) {
|
for (cursor = (start_scan + 1); !found && cursor > 0; cursor--) {
|
||||||
found = gst_flups_demux_scan_ts (demux, data--, mode, &ts);
|
found = gst_flups_demux_scan_ts (demux, data--, mode, &ts);
|
||||||
|
@ -2505,7 +2533,8 @@ gst_flups_sink_get_duration (GstFluPSDemux * demux)
|
||||||
/* Scan for notorious SCR and PTS to calculate the duration */
|
/* Scan for notorious SCR and PTS to calculate the duration */
|
||||||
/* scan for first SCR in the stream */
|
/* scan for first SCR in the stream */
|
||||||
offset = demux->sink_segment.start;
|
offset = demux->sink_segment.start;
|
||||||
gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &demux->first_scr);
|
gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &demux->first_scr,
|
||||||
|
DURATION_SCAN_LIMIT);
|
||||||
GST_DEBUG_OBJECT (demux, "First SCR: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT
|
GST_DEBUG_OBJECT (demux, "First SCR: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT
|
||||||
" in packet starting at %" G_GUINT64_FORMAT,
|
" in packet starting at %" G_GUINT64_FORMAT,
|
||||||
demux->first_scr, GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->first_scr)),
|
demux->first_scr, GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->first_scr)),
|
||||||
|
@ -2513,7 +2542,8 @@ gst_flups_sink_get_duration (GstFluPSDemux * demux)
|
||||||
demux->first_scr_offset = offset;
|
demux->first_scr_offset = offset;
|
||||||
/* scan for last SCR in the stream */
|
/* scan for last SCR in the stream */
|
||||||
offset = demux->sink_segment.stop;
|
offset = demux->sink_segment.stop;
|
||||||
gst_flups_demux_scan_backward_ts (demux, &offset, SCAN_SCR, &demux->last_scr);
|
gst_flups_demux_scan_backward_ts (demux, &offset, SCAN_SCR,
|
||||||
|
&demux->last_scr, 0);
|
||||||
GST_DEBUG_OBJECT (demux, "Last SCR: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT
|
GST_DEBUG_OBJECT (demux, "Last SCR: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT
|
||||||
" in packet starting at %" G_GUINT64_FORMAT,
|
" in packet starting at %" G_GUINT64_FORMAT,
|
||||||
demux->last_scr, GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->last_scr)),
|
demux->last_scr, GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->last_scr)),
|
||||||
|
@ -2521,18 +2551,22 @@ gst_flups_sink_get_duration (GstFluPSDemux * demux)
|
||||||
demux->last_scr_offset = offset;
|
demux->last_scr_offset = offset;
|
||||||
/* scan for first PTS in the stream */
|
/* scan for first PTS in the stream */
|
||||||
offset = demux->sink_segment.start;
|
offset = demux->sink_segment.start;
|
||||||
gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_PTS, &demux->first_pts);
|
gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_PTS, &demux->first_pts,
|
||||||
|
DURATION_SCAN_LIMIT);
|
||||||
GST_DEBUG_OBJECT (demux, "First PTS: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT
|
GST_DEBUG_OBJECT (demux, "First PTS: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT
|
||||||
" in packet starting at %" G_GUINT64_FORMAT,
|
" in packet starting at %" G_GUINT64_FORMAT,
|
||||||
demux->first_pts, GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->first_pts)),
|
demux->first_pts, GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->first_pts)),
|
||||||
offset);
|
offset);
|
||||||
/* scan for last PTS in the stream */
|
if (demux->first_pts != G_MAXUINT64) {
|
||||||
offset = demux->sink_segment.stop;
|
/* scan for last PTS in the stream */
|
||||||
gst_flups_demux_scan_backward_ts (demux, &offset, SCAN_PTS, &demux->last_pts);
|
offset = demux->sink_segment.stop;
|
||||||
GST_DEBUG_OBJECT (demux, "Last PTS: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT
|
gst_flups_demux_scan_backward_ts (demux, &offset, SCAN_PTS,
|
||||||
" in packet starting at %" G_GUINT64_FORMAT,
|
&demux->last_pts, DURATION_SCAN_LIMIT);
|
||||||
demux->last_pts, GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->last_pts)),
|
GST_DEBUG_OBJECT (demux,
|
||||||
offset);
|
"Last PTS: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT
|
||||||
|
" in packet starting at %" G_GUINT64_FORMAT, demux->last_pts,
|
||||||
|
GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->last_pts)), offset);
|
||||||
|
}
|
||||||
/* Detect wrong SCR values */
|
/* Detect wrong SCR values */
|
||||||
if (demux->first_scr > demux->last_scr) {
|
if (demux->first_scr > demux->last_scr) {
|
||||||
GST_DEBUG_OBJECT (demux, "Wrong SCR values detected, searching for "
|
GST_DEBUG_OBJECT (demux, "Wrong SCR values detected, searching for "
|
||||||
|
@ -2540,7 +2574,7 @@ gst_flups_sink_get_duration (GstFluPSDemux * demux)
|
||||||
offset = demux->first_scr_offset;
|
offset = demux->first_scr_offset;
|
||||||
for (i = 0; i < 10; i++) {
|
for (i = 0; i < 10; i++) {
|
||||||
offset++;
|
offset++;
|
||||||
gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &scr);
|
gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &scr, 0);
|
||||||
if (scr < demux->last_scr) {
|
if (scr < demux->last_scr) {
|
||||||
demux->first_scr = scr;
|
demux->first_scr = scr;
|
||||||
demux->first_scr_offset = offset;
|
demux->first_scr_offset = offset;
|
||||||
|
|
|
@ -829,8 +829,13 @@ gst_mpegts_demux_fill_stream (GstMpegTSStream * stream, guint8 id,
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (name == NULL || template == NULL || caps == NULL)
|
if (name == NULL || template == NULL || caps == NULL) {
|
||||||
|
if (name)
|
||||||
|
g_free (name);
|
||||||
|
if (caps)
|
||||||
|
gst_caps_unref (caps);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
stream->stream_type = stream_type;
|
stream->stream_type = stream_type;
|
||||||
stream->id = id;
|
stream->id = id;
|
||||||
|
@ -1105,6 +1110,10 @@ gst_mpegts_demux_add_all_streams (GstMpegTSDemux * demux, GstClockTime pts)
|
||||||
GstPad *srcpad;
|
GstPad *srcpad;
|
||||||
gboolean all_added = TRUE;
|
gboolean all_added = TRUE;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (demux, "Adding streams early fixes a wedge in some low "
|
||||||
|
"bitrate streams, but causes deadlocks - disabled for now");
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
/* When adding a stream, require either a valid base PCR, or a valid PTS */
|
/* When adding a stream, require either a valid base PCR, or a valid PTS */
|
||||||
if (!gst_mpegts_demux_setup_base_pts (demux, pts)) {
|
if (!gst_mpegts_demux_setup_base_pts (demux, pts)) {
|
||||||
GST_ERROR ("Can't set base pts");
|
GST_ERROR ("Can't set base pts");
|
||||||
|
|
|
@ -1275,6 +1275,8 @@ mpegts_parse_get_tags_from_sdt (MpegTSParse * parse, GstStructure * sdt_info)
|
||||||
* which looks like service-%d */
|
* which looks like service-%d */
|
||||||
sid_str = gst_structure_get_name (service);
|
sid_str = gst_structure_get_name (service);
|
||||||
tmp = g_strstr_len (sid_str, -1, "-");
|
tmp = g_strstr_len (sid_str, -1, "-");
|
||||||
|
if (!tmp)
|
||||||
|
continue;
|
||||||
program_number = atoi (++tmp);
|
program_number = atoi (++tmp);
|
||||||
|
|
||||||
program = mpegts_parse_get_program (parse, program_number);
|
program = mpegts_parse_get_program (parse, program_number);
|
||||||
|
|
|
@ -1097,6 +1097,8 @@ mpegts_base_get_tags_from_sdt (MpegTSBase * base, GstStructure * sdt_info)
|
||||||
* which looks like service-%d */
|
* which looks like service-%d */
|
||||||
sid_str = gst_structure_get_name (service);
|
sid_str = gst_structure_get_name (service);
|
||||||
tmp = g_strstr_len (sid_str, -1, "-");
|
tmp = g_strstr_len (sid_str, -1, "-");
|
||||||
|
if (!tmp)
|
||||||
|
continue;
|
||||||
program_number = atoi (++tmp);
|
program_number = atoi (++tmp);
|
||||||
|
|
||||||
program = mpegts_base_get_program (base, program_number);
|
program = mpegts_base_get_program (base, program_number);
|
||||||
|
|
|
@ -1050,6 +1050,7 @@ create_pad_for_stream (MpegTSBase * base, MpegTSBaseStream * bstream,
|
||||||
name = g_strdup_printf ("private_%04x", bstream->pid);
|
name = g_strdup_printf ("private_%04x", bstream->pid);
|
||||||
caps = gst_caps_new_empty_simple ("subpicture/x-dvb");
|
caps = gst_caps_new_empty_simple ("subpicture/x-dvb");
|
||||||
g_free (desc);
|
g_free (desc);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
/* hack for itv hd (sid 10510, video pid 3401 */
|
/* hack for itv hd (sid 10510, video pid 3401 */
|
||||||
if (program->program_number == 10510 && bstream->pid == 3401) {
|
if (program->program_number == 10510 && bstream->pid == 3401) {
|
||||||
|
|
|
@ -337,7 +337,7 @@ static void
|
||||||
gst_mve_mux_palette_analyze (GstMveMux * mvemux, const GstBuffer * pal,
|
gst_mve_mux_palette_analyze (GstMveMux * mvemux, const GstBuffer * pal,
|
||||||
guint16 * first, guint16 * last)
|
guint16 * first, guint16 * last)
|
||||||
{
|
{
|
||||||
guint i;
|
gint i;
|
||||||
guint32 *col1;
|
guint32 *col1;
|
||||||
|
|
||||||
col1 = (guint32 *) GST_BUFFER_DATA (pal);
|
col1 = (guint32 *) GST_BUFFER_DATA (pal);
|
||||||
|
|
|
@ -285,6 +285,9 @@ mve_quantize (const GstMveMux * mve, const guint16 * src,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (G_UNLIKELY (!best))
|
||||||
|
continue;
|
||||||
|
|
||||||
++best->hits;
|
++best->hits;
|
||||||
best->r_total += r;
|
best->r_total += r;
|
||||||
best->g_total += g;
|
best->g_total += g;
|
||||||
|
|
|
@ -488,7 +488,7 @@ gst_nuv_demux_stream_data (GstNuvDemux * nuv)
|
||||||
switch (h->i_type) {
|
switch (h->i_type) {
|
||||||
case 'V':
|
case 'V':
|
||||||
{
|
{
|
||||||
if (h->i_length == 0)
|
if (!buf)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
GST_BUFFER_OFFSET (buf) = nuv->video_offset;
|
GST_BUFFER_OFFSET (buf) = nuv->video_offset;
|
||||||
|
@ -499,7 +499,7 @@ gst_nuv_demux_stream_data (GstNuvDemux * nuv)
|
||||||
}
|
}
|
||||||
case 'A':
|
case 'A':
|
||||||
{
|
{
|
||||||
if (h->i_length == 0)
|
if (!buf)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
GST_BUFFER_OFFSET (buf) = nuv->audio_offset;
|
GST_BUFFER_OFFSET (buf) = nuv->audio_offset;
|
||||||
|
|
|
@ -158,7 +158,7 @@ gst_siren_enc_finalize (GObject * object)
|
||||||
Siren7_CloseEncoder (enc->encoder);
|
Siren7_CloseEncoder (enc->encoder);
|
||||||
g_object_unref (enc->adapter);
|
g_object_unref (enc->adapter);
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
|
@ -33,6 +33,7 @@ Android.mk: Makefile.am $(BUILT_SOURCES)
|
||||||
$(libgstvideoparsersbad_la_LIBADD) \
|
$(libgstvideoparsersbad_la_LIBADD) \
|
||||||
-ldl \
|
-ldl \
|
||||||
-:LIBFILTER_STATIC gstbaseparse-@GST_MAJORMINOR@ \
|
-:LIBFILTER_STATIC gstbaseparse-@GST_MAJORMINOR@ \
|
||||||
|
gstcodecparsers-@GST_MAJORMINOR@ \
|
||||||
-:PASSTHROUGH LOCAL_ARM_MODE:=arm \
|
-:PASSTHROUGH LOCAL_ARM_MODE:=arm \
|
||||||
LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
|
LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
|
||||||
> $@
|
> $@
|
||||||
|
|
|
@ -6,7 +6,7 @@ libgstavc_la_CPPFLAGS = \
|
||||||
$(GST_PLUGINS_BAD_CXXFLAGS) \
|
$(GST_PLUGINS_BAD_CXXFLAGS) \
|
||||||
$(GST_PLUGINS_BASE_CXXFLAGS) \
|
$(GST_PLUGINS_BASE_CXXFLAGS) \
|
||||||
$(GST_CXXFLAGS) \
|
$(GST_CXXFLAGS) \
|
||||||
-framework AVCVideoServices
|
-framework AVCVideoServices \
|
||||||
-Wno-deprecated-declarations
|
-Wno-deprecated-declarations
|
||||||
libgstavc_la_LIBADD = \
|
libgstavc_la_LIBADD = \
|
||||||
$(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) \
|
$(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) \
|
||||||
|
|
|
@ -196,9 +196,14 @@ gst_linsys_sdi_sink_get_property (GObject * object, guint property_id,
|
||||||
void
|
void
|
||||||
gst_linsys_sdi_sink_dispose (GObject * object)
|
gst_linsys_sdi_sink_dispose (GObject * object)
|
||||||
{
|
{
|
||||||
|
GstLinsysSdiSink *linsyssdisink;
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_LINSYS_SDI_SINK (object));
|
g_return_if_fail (GST_IS_LINSYS_SDI_SINK (object));
|
||||||
|
linsyssdisink = GST_LINSYS_SDI_SINK (object);
|
||||||
|
|
||||||
/* clean up as possible. may be called multiple times */
|
/* clean up as possible. may be called multiple times */
|
||||||
|
g_free (linsyssdisink->device);
|
||||||
|
linsyssdisink->device = NULL;
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,9 +212,12 @@ gst_linsys_sdi_src_get_property (GObject * object, guint property_id,
|
||||||
void
|
void
|
||||||
gst_linsys_sdi_src_dispose (GObject * object)
|
gst_linsys_sdi_src_dispose (GObject * object)
|
||||||
{
|
{
|
||||||
g_return_if_fail (GST_IS_LINSYS_SDI_SRC (object));
|
GstLinsysSdiSrc *linsyssdisrc = GST_LINSYS_SDI_SRC (object);
|
||||||
|
g_return_if_fail (linsyssdisrc != NULL);
|
||||||
|
|
||||||
/* clean up as possible. may be called multiple times */
|
/* clean up as possible. may be called multiple times */
|
||||||
|
g_free (linsyssdisrc->device);
|
||||||
|
linsyssdisrc->device = NULL;
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue