More ffmpeg wrapping going on here

Original commit message from CVS:
More ffmpeg wrapping going on here
This commit is contained in:
Wim Taymans 2002-11-25 21:37:26 +00:00
parent 4996d4c7d2
commit ba9ed9b9e4
7 changed files with 318 additions and 97 deletions

View file

@ -3,12 +3,13 @@ plugindir = $(libdir)/gst
plugin_LTLIBRARIES = libgstffmpeg.la
libgstffmpeg_la_SOURCES = gstffmpeg.c \
gstffmpegenc.c \
gstffmpegcodecmap.c \
gstffmpegdec.c \
gstffmpegdemux.c \
gstffmpegenc.c \
gstffmpegmux.c \
gstffmpegprotocol.c \
gstffmpegcodecmap.c
gstffmpegtypes.c
libgstffmpeg_la_CFLAGS = $(GST_CFLAGS) -I/opt/src/sourceforge/ffmpeg/ -I/opt/src/sourceforge/ffmpeg/libavcodec/
libgstffmpeg_la_LIBADD =

View file

@ -29,6 +29,9 @@
extern gboolean gst_ffmpegdemux_register (GstPlugin *plugin);
extern gboolean gst_ffmpegdec_register (GstPlugin *plugin);
extern gboolean gst_ffmpegenc_register (GstPlugin *plugin);
extern gboolean gst_ffmpegtypes_register (GstPlugin *plugin);
extern URLProtocol gstreamer_protocol;
static gboolean
plugin_init (GModule *module, GstPlugin *plugin)
@ -43,6 +46,9 @@ plugin_init (GModule *module, GstPlugin *plugin)
gst_ffmpegenc_register (plugin);
gst_ffmpegdec_register (plugin);
gst_ffmpegdemux_register (plugin);
gst_ffmpegtypes_register (plugin);
register_protocol (&gstreamer_protocol);
/* Now we can return the pointer to the newly created Plugin object. */
return TRUE;

View file

