Commit 7b63c14e authored by Ronald S. Bultje's avatar Ronald S. Bultje

HACKING: Add some basic documentation on how our wrapping works.

Original commit message from CVS:
* HACKING:
Add some basic documentation on how our wrapping works.
* TODO:
Add a list of things that could be worked on or that need doing.
* configure.ac:
Update snapshot.
* ext/ffmpeg/Makefile.am:
Changne .la links. See below (autotools patch).
* ext/ffmpeg/gstffmpeg.c: (plugin_init):
Enable demuxers. See below (gstffmpegdemux.c).
* ext/ffmpeg/gstffmpegcodecmap.c: (gst_ffmpeg_formatid_to_caps):
Realmedia caused a crash - fix that.
* ext/ffmpeg/gstffmpegdemux.c: (gst_ffmpegdemux_averror),
(gst_ffmpegdemux_base_init), (gst_ffmpegdemux_init),
(gst_ffmpegdemux_close), (gst_ffmpegdemux_dispose),
(gst_ffmpegdemux_stream_from_pad),
(gst_ffmpegdemux_src_event_mask), (gst_ffmpegdemux_src_event),
(gst_ffmpegdemux_src_format_list),
(gst_ffmpegdemux_src_query_list), (gst_ffmpegdemux_src_query),
(gst_ffmpegdemux_src_convert), (gst_ffmpegdemux_add),
(gst_ffmpegdemux_open), (gst_ffmpegdemux_loop),
(gst_ffmpegdemux_change_state), (gst_ffmpegdemux_register):
Right. OK, so I fixed up the demuxing and have it basically-working,
and the best way to get some more people to test it is to actually
enable it. I'm not sure if we want this for 0.8.0, but we can at
least give it a try. I've tested avi, matroska and mpeg, all appear
to work. The cool thing is that this gives us instant support for
several exotic formats that we'd never care about ourselves. Again,
this needs more testing for it to still be enabled in 0.8.0, but I
want to give it a try...
* ext/ffmpeg/gstffmpegmux.c: (gst_ffmpegmux_base_init),
(gst_ffmpegmux_init), (gst_ffmpegmux_request_new_pad),
(gst_ffmpegmux_connect), (gst_ffmpegmux_loop),
(gst_ffmpegmux_register):
Add some fixups that I use locally. Make it work in the case of
MPEG encoding, but the muxer is still not in shape to be enabled.
* ext/ffmpeg/gstffmpegprotocol.c: (gst_ffmpegdata_open),
(gst_ffmpegdata_read), (gst_ffmpegdata_write),
(gst_ffmpegdata_seek), (gst_ffmpegdata_close):
Some small fixups that crept into it while it was disabled for the
last few years. Basically works.
* gst-libs/ext/ffmpeg/Makefile.am:
Instead of having our local-autotoolized version, I patch the ffmpeg
source to be fully autotoolized. That means a simple SUBDIRS here
is now enough.
* gst-libs/ext/ffmpeg/Tag:
Version update.
* gst-libs/ext/ffmpeg/patch/autotools.diff:
Autotoolize ffmpeg. Needs to be sent to ffmpeg-devel@...
* gst-libs/ext/ffmpeg/patch/disableinstalllibs.diff:
Don't install their libs.
* gst-libs/ext/ffmpeg/patch/disablemmx.diff:
Don't use MMX. It cannot ocmpile using PIC.
* gst-libs/ext/ffmpeg/patch/disabletools.diff:
Don't compile/install their tools, we don't use them.
* gst-libs/ext/ffmpeg/patch/functions.diff:
Prevent symbol conflicts.
* gst-libs/ext/ffmpeg/patch/matroska.diff:
Add a matroska demuxer. Needs to be sent to ffmpeg-devel@...
parent db029240
=== gst-ffmpeg ===
2004-02-29 Ronald Bultje <rbultje@ronald.bitfreak.net>
* HACKING:
Add some basic documentation on how our wrapping works.
* TODO:
Add a list of things that could be worked on or that need doing.
* configure.ac:
Update snapshot.
* ext/ffmpeg/Makefile.am:
Changne .la links. See below (autotools patch).
* ext/ffmpeg/gstffmpeg.c: (plugin_init):
Enable demuxers. See below (gstffmpegdemux.c).
* ext/ffmpeg/gstffmpegcodecmap.c: (gst_ffmpeg_formatid_to_caps):
Realmedia caused a crash - fix that.
* ext/ffmpeg/gstffmpegdemux.c: (gst_ffmpegdemux_averror),
(gst_ffmpegdemux_base_init), (gst_ffmpegdemux_init),
(gst_ffmpegdemux_close), (gst_ffmpegdemux_dispose),
(gst_ffmpegdemux_stream_from_pad),
(gst_ffmpegdemux_src_event_mask), (gst_ffmpegdemux_src_event),
(gst_ffmpegdemux_src_format_list),
(gst_ffmpegdemux_src_query_list), (gst_ffmpegdemux_src_query),
(gst_ffmpegdemux_src_convert), (gst_ffmpegdemux_add),
(gst_ffmpegdemux_open), (gst_ffmpegdemux_loop),
(gst_ffmpegdemux_change_state), (gst_ffmpegdemux_register):
Right. OK, so I fixed up the demuxing and have it basically-working,
and the best way to get some more people to test it is to actually
enable it. I'm not sure if we want this for 0.8.0, but we can at
least give it a try. I've tested avi, matroska and mpeg, all appear
to work. The cool thing is that this gives us instant support for
several exotic formats that we'd never care about ourselves. Again,
this needs more testing for it to still be enabled in 0.8.0, but I
want to give it a try...
* ext/ffmpeg/gstffmpegmux.c: (gst_ffmpegmux_base_init),
(gst_ffmpegmux_init), (gst_ffmpegmux_request_new_pad),
(gst_ffmpegmux_connect), (gst_ffmpegmux_loop),
(gst_ffmpegmux_register):
Add some fixups that I use locally. Make it work in the case of
MPEG encoding, but the muxer is still not in shape to be enabled.
* ext/ffmpeg/gstffmpegprotocol.c: (gst_ffmpegdata_open),
(gst_ffmpegdata_read), (gst_ffmpegdata_write),
(gst_ffmpegdata_seek), (gst_ffmpegdata_close):
Some small fixups that crept into it while it was disabled for the
last few years. Basically works.
* gst-libs/ext/ffmpeg/Makefile.am:
Instead of having our local-autotoolized version, I patch the ffmpeg
source to be fully autotoolized. That means a simple SUBDIRS here
is now enough.
* gst-libs/ext/ffmpeg/Tag:
Version update.
* gst-libs/ext/ffmpeg/patch/autotools.diff:
Autotoolize ffmpeg. Needs to be sent to ffmpeg-devel@...
* gst-libs/ext/ffmpeg/patch/disableinstalllibs.diff:
Don't install their libs.
* gst-libs/ext/ffmpeg/patch/disablemmx.diff:
Don't use MMX. It cannot ocmpile using PIC.
* gst-libs/ext/ffmpeg/patch/disabletools.diff:
Don't compile/install their tools, we don't use them.
* gst-libs/ext/ffmpeg/patch/functions.diff:
Prevent symbol conflicts.
* gst-libs/ext/ffmpeg/patch/matroska.diff:
Add a matroska demuxer. Needs to be sent to ffmpeg-devel@...
2004-02-26 Thomas Vander Stichele <thomas at apestaart dot org>
......
......@@ -34,3 +34,65 @@ Axioms under which we work:
- it would be very nice if, on update of either the Tag file or the patch set,
make would know exactly what to do with it.
Some notes on how ffmpeg wrapping inside GStreamer currently works:
* gstffmpeg{dec,enc,demux,mux}.c are wrappers for specific element types from
their ffmpeg counterpart. If you want to wrap a new type of element in
ffmpeg (e.g. the URLProtocol things), then you'd need to write a new
wrapper file.
* gstffmpegcolorspace.c is a wrapper for one specific function in ffmpeg:
colorspace conversion. This works different from the previously mentioned
ones, and we'll come to that in the next item. If you want to wrap one
specific function, then that, too, belongs in a new wrapper file.
* the important difference between all those is that the colorspace element
contains one element, so there is a 1<->1 mapping. This makes for a fairly
basic element implementation. gstffmpegcolorspace.c, therefore, doesn't
differ much from other colorspace elements. The ffmpeg element types,
however, define a whole *list* of elements (in GStreamer, each decoder etc.
needs to be its own element). We use a set of tricks for that to keep
coding simple: codec mapping and dynamic type creation.
* ffmpeg uses CODEC_ID_* enumerations for their codecs. GStreamer uses caps,
which consists of a mimetype and a defined set of properties. In ffmpeg,
these properties live in a AVCodecContext struct, which contains anything
that could configure any codec (which makes it rather messy, but ohwell).
To convert from one to the other, we use codec mapping, which is done in
gstffmpegcodecmap.[ch]. This is the most important file in the whole
ffmpeg wrapping process! It contains functions to go from a codec type
(video or audio - used as the output format for decoding or the input
format for encoding), a codec id (to identify each format) or a format id
(a string identifying a file format - usually the file format extension)
to a GstCaps, and the other way around.
* to define multiple elements in one source file (which all behave similarly),
we dynamically create types for each plugin and let all of them operate on
the same struct (GstFFMpegDec, GstFFMpegEnc, ...). The functions in
gstffmpeg{dec,enc,demux,mux}.c called gst_ffmpeg*_register() do this.
The magic is as follows: for each codec or format, ffmpeg has a single
AVCodec or AV{Input,Output}Format, which are packed together in a list of
supported codecs/formats. We simply walk through the list, for each of
those, we check whether gstffmpegcodecmap.c knows about this single one.
If it does, we get the GstCaps for each pad template that belongs to it,
and register a type for all of those together. We also leave this inside
a caching struct, that will later be used by the base_init() function to
fill in information about this specific codec in the class struct of this
element (pad templates and codec/format information). Since the actual
codec information is the only thing that really makes each codec/format
different (they all behave the same through the ffmpeg API), we don't
really need to do anything else that is codec-specific, so all other
functions are rather simple.
* one particular thing that needs mention is how gstffmpeg{mux,demux}.c and
gstffmpegprotocol.c interoperate. ffmpeg uses URLProtocols for data input
and output. Now, of course, we want to use the *GStreamer* way of doing
input and output (filesrc, ...) rather than the ffmpeg way. Therefore, we
wrap up a GstPad as a URLProtocol and register this with ffmpeg. This is
what gstffmpegprotocol.c does. The URL is called gstreamer://%p, where %p
is the address of a GstPad. gstffmpeg{mux,demux}.c then open a file called
gstreamer://%p, with %p being their source/sink pad, respectively. This
way, we use GStreamer for data input/output through the ffmpeg API. It's
rather ugly, but it has worked quite well so far.
* there's lots of things that still need doing. See the TODO file for more
information.
The never-ending story of new features:
* add more codecs into our codec map
* encoding/decoding support lacks:
- event handling (particularly discont/flush and EOS)
- prevent data copying
* demux/mux support lacks:
- good testing of exotic formats
- correct caps sets on the pad templates
- event handling in the loop function (mux)
- prevent data copying
* some sort of codectype-fallback, so that we still register a codec plus its
mimetype even if we don't have a defined gst-type for it
* ffvideoscale && other filter elements
* can we wrap URLProtocol as a source/sink?
* propagate options like --disable-ffplay (and server and ffmpeg) to ffmpeg
source tree build directly in AC_CONFIG_SUBDIRS instead of the
'disabletools.diff' patch
If you have cool ideas, add them here or contact the mailinglist:
<gstreamer-devel@lists.sf.net>
......@@ -83,7 +83,7 @@ GST_CHECK_FEATURE(FFMPEG, [ffmpeg plug-ins], ffmpeg, [
# prerelease and release should get it disted
if test "x$GST_PLUGINS_VERSION_NANO" = x1; then
AC_MSG_NOTICE(slurping FFmpeg CVS source)
AS_SLURP_FFMPEG(gst-libs/ext/ffmpeg, 2003-10-26 10:00 GMT,
AS_SLURP_FFMPEG(gst-libs/ext/ffmpeg, 2004-02-29 20:00 GMT,
HAVE_FFMPEG=yes, HAVE_FFMPEG=no)
else
AC_MSG_NOTICE(FFmpeg CVS code should be included already)
......@@ -100,7 +100,7 @@ GST_ARCH()
dnl ###########################
dnl # Configure external libs #
dnl ###########################
if test "x$HAVE_FFMPEG" = xyes; then
if test "x$HAVE_FFMPEG" = "xyes"; then
AC_CONFIG_SUBDIRS(gst-libs/ext/ffmpeg/ffmpeg)
fi
......
......@@ -14,8 +14,8 @@ libgstffmpeg_la_CFLAGS = $(GST_CFLAGS) \
-I $(top_srcdir)/gst-libs/ext/ffmpeg/ffmpeg/libavcodec \
-I $(top_srcdir)/gst-libs/ext/ffmpeg/ffmpeg/libavformat
libgstffmpeg_la_LIBADD = \
$(top_builddir)/gst-libs/ext/ffmpeg/libavcodec.la \
$(top_builddir)/gst-libs/ext/ffmpeg/libavformat.la
$(top_builddir)/gst-libs/ext/ffmpeg/ffmpeg/libavcodec/libavcodec.la \
$(top_builddir)/gst-libs/ext/ffmpeg/ffmpeg/libavformat/libavformat.la
libgstffmpeg_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
......
......@@ -53,11 +53,11 @@ plugin_init (GstPlugin *plugin)
gst_ffmpegenc_register (plugin);
gst_ffmpegdec_register (plugin);
/*gst_ffmpegdemux_register (plugin);*/
gst_ffmpegdemux_register (plugin);
/*gst_ffmpegmux_register (plugin);*/
gst_ffmpegcsp_register (plugin);
/*register_protocol (&gstreamer_protocol);*/
register_protocol (&gstreamer_protocol);
/* Now we can return the pointer to the newly created Plugin object. */
return TRUE;
......
......@@ -890,7 +890,7 @@ gst_ffmpeg_formatid_to_caps (const gchar *format_name)
"systemstream", G_TYPE_BOOLEAN, TRUE,
NULL);
} else if (!strcmp (format_name, "rm")) {
caps = gst_caps_new_simple ("ffmpeg_rm", "audio/x-pn-realvideo",
caps = gst_caps_new_simple ("application/x-pn-realmedia",
"systemstream", G_TYPE_BOOLEAN, TRUE,
NULL);
} else if (!strcmp (format_name, "asf")) {
......@@ -919,7 +919,12 @@ gst_ffmpeg_formatid_to_caps (const gchar *format_name)
caps = gst_caps_new_simple ("video/x-4xm",
NULL);
} else {
/* unknown! */
gchar *name;
GST_WARNING ("Could not create stream format caps for %s", format_name);
name = g_strdup_printf ("application/x-gst_ff-%s", format_name);
caps = gst_caps_new_simple (name, NULL);
g_free (name);
}
return caps;
......
This diff is collapsed.
This diff is collapsed.
......@@ -43,9 +43,9 @@ struct _GstProtocolInfo {
};
static int
gst_open (URLContext *h,
const char *filename,
int flags)
gst_ffmpegdata_open (URLContext *h,
const char *filename,
int flags)
{
GstProtocolInfo *info;
GstPad *pad;
......@@ -80,6 +80,7 @@ gst_open (URLContext *h,
}
info->eos = FALSE;
info->pad = pad;
h->priv_data = (void *) info;
......@@ -87,12 +88,12 @@ gst_open (URLContext *h,
}
static int
gst_read (URLContext *h,
unsigned char *buf,
int size)
gst_ffmpegdata_read (URLContext *h,
unsigned char *buf,
int size)
{
GstByteStream *bs;
guint32 total;
guint32 total, request;
guint8 *data;
GstProtocolInfo *info;
......@@ -102,33 +103,47 @@ gst_read (URLContext *h,
bs = info->bs;
if (info->eos)
if (info->eos)
return 0;
total = gst_bytestream_peek_bytes (bs, &data, size);
if (total < size) {
GstEvent *event;
guint32 remaining;
gst_bytestream_get_status (bs, &remaining, &event);
if (!event) {
g_warning ("gstffmpegprotocol: no bytestream event");
return total;
do {
/* prevent EOS */
if (gst_bytestream_tell (bs) + size > gst_bytestream_length (bs))
request = gst_bytestream_length (bs) - gst_bytestream_tell (bs);
else
request = size;
if (request)
total = gst_bytestream_peek_bytes (bs, &data, request);
else
total = 0;
if (total < request) {
GstEvent *event;
guint32 remaining;
gst_bytestream_get_status (bs, &remaining, &event);
if (!event) {
g_warning ("gstffmpegprotocol: no bytestream event");
return total;
}
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_DISCONTINUOUS:
gst_bytestream_flush_fast (bs, remaining);
gst_event_unref (event);
break;
case GST_EVENT_EOS:
info->eos = TRUE;
gst_event_unref (event);
break;
default:
gst_pad_event_default (info->pad, event);
break;
}
}
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_DISCONTINUOUS:
gst_bytestream_flush_fast (bs, remaining);
case GST_EVENT_EOS:
info->eos = TRUE;
break;
default:
break;
}
gst_event_unref (event);
}
} while (!info->eos && total != request);
memcpy (buf, data, total);
gst_bytestream_flush (bs, total);
......@@ -137,9 +152,9 @@ gst_read (URLContext *h,
}
static int
gst_write (URLContext *h,
unsigned char *buf,
int size)
gst_ffmpegdata_write (URLContext *h,
unsigned char *buf,
int size)
{
GstProtocolInfo *info;
GstBuffer *outbuf;
......@@ -159,9 +174,9 @@ gst_write (URLContext *h,
}
static offset_t
gst_seek (URLContext *h,
offset_t pos,
int whence)
gst_ffmpegdata_seek (URLContext *h,
offset_t pos,
int whence)
{
GstSeekType seek_type = 0;
GstProtocolInfo *info;
......@@ -188,10 +203,12 @@ gst_seek (URLContext *h,
gst_bytestream_seek (info->bs, pos, seek_type);
break;
case URL_WRONLY: {
GstEvent *event = gst_event_new_seek (seek_type, pos);
gst_pad_push (info->pad, GST_DATA (event));
}
case URL_WRONLY:
gst_pad_push (info->pad, GST_DATA (gst_event_new_seek (seek_type, pos)));
break;
default:
g_assert (0);
break;
}
......@@ -199,7 +216,7 @@ gst_seek (URLContext *h,
}
static int
gst_close (URLContext *h)
gst_ffmpegdata_close (URLContext *h)
{
GstProtocolInfo *info;
......@@ -227,10 +244,10 @@ gst_close (URLContext *h)
URLProtocol gstreamer_protocol = {
.name = "gstreamer",
.url_open = gst_open,
.url_read = gst_read,
.url_write = gst_write,
.url_seek = gst_seek,
.url_close = gst_close,
.url_open = gst_ffmpegdata_open,
.url_read = gst_ffmpegdata_read,
.url_write = gst_ffmpegdata_write,
.url_seek = gst_ffmpegdata_seek,
.url_close = gst_ffmpegdata_close,
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment