gstffmpegprotocol.c 5.43 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* 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.
 */

20 21 22
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
23 24
#include <string.h>
#include <errno.h>
25 26 27 28 29 30
#ifdef HAVE_FFMPEG_UNINSTALLED
#include <avformat.h>
#else
#include <ffmpeg/avformat.h>
#endif

31
#include <gst/gst.h>
32
#include <gst/bytestream/bytestream.h>
33 34 35 36


typedef struct _GstProtocolInfo GstProtocolInfo;

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
37 38 39
struct _GstProtocolInfo
{
  GstPad *pad;
40

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
41
  int flags;
42
  GstByteStream *bs;
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
43
  gboolean eos;
44 45
};

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
46 47
static int
gst_ffmpegdata_open (URLContext * h, const char *filename, int flags)
48 49 50 51 52 53 54
{
  GstProtocolInfo *info;
  GstPad *pad;

  info = g_new0 (GstProtocolInfo, 1);
  info->flags = flags;

55
  /* we don't support R/W together */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
56
  if (flags != URL_RDONLY && flags != URL_WRONLY) {
57 58
    g_warning ("Only read-only or write-only are supported");
    return -EINVAL;
59 60
  }

61 62
  if (sscanf (&filename[12], "%p", &pad) != 1) {
    g_warning ("could not decode pad from %s", filename);
63 64 65
    return -EIO;
  }

66 67 68 69 70 71 72 73 74 75 76 77
  /* make sure we're a pad and that we're of the right type */
  g_return_val_if_fail (GST_IS_PAD (pad), -EINVAL);

  switch (flags) {
    case URL_RDONLY:
      g_return_val_if_fail (GST_PAD_IS_SINK (pad), -EINVAL);
      info->bs = gst_bytestream_new (pad);
      break;
    case URL_WRONLY:
      g_return_val_if_fail (GST_PAD_IS_SRC (pad), -EINVAL);
      info->bs = NULL;
      break;
78 79
  }

80
  info->eos = FALSE;
81
  info->pad = pad;
82

83 84 85 86 87
  h->priv_data = (void *) info;

  return 0;
}

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
88 89
static int
gst_ffmpegdata_read (URLContext * h, unsigned char *buf, int size)
90 91
{
  GstByteStream *bs;
92
  guint32 total, request;
93 94 95 96
  guint8 *data;
  GstProtocolInfo *info;

  info = (GstProtocolInfo *) h->priv_data;
97 98 99

  g_return_val_if_fail (info->flags == URL_RDONLY, -EIO);

100 101
  bs = info->bs;

102
  if (info->eos)
103 104
    return 0;

105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
  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;
      }
141
    }
142
  } while (!info->eos && total != request);
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
143

144 145
  memcpy (buf, data, total);
  gst_bytestream_flush (bs, total);
146 147 148 149

  return total;
}

150
static int
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
151
gst_ffmpegdata_write (URLContext * h, unsigned char *buf, int size)
152 153 154 155 156 157 158 159 160 161 162 163 164
{
  GstProtocolInfo *info;
  GstBuffer *outbuf;

  info = (GstProtocolInfo *) h->priv_data;

  g_return_val_if_fail (info->flags == URL_WRONLY, -EIO);

  /* create buffer and push data further */
  outbuf = gst_buffer_new_and_alloc (size);
  GST_BUFFER_SIZE (outbuf) = size;
  memcpy (GST_BUFFER_DATA (outbuf), buf, size);

165
  gst_pad_push (info->pad, GST_DATA (outbuf));
166 167 168 169 170

  return 0;
}

static offset_t
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
171
gst_ffmpegdata_seek (URLContext * h, offset_t pos, int whence)
172
{
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
  GstSeekType seek_type = 0;
  GstProtocolInfo *info;

  info = (GstProtocolInfo *) h->priv_data;

  switch (whence) {
    case SEEK_SET:
      seek_type = GST_SEEK_METHOD_SET;
      break;
    case SEEK_CUR:
      seek_type = GST_SEEK_METHOD_CUR;
      break;
    case SEEK_END:
      seek_type = GST_SEEK_METHOD_END;
      break;
    default:
      g_assert (0);
      break;
  }

  switch (info->flags) {
    case URL_RDONLY:
      gst_bytestream_seek (info->bs, pos, seek_type);
      break;

198 199 200 201 202 203
    case URL_WRONLY:
      gst_pad_push (info->pad, GST_DATA (gst_event_new_seek (seek_type, pos)));
      break;

    default:
      g_assert (0);
204 205
      break;
  }
206 207 208 209

  return 0;
}

210
static int
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
211
gst_ffmpegdata_close (URLContext * h)
212
{
213 214 215 216 217
  GstProtocolInfo *info;

  info = (GstProtocolInfo *) h->priv_data;

  switch (info->flags) {
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
218
    case URL_WRONLY:{
219 220
      /* send EOS - that closes down the stream */
      GstEvent *event = gst_event_new (GST_EVENT_EOS);
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
221

222
      gst_pad_push (info->pad, GST_DATA (event));
223 224 225 226 227 228 229 230 231 232 233 234
    }
      break;

    case URL_RDONLY:
      /* unref bytestream */
      gst_bytestream_destroy (info->bs);
      break;
  }

  /* clean up data */
  g_free (info);

235 236 237 238
  return 0;
}

URLProtocol gstreamer_protocol = {
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
239 240 241
  .name = "gstreamer",
  .url_open = gst_ffmpegdata_open,
  .url_read = gst_ffmpegdata_read,
242
  .url_write = gst_ffmpegdata_write,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
243
  .url_seek = gst_ffmpegdata_seek,
244
  .url_close = gst_ffmpegdata_close,
245
};