@ -21,9 +21,9 @@
#include <gst/gst.h>
GstCaps *
gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *context)
gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *context, int codec_id)
{
switch (context->codec_id) {
switch (codec_id) {
case CODEC_ID_NONE:
return GST_CAPS_NEW ("ffmpeg_none",
"unkown/unkown",
@ -72,13 +72,24 @@ gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *context)
NULL);
break;
case CODEC_ID_MPEG4:
return GST_CAPS_NEW ("ffmpeg_mpeg4",
"video/avi",
"format", GST_PROPS_STRING ("strf_vids"),
"fourcc", GST_PROPS_FOURCC (context->fourcc),
"width", GST_PROPS_INT (context->width),
"height", GST_PROPS_INT (context->height)
);
if (context) {
return GST_CAPS_NEW ("ffmpeg_mpeg4",
"video/avi",
"format", GST_PROPS_STRING ("strf_vids"),
"compression", GST_PROPS_FOURCC (context->fourcc),
"width", GST_PROPS_INT (context->width),
"height", GST_PROPS_INT (context->height)
);
}
else {
return GST_CAPS_NEW ("ffmpeg_mpeg4",
"video/avi",
"format", GST_PROPS_STRING ("strf_vids"),
"compression", GST_PROPS_FOURCC (GST_STR_FOURCC ("DIV3")),
"width", GST_PROPS_INT_RANGE (0, 4096),
"height", GST_PROPS_INT_RANGE (0, 4096)
);
}
break;
case CODEC_ID_RAWVIDEO:
return GST_CAPS_NEW ("ffmpeg_rawvideo",
@ -86,40 +97,81 @@ gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *context)
NULL);
break;
case CODEC_ID_MSMPEG4V1:
return GST_CAPS_NEW ("ffmpeg_msmpeg4v1",
"video/avi",
"format", GST_PROPS_STRING ("strf_vids"),
"fourcc", GST_PROPS_FOURCC (context->fourcc),
"width", GST_PROPS_INT (context->width),
"height", GST_PROPS_INT (context->height)
);
if (context) {
return GST_CAPS_NEW ("ffmpeg_msmpeg4v1",
"video/avi",
"format", GST_PROPS_STRING ("strf_vids"),
"compression", GST_PROPS_FOURCC (GST_STR_FOURCC ("MPG4")),
"width", GST_PROPS_INT (context->width),
"height", GST_PROPS_INT (context->height)
);
}
else {
return GST_CAPS_NEW ("ffmpeg_msmpeg4v1",
"video/avi",
"format", GST_PROPS_STRING ("strf_vids"),
"compression", GST_PROPS_FOURCC (GST_STR_FOURCC ("MPG4")),
"width", GST_PROPS_INT_RANGE (0, 4096),
"height", GST_PROPS_INT_RANGE (0, 4096)
);
}
break;
case CODEC_ID_MSMPEG4V2:
return GST_CAPS_NEW ("ffmpeg_msmpeg4v2",
"video/avi",
"format", GST_PROPS_STRING ("strf_vids"),
"fourcc", GST_PROPS_FOURCC (context->fourcc),
"width", GST_PROPS_INT (context->width),
"height", GST_PROPS_INT (context->height)
);
if (context) {
return GST_CAPS_NEW ("ffmpeg_msmpeg4v2",
"video/avi",
"format", GST_PROPS_STRING ("strf_vids"),
"compression", GST_PROPS_FOURCC (GST_STR_FOURCC ("MP42")),
"width", GST_PROPS_INT (context->width),
"height", GST_PROPS_INT (context->height)
);
}
else {
return GST_CAPS_NEW ("ffmpeg_msmpeg4v2",
"video/avi",
"format", GST_PROPS_STRING ("strf_vids"),
"compression", GST_PROPS_FOURCC (GST_STR_FOURCC ("MP42")),
"width", GST_PROPS_INT_RANGE (0, 4096),
"height", GST_PROPS_INT_RANGE (0, 4096)
);
}
break;
case CODEC_ID_MSMPEG4V3:
return GST_CAPS_NEW ("ffmpeg_msmpeg4v3",
"video/avi",
"format", GST_PROPS_STRING ("strf_vids"),
"fourcc", GST_PROPS_FOURCC (context->fourcc),
"width", GST_PROPS_INT (context->width),
"height", GST_PROPS_INT (context->height)
);
if (context) {
return GST_CAPS_NEW ("ffmpeg_msmpeg4v3",
"video/avi",
"format", GST_PROPS_STRING ("strf_vids"),
"compression", GST_PROPS_FOURCC (GST_STR_FOURCC ("DIV3")),
"width", GST_PROPS_INT (context->width),
"height", GST_PROPS_INT (context->height)
);
}
else {
return GST_CAPS_NEW ("ffmpeg_msmpeg4v3",
"video/avi",
"format", GST_PROPS_STRING ("strf_vids"),
"compression", GST_PROPS_FOURCC (GST_STR_FOURCC ("DIV3")),
"width", GST_PROPS_INT_RANGE (0, 4096),
"height", GST_PROPS_INT_RANGE (0, 4096)
);
}
break;
case CODEC_ID_WMV1:
return GST_CAPS_NEW ("ffmpeg_wmv1",
"video/avi",
"format", GST_PROPS_STRING ("strf_vids"),
"fourcc", GST_PROPS_FOURCC (GST_STR_FOURCC ("WMV1")),
"width", GST_PROPS_INT (context->width),
"height", GST_PROPS_INT (context->height)
);
if (context) {
return GST_CAPS_NEW ("ffmpeg_wmv1",
"video/avi",
"format", GST_PROPS_STRING ("strf_vids"),
"compression", GST_PROPS_FOURCC (GST_STR_FOURCC ("WMV1")),
"width", GST_PROPS_INT (context->width),
"height", GST_PROPS_INT (context->height)
);
}
else {
return GST_CAPS_NEW ("ffmpeg_wmv1",
"video/x-wmv1",
NULL
);
}
break;
case CODEC_ID_WMV2:
return GST_CAPS_NEW ("ffmpeg_wmv2",
@ -229,7 +281,7 @@ gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *context)
NULL);
break;
default:
g_warning ("no caps found for codec id %d\n", context->codec_id);
g_warning ("no caps found for codec id %d\n", codec_id);
break;
}

View file

