mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
avprotocol: Port from the URL protocol handler to saner public API
This commit is contained in:
parent
4c46f11d5f
commit
338b147374
5 changed files with 124 additions and 144 deletions
|
@ -30,7 +30,6 @@
|
||||||
|
|
||||||
#include <libavcodec/avcodec.h>
|
#include <libavcodec/avcodec.h>
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
#include <libavformat/url.h>
|
|
||||||
|
|
||||||
#include "gstav.h"
|
#include "gstav.h"
|
||||||
#include "gstavutils.h"
|
#include "gstavutils.h"
|
||||||
|
@ -150,9 +149,6 @@ plugin_init (GstPlugin * plugin)
|
||||||
gst_ffmpegaudioresample_register (plugin);
|
gst_ffmpegaudioresample_register (plugin);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ffurl_register_protocol (&gstreamer_protocol, sizeof (URLProtocol));
|
|
||||||
ffurl_register_protocol (&gstpipe_protocol, sizeof (URLProtocol));
|
|
||||||
|
|
||||||
/* Now we can return the pointer to the newly created Plugin object. */
|
/* Now we can return the pointer to the newly created Plugin object. */
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
|
|
||||||
#include <libavcodec/avcodec.h>
|
#include <libavcodec/avcodec.h>
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
#include <libavformat/url.h>
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
@ -56,10 +55,13 @@ int gst_ffmpeg_avcodec_open (AVCodecContext *avctx, AVCodec *codec);
|
||||||
int gst_ffmpeg_avcodec_close (AVCodecContext *avctx);
|
int gst_ffmpeg_avcodec_close (AVCodecContext *avctx);
|
||||||
int gst_ffmpeg_av_find_stream_info(AVFormatContext *ic);
|
int gst_ffmpeg_av_find_stream_info(AVFormatContext *ic);
|
||||||
|
|
||||||
G_END_DECLS
|
int gst_ffmpegdata_open (GstPad * pad, int flags, AVIOContext ** context);
|
||||||
|
int gst_ffmpegdata_close (AVIOContext * h);
|
||||||
|
typedef struct _GstFFMpegPipe GstFFMpegPipe;
|
||||||
|
int gst_ffmpeg_pipe_open (GstFFMpegPipe *ffpipe, int flags, AVIOContext ** context);
|
||||||
|
int gst_ffmpeg_pipe_close (AVIOContext * h);
|
||||||
|
|
||||||
extern URLProtocol gstreamer_protocol;
|
G_END_DECLS
|
||||||
extern URLProtocol gstpipe_protocol;
|
|
||||||
|
|
||||||
/* use GST_FFMPEG URL_STREAMHEADER with URL_WRONLY if the first
|
/* use GST_FFMPEG URL_STREAMHEADER with URL_WRONLY if the first
|
||||||
* buffer should be used as streamheader property on the pad's caps. */
|
* buffer should be used as streamheader property on the pad's caps. */
|
||||||
|
|
|
@ -332,8 +332,11 @@ gst_ffmpegdemux_close (GstFFMpegDemux * demux)
|
||||||
demux->audiopads = 0;
|
demux->audiopads = 0;
|
||||||
|
|
||||||
/* close demuxer context from ffmpeg */
|
/* close demuxer context from ffmpeg */
|
||||||
av_close_input_file (demux->context);
|
if (demux->seekable)
|
||||||
demux->context = NULL;
|
gst_ffmpegdata_close (demux->context->pb);
|
||||||
|
else
|
||||||
|
gst_ffmpeg_pipe_close (demux->context->pb);
|
||||||
|
avformat_close_input (&demux->context);
|
||||||
|
|
||||||
GST_OBJECT_LOCK (demux);
|
GST_OBJECT_LOCK (demux);
|
||||||
demux->opened = FALSE;
|
demux->opened = FALSE;
|
||||||
|
@ -1115,9 +1118,9 @@ gst_ffmpegdemux_read_tags (GstFFMpegDemux * demux)
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_ffmpegdemux_open (GstFFMpegDemux * demux)
|
gst_ffmpegdemux_open (GstFFMpegDemux * demux)
|
||||||
{
|
{
|
||||||
|
AVIOContext *iocontext = NULL;
|
||||||
GstFFMpegDemuxClass *oclass =
|
GstFFMpegDemuxClass *oclass =
|
||||||
(GstFFMpegDemuxClass *) G_OBJECT_GET_CLASS (demux);
|
(GstFFMpegDemuxClass *) G_OBJECT_GET_CLASS (demux);
|
||||||
gchar *location;
|
|
||||||
gint res, n_streams, i;
|
gint res, n_streams, i;
|
||||||
#if 0
|
#if 0
|
||||||
/* Re-enable once converted to new AVMetaData API
|
/* Re-enable once converted to new AVMetaData API
|
||||||
|
@ -1133,15 +1136,14 @@ gst_ffmpegdemux_open (GstFFMpegDemux * demux)
|
||||||
|
|
||||||
/* open via our input protocol hack */
|
/* open via our input protocol hack */
|
||||||
if (demux->seekable)
|
if (demux->seekable)
|
||||||
location = g_strdup_printf ("gstreamer://%p", demux->sinkpad);
|
res = gst_ffmpegdata_open (demux->sinkpad, AVIO_FLAG_READ, &iocontext);
|
||||||
else
|
else
|
||||||
location = g_strdup_printf ("gstpipe://%p", &demux->ffpipe);
|
res = gst_ffmpeg_pipe_open (&demux->ffpipe, AVIO_FLAG_READ, &iocontext);
|
||||||
GST_DEBUG_OBJECT (demux, "about to call av_open_input_file %s", location);
|
|
||||||
|
|
||||||
res = avformat_open_input (&demux->context, location,
|
demux->context = avformat_alloc_context ();
|
||||||
oclass->in_plugin, NULL);
|
demux->context->pb = iocontext;
|
||||||
|
res = avformat_open_input (&demux->context, NULL, oclass->in_plugin, NULL);
|
||||||
|
|
||||||
g_free (location);
|
|
||||||
GST_DEBUG_OBJECT (demux, "av_open_input returned %d", res);
|
GST_DEBUG_OBJECT (demux, "av_open_input returned %d", res);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
goto open_failed;
|
goto open_failed;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/base/gstcollectpads.h>
|
#include <gst/base/gstcollectpads.h>
|
||||||
|
|
||||||
|
@ -58,6 +59,7 @@ struct _GstFFMpegMux
|
||||||
/* event_function is the collectpads default eventfunction */
|
/* event_function is the collectpads default eventfunction */
|
||||||
GstPadEventFunction event_function;
|
GstPadEventFunction event_function;
|
||||||
int max_delay;
|
int max_delay;
|
||||||
|
int preload;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _GstFFMpegMuxClass GstFFMpegMuxClass;
|
typedef struct _GstFFMpegMuxClass GstFFMpegMuxClass;
|
||||||
|
@ -294,7 +296,7 @@ gst_ffmpegmux_class_init (GstFFMpegMuxClass * klass)
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class, PROP_PRELOAD,
|
g_object_class_install_property (gobject_class, PROP_PRELOAD,
|
||||||
g_param_spec_int ("preload", "preload",
|
g_param_spec_int ("preload", "preload",
|
||||||
"Set the initial demux-decode delay (in microseconds) (DEPRECATED)",
|
"Set the initial demux-decode delay (in microseconds)",
|
||||||
0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class, PROP_MAXDELAY,
|
g_object_class_install_property (gobject_class, PROP_MAXDELAY,
|
||||||
|
@ -325,9 +327,6 @@ gst_ffmpegmux_init (GstFFMpegMux * ffmpegmux, GstFFMpegMuxClass * g_class)
|
||||||
ffmpegmux->context = g_new0 (AVFormatContext, 1);
|
ffmpegmux->context = g_new0 (AVFormatContext, 1);
|
||||||
ffmpegmux->context->oformat = oclass->in_plugin;
|
ffmpegmux->context->oformat = oclass->in_plugin;
|
||||||
ffmpegmux->context->nb_streams = 0;
|
ffmpegmux->context->nb_streams = 0;
|
||||||
g_snprintf (ffmpegmux->context->filename,
|
|
||||||
sizeof (ffmpegmux->context->filename),
|
|
||||||
"gstreamer://%p", ffmpegmux->srcpad);
|
|
||||||
ffmpegmux->opened = FALSE;
|
ffmpegmux->opened = FALSE;
|
||||||
|
|
||||||
ffmpegmux->videopads = 0;
|
ffmpegmux->videopads = 0;
|
||||||
|
@ -345,6 +344,7 @@ gst_ffmpegmux_set_property (GObject * object, guint prop_id,
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_PRELOAD:
|
case PROP_PRELOAD:
|
||||||
|
src->preload = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
case PROP_MAXDELAY:
|
case PROP_MAXDELAY:
|
||||||
src->max_delay = g_value_get_int (value);
|
src->max_delay = g_value_get_int (value);
|
||||||
|
@ -365,6 +365,7 @@ gst_ffmpegmux_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_PRELOAD:
|
case PROP_PRELOAD:
|
||||||
|
g_value_set_int (value, src->preload);
|
||||||
break;
|
break;
|
||||||
case PROP_MAXDELAY:
|
case PROP_MAXDELAY:
|
||||||
g_value_set_int (value, src->max_delay);
|
g_value_set_int (value, src->max_delay);
|
||||||
|
@ -470,6 +471,7 @@ gst_ffmpegmux_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
collect_pad = (GstFFMpegMuxPad *) gst_pad_get_element_private (pad);
|
collect_pad = (GstFFMpegMuxPad *) gst_pad_get_element_private (pad);
|
||||||
|
|
||||||
st = ffmpegmux->context->streams[collect_pad->padnum];
|
st = ffmpegmux->context->streams[collect_pad->padnum];
|
||||||
|
av_opt_set_int (&ffmpegmux->context, "preload", ffmpegmux->preload, 0);
|
||||||
ffmpegmux->context->max_delay = ffmpegmux->max_delay;
|
ffmpegmux->context->max_delay = ffmpegmux->max_delay;
|
||||||
|
|
||||||
/* for the format-specific guesses, we'll go to
|
/* for the format-specific guesses, we'll go to
|
||||||
|
@ -637,8 +639,8 @@ gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data)
|
||||||
open_flags |= GST_FFMPEG_URL_STREAMHEADER;
|
open_flags |= GST_FFMPEG_URL_STREAMHEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avio_open (&ffmpegmux->context->pb,
|
if (gst_ffmpegdata_open (ffmpegmux->srcpad, open_flags,
|
||||||
ffmpegmux->context->filename, open_flags) < 0) {
|
&ffmpegmux->context->pb) < 0) {
|
||||||
GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, TOO_LAZY, (NULL),
|
GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, TOO_LAZY, (NULL),
|
||||||
("Failed to open stream context in avmux"));
|
("Failed to open stream context in avmux"));
|
||||||
return GST_FLOW_ERROR;
|
return GST_FLOW_ERROR;
|
||||||
|
@ -763,7 +765,7 @@ gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data)
|
||||||
av_write_trailer (ffmpegmux->context);
|
av_write_trailer (ffmpegmux->context);
|
||||||
ffmpegmux->opened = FALSE;
|
ffmpegmux->opened = FALSE;
|
||||||
avio_flush (ffmpegmux->context->pb);
|
avio_flush (ffmpegmux->context->pb);
|
||||||
avio_close (ffmpegmux->context->pb);
|
gst_ffmpegdata_close (ffmpegmux->context->pb);
|
||||||
gst_pad_push_event (ffmpegmux->srcpad, gst_event_new_eos ());
|
gst_pad_push_event (ffmpegmux->srcpad, gst_event_new_eos ());
|
||||||
return GST_FLOW_EOS;
|
return GST_FLOW_EOS;
|
||||||
}
|
}
|
||||||
|
@ -801,7 +803,7 @@ gst_ffmpegmux_change_state (GstElement * element, GstStateChange transition)
|
||||||
gst_tag_setter_reset_tags (GST_TAG_SETTER (ffmpegmux));
|
gst_tag_setter_reset_tags (GST_TAG_SETTER (ffmpegmux));
|
||||||
if (ffmpegmux->opened) {
|
if (ffmpegmux->opened) {
|
||||||
ffmpegmux->opened = FALSE;
|
ffmpegmux->opened = FALSE;
|
||||||
avio_close (ffmpegmux->context->pb);
|
gst_ffmpegdata_close (ffmpegmux->context->pb);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
#include <libavformat/url.h>
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
@ -44,61 +43,14 @@ struct _GstProtocolInfo
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
gst_ffmpegdata_open (URLContext * h, const char *filename, int flags)
|
gst_ffmpegdata_peek (void *priv_data, unsigned char *buf, int size)
|
||||||
{
|
|
||||||
GstProtocolInfo *info;
|
|
||||||
GstPad *pad;
|
|
||||||
|
|
||||||
GST_LOG ("Opening %s", filename);
|
|
||||||
|
|
||||||
info = g_new0 (GstProtocolInfo, 1);
|
|
||||||
|
|
||||||
info->set_streamheader = flags & GST_FFMPEG_URL_STREAMHEADER;
|
|
||||||
flags &= ~GST_FFMPEG_URL_STREAMHEADER;
|
|
||||||
h->flags &= ~GST_FFMPEG_URL_STREAMHEADER;
|
|
||||||
|
|
||||||
/* we don't support R/W together */
|
|
||||||
if ((flags & AVIO_FLAG_WRITE) && (flags & AVIO_FLAG_READ)) {
|
|
||||||
GST_WARNING ("Only read-only or write-only are supported");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sscanf (&filename[12], "%p", &pad) != 1) {
|
|
||||||
GST_WARNING ("could not decode pad from %s", filename);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make sure we're a pad and that we're of the right type */
|
|
||||||
g_return_val_if_fail (GST_IS_PAD (pad), -EINVAL);
|
|
||||||
|
|
||||||
if ((flags & AVIO_FLAG_READ)) {
|
|
||||||
g_return_val_if_fail (GST_PAD_IS_SINK (pad), -EINVAL);
|
|
||||||
}
|
|
||||||
if ((flags & AVIO_FLAG_WRITE)) {
|
|
||||||
g_return_val_if_fail (GST_PAD_IS_SRC (pad), -EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
info->eos = FALSE;
|
|
||||||
info->pad = pad;
|
|
||||||
info->offset = 0;
|
|
||||||
|
|
||||||
h->priv_data = (void *) info;
|
|
||||||
h->is_streamed = FALSE;
|
|
||||||
h->max_packet_size = 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
gst_ffmpegdata_peek (URLContext * h, unsigned char *buf, int size)
|
|
||||||
{
|
{
|
||||||
GstProtocolInfo *info;
|
GstProtocolInfo *info;
|
||||||
GstBuffer *inbuf = NULL;
|
GstBuffer *inbuf = NULL;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
int total = 0;
|
int total = 0;
|
||||||
|
|
||||||
g_return_val_if_fail ((h->flags & AVIO_FLAG_READ), AVERROR (EIO));
|
info = (GstProtocolInfo *) priv_data;
|
||||||
info = (GstProtocolInfo *) h->priv_data;
|
|
||||||
|
|
||||||
GST_DEBUG ("Pulling %d bytes at position %" G_GUINT64_FORMAT, size,
|
GST_DEBUG ("Pulling %d bytes at position %" G_GUINT64_FORMAT, size,
|
||||||
info->offset);
|
info->offset);
|
||||||
|
@ -130,17 +82,17 @@ gst_ffmpegdata_peek (URLContext * h, unsigned char *buf, int size)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
gst_ffmpegdata_read (URLContext * h, unsigned char *buf, int size)
|
gst_ffmpegdata_read (void *priv_data, unsigned char *buf, int size)
|
||||||
{
|
{
|
||||||
gint res;
|
gint res;
|
||||||
GstProtocolInfo *info;
|
GstProtocolInfo *info;
|
||||||
|
|
||||||
info = (GstProtocolInfo *) h->priv_data;
|
info = (GstProtocolInfo *) priv_data;
|
||||||
|
|
||||||
GST_DEBUG ("Reading %d bytes of data at position %" G_GUINT64_FORMAT, size,
|
GST_DEBUG ("Reading %d bytes of data at position %" G_GUINT64_FORMAT, size,
|
||||||
info->offset);
|
info->offset);
|
||||||
|
|
||||||
res = gst_ffmpegdata_peek (h, buf, size);
|
res = gst_ffmpegdata_peek (priv_data, buf, size);
|
||||||
if (res >= 0)
|
if (res >= 0)
|
||||||
info->offset += res;
|
info->offset += res;
|
||||||
|
|
||||||
|
@ -150,15 +102,13 @@ gst_ffmpegdata_read (URLContext * h, unsigned char *buf, int size)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
gst_ffmpegdata_write (URLContext * h, const unsigned char *buf, int size)
|
gst_ffmpegdata_write (void *priv_data, uint8_t * buf, int size)
|
||||||
{
|
{
|
||||||
GstProtocolInfo *info;
|
GstProtocolInfo *info;
|
||||||
GstBuffer *outbuf;
|
GstBuffer *outbuf;
|
||||||
|
|
||||||
GST_DEBUG ("Writing %d bytes", size);
|
GST_DEBUG ("Writing %d bytes", size);
|
||||||
info = (GstProtocolInfo *) h->priv_data;
|
info = (GstProtocolInfo *) priv_data;
|
||||||
|
|
||||||
g_return_val_if_fail ((h->flags & AVIO_FLAG_WRITE), -EIO);
|
|
||||||
|
|
||||||
/* create buffer and push data further */
|
/* create buffer and push data further */
|
||||||
outbuf = gst_buffer_new_and_alloc (size);
|
outbuf = gst_buffer_new_and_alloc (size);
|
||||||
|
@ -173,7 +123,7 @@ gst_ffmpegdata_write (URLContext * h, const unsigned char *buf, int size)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t
|
static int64_t
|
||||||
gst_ffmpegdata_seek (URLContext * h, int64_t pos, int whence)
|
gst_ffmpegdata_seek (void *priv_data, int64_t pos, int whence)
|
||||||
{
|
{
|
||||||
GstProtocolInfo *info;
|
GstProtocolInfo *info;
|
||||||
guint64 newpos = 0, oldpos;
|
guint64 newpos = 0, oldpos;
|
||||||
|
@ -181,10 +131,11 @@ gst_ffmpegdata_seek (URLContext * h, int64_t pos, int whence)
|
||||||
GST_DEBUG ("Seeking to %" G_GINT64_FORMAT ", whence=%d",
|
GST_DEBUG ("Seeking to %" G_GINT64_FORMAT ", whence=%d",
|
||||||
(gint64) pos, whence);
|
(gint64) pos, whence);
|
||||||
|
|
||||||
info = (GstProtocolInfo *) h->priv_data;
|
info = (GstProtocolInfo *) priv_data;
|
||||||
|
|
||||||
/* TODO : if we are push-based, we need to return sensible info */
|
/* TODO : if we are push-based, we need to return sensible info */
|
||||||
if ((h->flags & AVIO_FLAG_READ)) {
|
|
||||||
|
if (GST_PAD_IS_SINK (info->pad)) {
|
||||||
/* sinkpad */
|
/* sinkpad */
|
||||||
switch (whence) {
|
switch (whence) {
|
||||||
case SEEK_SET:
|
case SEEK_SET:
|
||||||
|
@ -214,9 +165,7 @@ gst_ffmpegdata_seek (URLContext * h, int64_t pos, int whence)
|
||||||
/* FIXME : implement case for push-based behaviour */
|
/* FIXME : implement case for push-based behaviour */
|
||||||
if (whence != AVSEEK_SIZE)
|
if (whence != AVSEEK_SIZE)
|
||||||
info->offset = newpos;
|
info->offset = newpos;
|
||||||
}
|
} else if (GST_PAD_IS_SRC (info->pad)) {
|
||||||
|
|
||||||
if ((h->flags & AVIO_FLAG_WRITE)) {
|
|
||||||
GstSegment segment;
|
GstSegment segment;
|
||||||
|
|
||||||
oldpos = info->offset;
|
oldpos = info->offset;
|
||||||
|
@ -242,6 +191,8 @@ gst_ffmpegdata_seek (URLContext * h, int64_t pos, int whence)
|
||||||
segment.time = newpos;
|
segment.time = newpos;
|
||||||
gst_pad_push_event (info->pad, gst_event_new_segment (&segment));
|
gst_pad_push_event (info->pad, gst_event_new_segment (&segment));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG ("Now at offset %" G_GUINT64_FORMAT " (returning %" G_GUINT64_FORMAT
|
GST_DEBUG ("Now at offset %" G_GUINT64_FORMAT " (returning %" G_GUINT64_FORMAT
|
||||||
|
@ -249,79 +200,90 @@ gst_ffmpegdata_seek (URLContext * h, int64_t pos, int whence)
|
||||||
return newpos;
|
return newpos;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
int
|
||||||
gst_ffmpegdata_close (URLContext * h)
|
gst_ffmpegdata_close (AVIOContext * h)
|
||||||
{
|
{
|
||||||
GstProtocolInfo *info;
|
GstProtocolInfo *info;
|
||||||
|
|
||||||
info = (GstProtocolInfo *) h->priv_data;
|
info = (GstProtocolInfo *) h->opaque;
|
||||||
if (info == NULL)
|
if (info == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
GST_LOG ("Closing file");
|
GST_LOG ("Closing file");
|
||||||
|
|
||||||
if ((h->flags & AVIO_FLAG_WRITE)) {
|
if (GST_PAD_IS_SRC (info->pad)) {
|
||||||
/* send EOS - that closes down the stream */
|
/* send EOS - that closes down the stream */
|
||||||
gst_pad_push_event (info->pad, gst_event_new_eos ());
|
gst_pad_push_event (info->pad, gst_event_new_eos ());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clean up data */
|
/* clean up data */
|
||||||
g_free (info);
|
g_free (info);
|
||||||
h->priv_data = NULL;
|
h->opaque = NULL;
|
||||||
|
|
||||||
|
av_freep (&h->buffer);
|
||||||
|
av_free (h);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gst_ffmpegdata_open (GstPad * pad, int flags, AVIOContext ** context)
|
||||||
|
{
|
||||||
|
GstProtocolInfo *info;
|
||||||
|
static const int buffer_size = 4096;
|
||||||
|
unsigned char *buffer = NULL;
|
||||||
|
|
||||||
URLProtocol gstreamer_protocol = {
|
info = g_new0 (GstProtocolInfo, 1);
|
||||||
/*.name = */ "gstreamer",
|
|
||||||
/*.url_open = */ gst_ffmpegdata_open,
|
|
||||||
/*.url_open2 = */ NULL,
|
|
||||||
/*.url_read = */ gst_ffmpegdata_read,
|
|
||||||
/*.url_write = */ gst_ffmpegdata_write,
|
|
||||||
/*.url_seek = */ gst_ffmpegdata_seek,
|
|
||||||
/*.url_close = */ gst_ffmpegdata_close,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
info->set_streamheader = flags & GST_FFMPEG_URL_STREAMHEADER;
|
||||||
|
flags &= ~GST_FFMPEG_URL_STREAMHEADER;
|
||||||
|
|
||||||
|
/* we don't support R/W together */
|
||||||
|
if ((flags & AVIO_FLAG_WRITE) && (flags & AVIO_FLAG_READ)) {
|
||||||
|
GST_WARNING ("Only read-only or write-only are supported");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure we're a pad and that we're of the right type */
|
||||||
|
g_return_val_if_fail (GST_IS_PAD (pad), -EINVAL);
|
||||||
|
|
||||||
|
if ((flags & AVIO_FLAG_READ))
|
||||||
|
g_return_val_if_fail (GST_PAD_IS_SINK (pad), -EINVAL);
|
||||||
|
if ((flags & AVIO_FLAG_WRITE))
|
||||||
|
g_return_val_if_fail (GST_PAD_IS_SRC (pad), -EINVAL);
|
||||||
|
|
||||||
|
info->eos = FALSE;
|
||||||
|
info->pad = pad;
|
||||||
|
info->offset = 0;
|
||||||
|
|
||||||
|
buffer = av_malloc (buffer_size);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
GST_WARNING ("Failed to allocate buffer");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
*context =
|
||||||
|
avio_alloc_context (buffer, buffer_size, flags, (void *) info,
|
||||||
|
gst_ffmpegdata_read, gst_ffmpegdata_write, gst_ffmpegdata_seek);
|
||||||
|
(*context)->seekable = AVIO_SEEKABLE_NORMAL;
|
||||||
|
if (!(flags & AVIO_FLAG_WRITE)) {
|
||||||
|
(*context)->buf_ptr = (*context)->buf_end;
|
||||||
|
(*context)->write_flag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* specialized protocol for cross-thread pushing,
|
/* specialized protocol for cross-thread pushing,
|
||||||
* based on ffmpeg's pipe protocol */
|
* based on ffmpeg's pipe protocol */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
gst_ffmpeg_pipe_open (URLContext * h, const char *filename, int flags)
|
gst_ffmpeg_pipe_read (void *priv_data, uint8_t * buf, int size)
|
||||||
{
|
|
||||||
GstFFMpegPipe *ffpipe;
|
|
||||||
|
|
||||||
GST_LOG ("Opening %s", filename);
|
|
||||||
|
|
||||||
/* we don't support W together */
|
|
||||||
if ((flags & AVIO_FLAG_WRITE)) {
|
|
||||||
GST_WARNING ("Only read-only is supported");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sscanf (&filename[10], "%p", &ffpipe) != 1) {
|
|
||||||
GST_WARNING ("could not decode pipe info from %s", filename);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* sanity check */
|
|
||||||
g_return_val_if_fail (GST_IS_ADAPTER (ffpipe->adapter), -EINVAL);
|
|
||||||
|
|
||||||
h->priv_data = (void *) ffpipe;
|
|
||||||
h->is_streamed = TRUE;
|
|
||||||
h->max_packet_size = 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
gst_ffmpeg_pipe_read (URLContext * h, unsigned char *buf, int size)
|
|
||||||
{
|
{
|
||||||
GstFFMpegPipe *ffpipe;
|
GstFFMpegPipe *ffpipe;
|
||||||
guint available;
|
guint available;
|
||||||
|
|
||||||
ffpipe = (GstFFMpegPipe *) h->priv_data;
|
ffpipe = (GstFFMpegPipe *) priv_data;
|
||||||
|
|
||||||
GST_LOG ("requested size %d", size);
|
GST_LOG ("requested size %d", size);
|
||||||
|
|
||||||
|
@ -351,22 +313,38 @@ gst_ffmpeg_pipe_read (URLContext * h, unsigned char *buf, int size)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
int
|
||||||
gst_ffmpeg_pipe_close (URLContext * h)
|
gst_ffmpeg_pipe_close (AVIOContext * h)
|
||||||
{
|
{
|
||||||
GST_LOG ("Closing pipe");
|
GST_LOG ("Closing pipe");
|
||||||
|
|
||||||
h->priv_data = NULL;
|
h->opaque = NULL;
|
||||||
|
av_freep (&h->buffer);
|
||||||
|
av_free (h);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
URLProtocol gstpipe_protocol = {
|
int
|
||||||
"gstpipe",
|
gst_ffmpeg_pipe_open (GstFFMpegPipe * ffpipe, int flags, AVIOContext ** context)
|
||||||
gst_ffmpeg_pipe_open,
|
{
|
||||||
NULL,
|
static const int buffer_size = 4096;
|
||||||
gst_ffmpeg_pipe_read,
|
unsigned char *buffer = NULL;
|
||||||
NULL,
|
|
||||||
NULL,
|
/* sanity check */
|
||||||
gst_ffmpeg_pipe_close,
|
g_return_val_if_fail (GST_IS_ADAPTER (ffpipe->adapter), -EINVAL);
|
||||||
};
|
|
||||||
|
buffer = av_malloc (buffer_size);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
GST_WARNING ("Failed to allocate buffer");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
*context =
|
||||||
|
avio_alloc_context (buffer, buffer_size, 0, (void *) ffpipe,
|
||||||
|
gst_ffmpeg_pipe_read, NULL, NULL);
|
||||||
|
(*context)->seekable = 0;
|
||||||
|
(*context)->buf_ptr = (*context)->buf_end;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue