mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-28 20:05:38 +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 <libavformat/avformat.h>
|
||||
#include <libavformat/url.h>
|
||||
|
||||
#include "gstav.h"
|
||||
#include "gstavutils.h"
|
||||
|
@ -150,9 +149,6 @@ plugin_init (GstPlugin * plugin)
|
|||
gst_ffmpegaudioresample_register (plugin);
|
||||
#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. */
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavformat/url.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_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;
|
||||
extern URLProtocol gstpipe_protocol;
|
||||
G_END_DECLS
|
||||
|
||||
/* use GST_FFMPEG URL_STREAMHEADER with URL_WRONLY if the first
|
||||
* buffer should be used as streamheader property on the pad's caps. */
|
||||
|
|
|
@ -332,8 +332,11 @@ gst_ffmpegdemux_close (GstFFMpegDemux * demux)
|
|||
demux->audiopads = 0;
|
||||
|
||||
/* close demuxer context from ffmpeg */
|
||||
av_close_input_file (demux->context);
|
||||
demux->context = NULL;
|
||||
if (demux->seekable)
|
||||
gst_ffmpegdata_close (demux->context->pb);
|
||||
else
|
||||
gst_ffmpeg_pipe_close (demux->context->pb);
|
||||
avformat_close_input (&demux->context);
|
||||
|
||||
GST_OBJECT_LOCK (demux);
|
||||
demux->opened = FALSE;
|
||||
|
@ -1115,9 +1118,9 @@ gst_ffmpegdemux_read_tags (GstFFMpegDemux * demux)
|
|||
static gboolean
|
||||
gst_ffmpegdemux_open (GstFFMpegDemux * demux)
|
||||
{
|
||||
AVIOContext *iocontext = NULL;
|
||||
GstFFMpegDemuxClass *oclass =
|
||||
(GstFFMpegDemuxClass *) G_OBJECT_GET_CLASS (demux);
|
||||
gchar *location;
|
||||
gint res, n_streams, i;
|
||||
#if 0
|
||||
/* Re-enable once converted to new AVMetaData API
|
||||
|
@ -1133,15 +1136,14 @@ gst_ffmpegdemux_open (GstFFMpegDemux * demux)
|
|||
|
||||
/* open via our input protocol hack */
|
||||
if (demux->seekable)
|
||||
location = g_strdup_printf ("gstreamer://%p", demux->sinkpad);
|
||||
res = gst_ffmpegdata_open (demux->sinkpad, AVIO_FLAG_READ, &iocontext);
|
||||
else
|
||||
location = g_strdup_printf ("gstpipe://%p", &demux->ffpipe);
|
||||
GST_DEBUG_OBJECT (demux, "about to call av_open_input_file %s", location);
|
||||
res = gst_ffmpeg_pipe_open (&demux->ffpipe, AVIO_FLAG_READ, &iocontext);
|
||||
|
||||
res = avformat_open_input (&demux->context, location,
|
||||
oclass->in_plugin, NULL);
|
||||
demux->context = avformat_alloc_context ();
|
||||
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);
|
||||
if (res < 0)
|
||||
goto open_failed;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstcollectpads.h>
|
||||
|
||||
|
@ -58,6 +59,7 @@ struct _GstFFMpegMux
|
|||
/* event_function is the collectpads default eventfunction */
|
||||
GstPadEventFunction event_function;
|
||||
int max_delay;
|
||||
int preload;
|
||||
};
|
||||
|
||||
typedef struct _GstFFMpegMuxClass GstFFMpegMuxClass;
|
||||
|
@ -294,7 +296,7 @@ gst_ffmpegmux_class_init (GstFFMpegMuxClass * klass)
|
|||
|
||||
g_object_class_install_property (gobject_class, PROP_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));
|
||||
|
||||
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->oformat = oclass->in_plugin;
|
||||
ffmpegmux->context->nb_streams = 0;
|
||||
g_snprintf (ffmpegmux->context->filename,
|
||||
sizeof (ffmpegmux->context->filename),
|
||||
"gstreamer://%p", ffmpegmux->srcpad);
|
||||
ffmpegmux->opened = FALSE;
|
||||
|
||||
ffmpegmux->videopads = 0;
|
||||
|
@ -345,6 +344,7 @@ gst_ffmpegmux_set_property (GObject * object, guint prop_id,
|
|||
|
||||
switch (prop_id) {
|
||||
case PROP_PRELOAD:
|
||||
src->preload = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_MAXDELAY:
|
||||
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) {
|
||||
case PROP_PRELOAD:
|
||||
g_value_set_int (value, src->preload);
|
||||
break;
|
||||
case PROP_MAXDELAY:
|
||||
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);
|
||||
|
||||
st = ffmpegmux->context->streams[collect_pad->padnum];
|
||||
av_opt_set_int (&ffmpegmux->context, "preload", ffmpegmux->preload, 0);
|
||||
ffmpegmux->context->max_delay = ffmpegmux->max_delay;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if (avio_open (&ffmpegmux->context->pb,
|
||||
ffmpegmux->context->filename, open_flags) < 0) {
|
||||
if (gst_ffmpegdata_open (ffmpegmux->srcpad, open_flags,
|
||||
&ffmpegmux->context->pb) < 0) {
|
||||
GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, TOO_LAZY, (NULL),
|
||||
("Failed to open stream context in avmux"));
|
||||
return GST_FLOW_ERROR;
|
||||
|
@ -763,7 +765,7 @@ gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data)
|
|||
av_write_trailer (ffmpegmux->context);
|
||||
ffmpegmux->opened = FALSE;
|
||||
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 ());
|
||||
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));
|
||||
if (ffmpegmux->opened) {
|
||||
ffmpegmux->opened = FALSE;
|
||||
avio_close (ffmpegmux->context->pb);
|
||||
gst_ffmpegdata_close (ffmpegmux->context->pb);
|
||||
}
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <errno.h>
|
||||
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavformat/url.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
|
@ -44,61 +43,14 @@ struct _GstProtocolInfo
|
|||
};
|
||||
|
||||
static int
|
||||
gst_ffmpegdata_open (URLContext * h, const char *filename, int flags)
|
||||
{
|
||||
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)
|
||||
gst_ffmpegdata_peek (void *priv_data, unsigned char *buf, int size)
|
||||
{
|
||||
GstProtocolInfo *info;
|
||||
GstBuffer *inbuf = NULL;
|
||||
GstFlowReturn ret;
|
||||
int total = 0;
|
||||
|
||||
g_return_val_if_fail ((h->flags & AVIO_FLAG_READ), AVERROR (EIO));
|
||||
info = (GstProtocolInfo *) h->priv_data;
|
||||
info = (GstProtocolInfo *) priv_data;
|
||||
|
||||
GST_DEBUG ("Pulling %d bytes at position %" G_GUINT64_FORMAT, size,
|
||||
info->offset);
|
||||
|
@ -130,17 +82,17 @@ gst_ffmpegdata_peek (URLContext * h, unsigned char *buf, int size)
|
|||
}
|
||||
|
||||
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;
|
||||
GstProtocolInfo *info;
|
||||
|
||||
info = (GstProtocolInfo *) h->priv_data;
|
||||
info = (GstProtocolInfo *) priv_data;
|
||||
|
||||
GST_DEBUG ("Reading %d bytes of data at position %" G_GUINT64_FORMAT, size,
|
||||
info->offset);
|
||||
|
||||
res = gst_ffmpegdata_peek (h, buf, size);
|
||||
res = gst_ffmpegdata_peek (priv_data, buf, size);
|
||||
if (res >= 0)
|
||||
info->offset += res;
|
||||
|
||||
|
@ -150,15 +102,13 @@ gst_ffmpegdata_read (URLContext * h, unsigned char *buf, int size)
|
|||
}
|
||||
|
||||
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;
|
||||
GstBuffer *outbuf;
|
||||
|
||||
GST_DEBUG ("Writing %d bytes", size);
|
||||
info = (GstProtocolInfo *) h->priv_data;
|
||||
|
||||
g_return_val_if_fail ((h->flags & AVIO_FLAG_WRITE), -EIO);
|
||||
info = (GstProtocolInfo *) priv_data;
|
||||
|
||||
/* create buffer and push data further */
|
||||
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
|
||||
gst_ffmpegdata_seek (URLContext * h, int64_t pos, int whence)
|
||||
gst_ffmpegdata_seek (void *priv_data, int64_t pos, int whence)
|
||||
{
|
||||
GstProtocolInfo *info;
|
||||
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",
|
||||
(gint64) pos, whence);
|
||||
|
||||
info = (GstProtocolInfo *) h->priv_data;
|
||||
info = (GstProtocolInfo *) priv_data;
|
||||
|
||||
/* 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 */
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
|
@ -214,9 +165,7 @@ gst_ffmpegdata_seek (URLContext * h, int64_t pos, int whence)
|
|||
/* FIXME : implement case for push-based behaviour */
|
||||
if (whence != AVSEEK_SIZE)
|
||||
info->offset = newpos;
|
||||
}
|
||||
|
||||
if ((h->flags & AVIO_FLAG_WRITE)) {
|
||||
} else if (GST_PAD_IS_SRC (info->pad)) {
|
||||
GstSegment segment;
|
||||
|
||||
oldpos = info->offset;
|
||||
|
@ -242,6 +191,8 @@ gst_ffmpegdata_seek (URLContext * h, int64_t pos, int whence)
|
|||
segment.time = newpos;
|
||||
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
|
||||
|
@ -249,79 +200,90 @@ gst_ffmpegdata_seek (URLContext * h, int64_t pos, int whence)
|
|||
return newpos;
|
||||
}
|
||||
|
||||
static int
|
||||
gst_ffmpegdata_close (URLContext * h)
|
||||
int
|
||||
gst_ffmpegdata_close (AVIOContext * h)
|
||||
{
|
||||
GstProtocolInfo *info;
|
||||
|
||||
info = (GstProtocolInfo *) h->priv_data;
|
||||
info = (GstProtocolInfo *) h->opaque;
|
||||
if (info == NULL)
|
||||
return 0;
|
||||
|
||||
GST_LOG ("Closing file");
|
||||
|
||||
if ((h->flags & AVIO_FLAG_WRITE)) {
|
||||
if (GST_PAD_IS_SRC (info->pad)) {
|
||||
/* send EOS - that closes down the stream */
|
||||
gst_pad_push_event (info->pad, gst_event_new_eos ());
|
||||
}
|
||||
|
||||
/* clean up data */
|
||||
g_free (info);
|
||||
h->priv_data = NULL;
|
||||
h->opaque = NULL;
|
||||
|
||||
av_freep (&h->buffer);
|
||||
av_free (h);
|
||||
|
||||
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 = {
|
||||
/*.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 = g_new0 (GstProtocolInfo, 1);
|
||||
|
||||
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,
|
||||
* based on ffmpeg's pipe protocol */
|
||||
|
||||
static int
|
||||
gst_ffmpeg_pipe_open (URLContext * h, const char *filename, int flags)
|
||||
{
|
||||
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)
|
||||
gst_ffmpeg_pipe_read (void *priv_data, uint8_t * buf, int size)
|
||||
{
|
||||
GstFFMpegPipe *ffpipe;
|
||||
guint available;
|
||||
|
||||
ffpipe = (GstFFMpegPipe *) h->priv_data;
|
||||
ffpipe = (GstFFMpegPipe *) priv_data;
|
||||
|
||||
GST_LOG ("requested size %d", size);
|
||||
|
||||
|
@ -351,22 +313,38 @@ gst_ffmpeg_pipe_read (URLContext * h, unsigned char *buf, int size)
|
|||
return size;
|
||||
}
|
||||
|
||||
static int
|
||||
gst_ffmpeg_pipe_close (URLContext * h)
|
||||
int
|
||||
gst_ffmpeg_pipe_close (AVIOContext * h)
|
||||
{
|
||||
GST_LOG ("Closing pipe");
|
||||
|
||||
h->priv_data = NULL;
|
||||
h->opaque = NULL;
|
||||
av_freep (&h->buffer);
|
||||
av_free (h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
URLProtocol gstpipe_protocol = {
|
||||
"gstpipe",
|
||||
gst_ffmpeg_pipe_open,
|
||||
NULL,
|
||||
gst_ffmpeg_pipe_read,
|
||||
NULL,
|
||||
NULL,
|
||||
gst_ffmpeg_pipe_close,
|
||||
};
|
||||
int
|
||||
gst_ffmpeg_pipe_open (GstFFMpegPipe * ffpipe, int flags, AVIOContext ** context)
|
||||
{
|
||||
static const int buffer_size = 4096;
|
||||
unsigned char *buffer = NULL;
|
||||
|
||||
/* sanity check */
|
||||
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