@ -23,6 +23,9 @@
#include <gst/gst.h>
extern GstCaps* gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *ctx, int id);
typedef struct _GstFFMpegDec GstFFMpegDec;
struct _GstFFMpegDec {
@ -42,8 +45,14 @@ struct _GstFFMpegDecClass {
GstElementClass parent_class;
AVCodec *in_plugin;
GstPadTemplate *templ;
};
typedef struct {
AVCodec *in_plugin;
GstPadTemplate *templ;
} GstFFMpegClassParams;
#define GST_TYPE_FFMPEGDEC \
(gst_ffmpegdec_get_type())
#define GST_FFMPEGDEC(obj) \
@ -65,23 +74,6 @@ enum {
/* FILL ME */
};
/* This factory is much simpler, and defines the source pad. */
GST_PAD_TEMPLATE_FACTORY (gst_ffmpegdec_sink_factory,
"sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_CAPS_NEW (
"ffmpegdec_sink",
"video/avi",
"format", GST_PROPS_STRING ("strf_vids")
),
GST_CAPS_NEW (
"ffmpegdec_sink",
"video/mpeg",
NULL
)
)
/* This factory is much simpler, and defines the source pad. */
GST_PAD_TEMPLATE_FACTORY (gst_ffmpegdec_audio_src_factory,
"src",
@ -140,15 +132,19 @@ gst_ffmpegdec_class_init (GstFFMpegDecClass *klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstFFMpegClassParams *params;
gobject_class = (GObjectClass*)klass;
gstelement_class = (GstElementClass*)klass;
parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
klass->in_plugin = g_hash_table_lookup (global_plugins,
params = g_hash_table_lookup (global_plugins,
GINT_TO_POINTER (G_OBJECT_CLASS_TYPE (gobject_class)));
klass->in_plugin = params->in_plugin;
klass->templ = params->templ;
gobject_class->set_property = gst_ffmpegdec_set_property;
gobject_class->get_property = gst_ffmpegdec_get_property;
}
@ -168,7 +164,6 @@ gst_ffmpegdec_sinkconnect (GstPad *pad, GstCaps *caps)
gst_caps_get_int (caps, "height", &ffmpegdec->context->height);
ffmpegdec->context->pix_fmt = PIX_FMT_YUV420P;
ffmpegdec->context->frame_rate = 23 * FRAME_RATE_BASE;
ffmpegdec->context->bit_rate = 0;
/* FIXME bug in ffmpeg */
@ -191,8 +186,7 @@ gst_ffmpegdec_init(GstFFMpegDec *ffmpegdec)
ffmpegdec->context = g_malloc0 (sizeof (AVCodecContext));
ffmpegdec->sinkpad = gst_pad_new_from_template (
GST_PAD_TEMPLATE_GET (gst_ffmpegdec_sink_factory), "sink");
ffmpegdec->sinkpad = gst_pad_new_from_template (oclass->templ, "sink");
gst_pad_set_connect_function (ffmpegdec->sinkpad, gst_ffmpegdec_sinkconnect);
if (oclass->in_plugin->type == CODEC_TYPE_VIDEO) {
@ -367,6 +361,9 @@ gst_ffmpegdec_register (GstPlugin *plugin)
while (in_plugin) {
gchar *type_name;
gchar *codec_type;
GstPadTemplate *sinktempl;
GstCaps *sinkcaps;
GstFFMpegClassParams *params;
if (in_plugin->decode) {
codec_type = "dec";
@ -396,18 +393,23 @@ gst_ffmpegdec_register (GstPlugin *plugin)
details->author = g_strdup("The FFMPEG crew, GStreamer plugin by Wim Taymans <wim.taymans@chello.be>");
details->copyright = g_strdup("(c) 2001");
g_hash_table_insert (global_plugins,
GINT_TO_POINTER (type),
(gpointer) in_plugin);
/* register the plugin with gstreamer */
factory = gst_element_factory_new(type_name,type,details);
g_return_val_if_fail(factory != NULL, FALSE);
gst_element_factory_set_rank (factory, GST_ELEMENT_RANK_NONE);
gst_element_factory_add_pad_template (factory,
GST_PAD_TEMPLATE_GET (gst_ffmpegdec_sink_factory));
sinkcaps = gst_ffmpegcodec_codec_context_to_caps (NULL, in_plugin->id);
sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sinkcaps, NULL);
gst_element_factory_add_pad_template (factory, sinktempl);
params = g_new0 (GstFFMpegClassParams, 1);
params->in_plugin = in_plugin;
params->templ = sinktempl;
g_hash_table_insert (global_plugins,
GINT_TO_POINTER (type),
(gpointer) params);
if (in_plugin->type == CODEC_TYPE_VIDEO) {
gst_element_factory_add_pad_template (factory,

View file

@ -23,13 +23,11 @@
#include <gst/gst.h>
extern URLProtocol gstreamer_protocol;
extern GstCaps* gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *context, int codec_id);
typedef enum {
STATE_OPEN,
STATE_STREAM_INFO,
STATE_DEMUX,
STATE_END,
} DemuxState;
typedef struct _GstFFMpegDemux GstFFMpegDemux;
@ -164,9 +162,6 @@ gst_ffmpegdemux_loop (GstElement *element)
0,
NULL);
/* this doesn't work */
av_set_pts_info (ffmpegdemux->context, 33, 1, 100000);
ffmpegdemux->state = STATE_DEMUX;
break;
}
@ -180,44 +175,53 @@ gst_ffmpegdemux_loop (GstElement *element)
res = av_read_packet(ct, &pkt);
if (res < 0) {
gint i;
if (url_feof (&ct->pb)) {
gint i;
for (i = 0; i < ct->nb_streams; i++) {
GstPad *pad;
for (i = 0; i < ct->nb_streams; i++) {
GstPad *pad;
pad = ffmpegdemux->srcpads[i];
pad = ffmpegdemux->srcpads[i];
if (GST_PAD_IS_USABLE (pad)) {
gst_pad_push (pad, GST_BUFFER (gst_event_new (GST_EVENT_EOS)));
if (GST_PAD_IS_USABLE (pad)) {
gst_pad_push (pad, GST_BUFFER (gst_event_new (GST_EVENT_EOS)));
}
}
gst_element_set_eos (element);
}
gst_element_set_eos (element);
return;
}
st = ct->streams[pkt.stream_index];
if (st->codec_info_state == 0) {
gchar *padname = NULL;
GstPadTemplate *templ = NULL;
gchar *templname = NULL;
st->codec_info_state = 1;
if (st->codec.codec_type == CODEC_TYPE_VIDEO) {
padname = g_strdup_printf ("video_%02d", pkt.stream_index);
templ = GST_PAD_TEMPLATE_GET (gst_ffmpegdemux_video_src_factory);
templname = "video_%02d";
}
else if (st->codec.codec_type == CODEC_TYPE_AUDIO) {
padname = g_strdup_printf ("audio_%02d", pkt.stream_index);
templ = GST_PAD_TEMPLATE_GET (gst_ffmpegdemux_audio_src_factory);
templname = "audio_%02d";
}
if (padname != NULL) {
if (templname != NULL) {
gchar *padname;
GstCaps *caps;
GstPadTemplate *templ;
caps = gst_ffmpegcodec_codec_context_to_caps (&st->codec, st->codec.codec_id);
templ = gst_pad_template_new (templname,
GST_PAD_SRC,
GST_PAD_SOMETIMES,
caps, NULL);
padname = g_strdup_printf (templname, pkt.stream_index);
pad = gst_pad_new_from_template (templ, padname);
ffmpegdemux->srcpads[pkt.stream_index] = pad;
gst_element_add_pad (GST_ELEMENT (ffmpegdemux), pad);
g_print ("new pad\n");
}
else {
g_warning ("unkown pad type %d", st->codec.codec_type);
@ -234,8 +238,9 @@ gst_ffmpegdemux_loop (GstElement *element)
outbuf = gst_buffer_new ();
GST_BUFFER_DATA (outbuf) = pkt.data;
GST_BUFFER_SIZE (outbuf) = pkt.size;
if (pkt.pts != 0) {
GST_BUFFER_TIMESTAMP (outbuf) = pkt.pts * GST_SECOND / 90000LL;
if (pkt.pts != AV_NOPTS_VALUE && ct->pts_den) {
GST_BUFFER_TIMESTAMP (outbuf) = pkt.pts * GST_SECOND * ct->pts_num / ct->pts_den;
}
else {
GST_BUFFER_TIMESTAMP (outbuf) = -1;
@ -364,7 +369,5 @@ next:
in_plugin = in_plugin->next;
}
register_protocol (&gstreamer_protocol);
return TRUE;
}

View file

@ -28,10 +28,11 @@ typedef struct _GstProtocolInfo GstProtocolInfo;
struct _GstProtocolInfo
{
GstPad *pad;
GstPad *pad;
int flags;
int flags;
GstByteStream *bs;
gboolean eos;
};
static int
@ -54,6 +55,7 @@ gst_open (URLContext *h, const char *filename, int flags)
}
info->bs = gst_bytestream_new (pad);
info->eos = FALSE;
h->priv_data = (void *) info;
@ -71,10 +73,36 @@ gst_read (URLContext *h, unsigned char *buf, int size)
info = (GstProtocolInfo *) h->priv_data;
bs = info->bs;
total = gst_bytestream_peek_bytes (bs, &data, size);
memcpy (buf, data, total);
if (info->eos)
return 0;
gst_bytestream_flush_fast (bs, total);
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;
}
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);
}
memcpy (buf, data, total);
gst_bytestream_flush (bs, total);
return total;
}

129
ext/ffmpeg/gstffmpegtypes.c Normal file
View file

@ -0,0 +1,129 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* 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.
*/
#include <assert.h>
#include <string.h>
#include <libav/avformat.h>
#include <gst/gst.h>
static GHashTable *global_types = NULL;
extern GstCaps* gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *ctx, int id);
static GstCaps*
gst_ffmpegtypes_typefind (GstBuffer *buffer, gpointer priv)
{
AVInputFormat *in_plugin;
AVInputFormat *highest = NULL;
gint max = 0;
gint res = 0;
in_plugin = first_iformat;
while (in_plugin) {
if (in_plugin->read_probe) {
AVProbeData probe_data;
probe_data.filename = "";
probe_data.buf = GST_BUFFER_DATA (buffer);
probe_data.buf_size = GST_BUFFER_SIZE (buffer);
res = in_plugin->read_probe (&probe_data);
if (res > max) {
max = res;
highest = in_plugin;
}
}
in_plugin = in_plugin->next;
}
if (highest) {
GstCaps *caps;
caps = g_hash_table_lookup (global_types, highest->name);
return caps;
}
return NULL;
}
#define ADD_TYPE(key,caps) g_hash_table_insert (global_types, (key), (caps))
static void
register_standard_formats (void)
{
global_types = g_hash_table_new (g_str_hash, g_str_equal);
ADD_TYPE ("avi", GST_CAPS_NEW ("ffmpeg_type_avi", "video/avi", NULL));
ADD_TYPE ("mpeg", GST_CAPS_NEW ("ffmpeg_type_mpeg", "video/mpeg",
"systemstream", GST_PROPS_BOOLEAN (TRUE)));
ADD_TYPE ("mpegts", GST_CAPS_NEW ("ffmpeg_type_mpegts", "video/x-mpegts",
"systemstream", GST_PROPS_BOOLEAN (TRUE)));
ADD_TYPE ("rm", GST_CAPS_NEW ("ffmpeg_type_rm", "audio/x-pn-realaudio", NULL));
ADD_TYPE ("asf", GST_CAPS_NEW ("ffmpeg_type_asf", "video/x-ms-asf", NULL));
ADD_TYPE ("avi", GST_CAPS_NEW ("ffmpeg_type_avi", "video/avi",
"format", GST_PROPS_STRING ("AVI")));
ADD_TYPE ("mov", GST_CAPS_NEW ("ffmpeg_type_mov", "video/quicktime", NULL));
ADD_TYPE ("swf", GST_CAPS_NEW ("ffmpeg_type_swf", "application/x-shockwave-flash", NULL));
ADD_TYPE ("au", GST_CAPS_NEW ("ffmpeg_type_au", "audio/basic", NULL));
ADD_TYPE ("mov", GST_CAPS_NEW ("ffmpeg_type_mov", "video/quicktime", NULL));
}
gboolean
gst_ffmpegtypes_register (GstPlugin *plugin)
{
AVInputFormat *in_plugin;
GstTypeFactory *factory;
GstTypeDefinition *definition;
in_plugin = first_iformat;
while (in_plugin) {
gchar *type_name;
gchar *p;
if (!in_plugin->read_probe)
goto next;
/* construct the type */
type_name = g_strdup_printf("fftype_%s", in_plugin->name);
p = type_name;
while (*p) {
if (*p == '.') *p = '_';
p++;
}
definition = g_new0 (GstTypeDefinition, 1);
definition->name = type_name;
definition->mime = type_name;
definition->exts = g_strdup (in_plugin->extensions);
definition->typefindfunc = gst_ffmpegtypes_typefind;
factory = gst_type_factory_new (definition);
/* The very last thing is to register the elementfactory with the plugin. */
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
next:
in_plugin = in_plugin->next;
}
register_standard_formats ();
return TRUE;
}