gstavidemux.c 57.9 KB
Newer Older
1 2
/* GStreamer
 * Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * 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.
 */


21
/* #define GST_DEBUG_ENABLED */
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
22 23 24 25 26 27
#include <string.h>

#include "gstavidemux.h"

/* elementfactory information */
static GstElementDetails gst_avi_demux_details = {
28 29
  "Avi demuxer",
  "Codec/Demuxer",
30
  "LGPL",
31
  "Demultiplex an avi file into audio and video",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
32 33
  VERSION,
  "Erik Walthinsen <omega@cse.ogi.edu>\n"
34
  "Wim Taymans <wim.taymans@chello.be>",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
35 36 37
  "(C) 1999",
};

38
static GstCaps* avi_type_find (GstBuffer *buf, gpointer private);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
39 40 41 42 43 44

/* typefactory for 'avi' */
static GstTypeDefinition avidefinition = {
  "avidemux_video/avi",
  "video/avi",
  ".avi",
45
  avi_type_find,
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
46 47 48 49 50 51 52 53 54 55 56
};

/* AviDemux signals and args */
enum {
  /* FILL ME */
  LAST_SIGNAL
};

enum {
  ARG_0,
  ARG_BITRATE,
57 58
  ARG_METADATA,
  ARG_STREAMINFO,
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
59 60 61
  /* FILL ME */
};

62
GST_PAD_TEMPLATE_FACTORY (sink_templ,
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
63 64 65 66 67 68
  "sink",
  GST_PAD_SINK,
  GST_PAD_ALWAYS,
  GST_CAPS_NEW (
    "avidemux_sink",
     "video/avi",
69
      "format",    GST_PROPS_STRING ("AVI")
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
70 71 72
  )
)

73
GST_PAD_TEMPLATE_FACTORY (src_video_templ,
Wim Taymans's avatar
Wim Taymans committed
74
  "video_%02d",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
75
  GST_PAD_SRC,
76
  GST_PAD_SOMETIMES,
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
77
  GST_CAPS_NEW (
Ronald S. Bultje's avatar
Ronald S. Bultje committed
78
    "avidemux_src_video",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
79 80 81 82
    "video/avi",
      "format",  GST_PROPS_LIST (
	           GST_PROPS_STRING ("strf_vids"),
	           GST_PROPS_STRING ("strf_iavs")
Ronald S. Bultje's avatar
Ronald S. Bultje committed
83 84 85 86
      		 ),
      "width",   GST_PROPS_INT_RANGE (16, 4096),
      "height",  GST_PROPS_INT_RANGE (16, 4096)

Ronald S. Bultje's avatar
Ronald S. Bultje committed
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
  ),
  GST_CAPS_NEW (
    "avidemux_src_video",
    "video/raw",
      "format",  GST_PROPS_LIST (
                   GST_PROPS_FOURCC (GST_MAKE_FOURCC('Y','U','Y','2')),
                   GST_PROPS_FOURCC (GST_MAKE_FOURCC('I','4','2','0'))
                 ),
      "width",          GST_PROPS_INT_RANGE (16, 4096),
      "height",         GST_PROPS_INT_RANGE (16, 4096)
  ),
  GST_CAPS_NEW (
    "avidemux_src_video",
    "video/jpeg",
      "width",   GST_PROPS_INT_RANGE (16, 4096),
      "height",  GST_PROPS_INT_RANGE (16, 4096)
  ),
  GST_CAPS_NEW (
    "avidemux_src_video",
    "video/dv",
      "format",  GST_PROPS_LIST (
                   GST_PROPS_STRING ("NTSC"),
                   GST_PROPS_STRING ("PAL")
Ronald S. Bultje's avatar
Ronald S. Bultje committed
110 111 112
                 ),
      "width",   GST_PROPS_INT_RANGE (16, 4096),
      "height",  GST_PROPS_INT_RANGE (16, 4096)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
113 114 115
  )
)

116
GST_PAD_TEMPLATE_FACTORY (src_audio_templ,
Wim Taymans's avatar
Wim Taymans committed
117
  "audio_%02d",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
118
  GST_PAD_SRC,
119
  GST_PAD_SOMETIMES,
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
120
  GST_CAPS_NEW (
Ronald S. Bultje's avatar
Ronald S. Bultje committed
121
    "avidemux_src_audio",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
122
    "video/avi",
Ronald S. Bultje's avatar
Ronald S. Bultje committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
      "format",  GST_PROPS_STRING ("strf_auds")
  ),
  GST_CAPS_NEW (
    "avidemux_src_audio",
    "audio/raw",
      "format",           GST_PROPS_STRING ("int"),
      "law",              GST_PROPS_INT (0),
      "endianness",       GST_PROPS_INT (G_BYTE_ORDER),
      "signed",           GST_PROPS_LIST (
      			    GST_PROPS_BOOLEAN (TRUE),
      			    GST_PROPS_BOOLEAN (FALSE)
			  ),
      "width",            GST_PROPS_LIST (
      			    GST_PROPS_INT (8),
      			    GST_PROPS_INT (16)
			  ),
      "depth",            GST_PROPS_LIST (
      			    GST_PROPS_INT (8),
      			    GST_PROPS_INT (16)
			  ),
      "rate",             GST_PROPS_INT_RANGE (11025, 44100),
      "channels",         GST_PROPS_INT_RANGE (1, 2)
  ),
  GST_CAPS_NEW (
    "avidemux_src_audio",
148
    "audio/x-mp3",
Ronald S. Bultje's avatar
Ronald S. Bultje committed
149
      NULL
150
  ),
Wim Taymans's avatar
Wim Taymans committed
151 152 153 154 155
  GST_CAPS_NEW (
    "avidemux_src_audio",
    "audio/a52",
      NULL
  ),
156 157 158 159
  GST_CAPS_NEW (
    "avidemux_src_audio",
    "application/x-ogg",
    NULL
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
160 161 162
  )
)

163 164
static void 		gst_avi_demux_class_init		(GstAviDemuxClass *klass);
static void 		gst_avi_demux_init			(GstAviDemux *avi_demux);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
165

166
static void 		gst_avi_demux_loop 			(GstElement *element);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
167

168
static gboolean 	gst_avi_demux_send_event 		(GstElement *element, GstEvent *event);
169

170 171 172 173
static const GstEventMask*
			gst_avi_demux_get_event_mask 		(GstPad *pad);
static gboolean 	gst_avi_demux_handle_src_event 		(GstPad *pad, GstEvent *event);
static const GstFormat* gst_avi_demux_get_src_formats 		(GstPad *pad); 
Wim Taymans's avatar
Wim Taymans committed
174
static const GstQueryType*
175
			gst_avi_demux_get_src_query_types 	(GstPad *pad);
Wim Taymans's avatar
Wim Taymans committed
176
static gboolean 	gst_avi_demux_handle_src_query 		(GstPad *pad, GstQueryType type, 
177 178 179
								 GstFormat *format, gint64 *value);
static gboolean 	gst_avi_demux_src_convert 		(GstPad *pad, GstFormat src_format, gint64 src_value,
	        	          				 GstFormat *dest_format, gint64 *dest_value);
Wim Taymans's avatar
Wim Taymans committed
180

Wim Taymans's avatar
Wim Taymans committed
181
static GstElementStateReturn
182
			gst_avi_demux_change_state 		(GstElement *element);
Wim Taymans's avatar
Wim Taymans committed
183

184 185
static void     	gst_avi_demux_get_property      	(GObject *object, guint prop_id, 	
								 GValue *value, GParamSpec *pspec);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
186 187 188


static GstElementClass *parent_class = NULL;
189
/*static guint gst_avi_demux_signals[LAST_SIGNAL] = { 0 }; */
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223

GType
gst_avi_demux_get_type(void) 
{
  static GType avi_demux_type = 0;

  if (!avi_demux_type) {
    static const GTypeInfo avi_demux_info = {
      sizeof(GstAviDemuxClass),      
      NULL,
      NULL,
      (GClassInitFunc)gst_avi_demux_class_init,
      NULL,
      NULL,
      sizeof(GstAviDemux),
      0,
      (GInstanceInitFunc)gst_avi_demux_init,
    };
    avi_demux_type = g_type_register_static(GST_TYPE_ELEMENT, "GstAviDemux", &avi_demux_info, 0);
  }
  return avi_demux_type;
}

static void
gst_avi_demux_class_init (GstAviDemuxClass *klass) 
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

  gobject_class = (GObjectClass*)klass;
  gstelement_class = (GstElementClass*)klass;

  g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_BITRATE,
    g_param_spec_long ("bitrate","bitrate","bitrate",
224
                       G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); /* CHECKME */
225 226 227 228 229 230
  g_object_class_install_property (gobject_class, ARG_METADATA,
    g_param_spec_boxed ("metadata", "Metadata", "Metadata",
                        GST_TYPE_CAPS, G_PARAM_READABLE));
  g_object_class_install_property (gobject_class, ARG_STREAMINFO,
    g_param_spec_boxed ("streaminfo", "Streaminfo", "Streaminfo",
                        GST_TYPE_CAPS, G_PARAM_READABLE));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
231 232 233 234

  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
  
  gobject_class->get_property = gst_avi_demux_get_property;
Wim Taymans's avatar
Wim Taymans committed
235 236
  
  gstelement_class->change_state = gst_avi_demux_change_state;
237
  gstelement_class->send_event = gst_avi_demux_send_event;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
238 239 240 241 242 243 244 245
}

static void 
gst_avi_demux_init (GstAviDemux *avi_demux) 
{
  GST_FLAG_SET (avi_demux, GST_ELEMENT_EVENT_AWARE);
				
  avi_demux->sinkpad = gst_pad_new_from_template (
246
		  GST_PAD_TEMPLATE_GET (sink_templ), "sink");
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
247 248 249 250 251 252
  gst_element_add_pad (GST_ELEMENT (avi_demux), avi_demux->sinkpad);

  gst_element_set_loop_function (GST_ELEMENT (avi_demux), gst_avi_demux_loop);
}

static GstCaps*
253
avi_type_find (GstBuffer *buf,
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
254 255 256 257 258
              gpointer private)
{
  gchar *data = GST_BUFFER_DATA (buf);
  GstCaps *new;

259
  GST_DEBUG (0,"avi_demux: typefind");
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
260 261 262 263 264 265

  if (GUINT32_FROM_LE (((guint32 *)data)[0]) != GST_RIFF_TAG_RIFF)
    return NULL;
  if (GUINT32_FROM_LE (((guint32 *)data)[2]) != GST_RIFF_RIFF_AVI)
    return NULL;

266
  new = GST_CAPS_NEW ("avi_type_find",
267
		      "video/avi", 
268
		        "format", GST_PROPS_STRING ("AVI"));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
269 270 271 272 273 274 275
  return new;
}

static gboolean
gst_avi_demux_avih (GstAviDemux *avi_demux)
{
  gst_riff_avih *avih;
276 277 278 279
  GstByteStream  *bs = avi_demux->bs;
  guint32 got_bytes;

  got_bytes = gst_bytestream_peek_bytes (bs, (guint8 **)&avih, sizeof (gst_riff_avih));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
280

281
  if (got_bytes == sizeof (gst_riff_avih)) {
Wim Taymans's avatar
Wim Taymans committed
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
    avi_demux->avih.us_frame 	= GUINT32_FROM_LE (avih->us_frame);
    avi_demux->avih.max_bps 	= GUINT32_FROM_LE (avih->max_bps);
    avi_demux->avih.pad_gran 	= GUINT32_FROM_LE (avih->pad_gran);
    avi_demux->avih.flags 	= GUINT32_FROM_LE (avih->flags);
    avi_demux->avih.tot_frames 	= GUINT32_FROM_LE (avih->tot_frames);
    avi_demux->avih.init_frames = GUINT32_FROM_LE (avih->init_frames);
    avi_demux->avih.streams 	= GUINT32_FROM_LE (avih->streams);
    avi_demux->avih.bufsize 	= GUINT32_FROM_LE (avih->bufsize);
    avi_demux->avih.width 	= GUINT32_FROM_LE (avih->width);
    avi_demux->avih.height 	= GUINT32_FROM_LE (avih->height);
    avi_demux->avih.scale 	= GUINT32_FROM_LE (avih->scale);
    avi_demux->avih.rate 	= GUINT32_FROM_LE (avih->rate);
    avi_demux->avih.start 	= GUINT32_FROM_LE (avih->start);
    avi_demux->avih.length 	= GUINT32_FROM_LE (avih->length);

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
297
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: avih tag found");
Wim Taymans's avatar
Wim Taymans committed
298 299 300 301 302 303 304 305 306 307 308 309 310 311
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  us_frame    %d", avi_demux->avih.us_frame);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  max_bps     %d", avi_demux->avih.max_bps);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  pad_gran    %d", avi_demux->avih.pad_gran);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  flags       0x%08x", avi_demux->avih.flags);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  tot_frames  %d", avi_demux->avih.tot_frames);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  init_frames %d", avi_demux->avih.init_frames);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  streams     %d", avi_demux->avih.streams);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  bufsize     %d", avi_demux->avih.bufsize);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  width       %d", avi_demux->avih.width);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  height      %d", avi_demux->avih.height);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  scale       %d", avi_demux->avih.scale);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  rate        %d", avi_demux->avih.rate);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  start       %d", avi_demux->avih.start);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  length      %d", avi_demux->avih.length);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
312 313 314 315 316 317 318 319 320 321

    return TRUE;
  }
  return FALSE;
}

static gboolean 
gst_avi_demux_strh (GstAviDemux *avi_demux)
{
  gst_riff_strh *strh;
322 323 324 325
  GstByteStream  *bs = avi_demux->bs;
  guint32 got_bytes;

  got_bytes = gst_bytestream_peek_bytes (bs, (guint8 **)&strh, sizeof (gst_riff_strh));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
326

327
  if (got_bytes == sizeof (gst_riff_strh)) {
Wim Taymans's avatar
Wim Taymans committed
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
    avi_stream_context *target;

    avi_demux->fcc_type = GUINT32_FROM_LE (strh->type);

    target = &avi_demux->stream[avi_demux->num_streams];

    target->num = avi_demux->num_streams;

    target->strh.type 		= avi_demux->fcc_type;
    target->strh.fcc_handler 	= GUINT32_FROM_LE (strh->fcc_handler);
    target->strh.flags		= GUINT32_FROM_LE (strh->flags);
    target->strh.priority	= GUINT32_FROM_LE (strh->priority);
    target->strh.init_frames	= GUINT32_FROM_LE (strh->init_frames);
    target->strh.scale		= GUINT32_FROM_LE (strh->scale);
    target->strh.rate		= GUINT32_FROM_LE (strh->rate);
    target->strh.start		= GUINT32_FROM_LE (strh->start);
    target->strh.length		= GUINT32_FROM_LE (strh->length);
    target->strh.bufsize	= GUINT32_FROM_LE (strh->bufsize);
    target->strh.quality	= GUINT32_FROM_LE (strh->quality);
    target->strh.samplesize	= GUINT32_FROM_LE (strh->samplesize);

    if (!target->strh.scale)
      target->strh.scale = 1; /* avoid division by zero */
    if (!target->strh.rate)
      target->strh.rate = 1; /* avoid division by zero */

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
354 355
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strh tag found");
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  type        0x%08x (%s)", 
Wim Taymans's avatar
Wim Taymans committed
356
  		  target->strh.type, gst_riff_id_to_fourcc (strh->type));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
357
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  fcc_handler 0x%08x (%s)", 
Wim Taymans's avatar
Wim Taymans committed
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
		  target->strh.fcc_handler, gst_riff_id_to_fourcc (strh->fcc_handler));
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  flags       0x%08x", strh->flags);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  priority    %d", target->strh.priority);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  init_frames %d", target->strh.init_frames);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  scale       %d", target->strh.scale);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  rate        %d", target->strh.rate);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  start       %d", target->strh.start);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  length      %d", target->strh.length);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  bufsize     %d", target->strh.bufsize);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  quality     %d", target->strh.quality);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  samplesize  %d", target->strh.samplesize);

    target->delay = 0LL;
    target->total_bytes = 0LL;
    target->total_frames = 0;
Wim Taymans's avatar
Wim Taymans committed
373
    target->end_pos = -1;
374 375 376
    target->current_frame = 0;
    target->current_byte = 0;
    target->need_flush = FALSE;
Wim Taymans's avatar
Wim Taymans committed
377
    target->skip = 0;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
378

379 380
    avi_demux->avih.bufsize = MAX (avi_demux->avih.bufsize, target->strh.bufsize);

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
381 382 383 384 385
    return TRUE;
  }
  return FALSE;
}

386 387 388 389
static void
gst_avi_demux_dmlh (GstAviDemux *avi_demux)
{
  gst_riff_dmlh *dmlh;
390
  GstByteStream  *bs = avi_demux->bs;
391 392
  guint32 got_bytes;

393
  got_bytes = gst_bytestream_peek_bytes (bs, (guint8 **)&dmlh, sizeof (gst_riff_dmlh));
394 395
}

Wim Taymans's avatar
Wim Taymans committed
396 397 398 399 400 401 402 403 404 405 406 407 408 409
static void
gst_avi_demux_strn (GstAviDemux *avi_demux, gint len)
{
  gchar *name;
  GstByteStream  *bs = avi_demux->bs;
  guint32 got_bytes;

  got_bytes = gst_bytestream_peek_bytes (bs, (guint8 **)&name, len);
  if (got_bytes != len)
    return;

  GST_DEBUG (0, "Stream name: \"%s\"", name);
}

410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
static void
gst_avi_demux_metadata (GstAviDemux *avi_demux, gint len)
{
  guint32 got_bytes;
  GstByteStream  *bs = avi_demux->bs;
  gst_riff_chunk *chunk;
  gchar *name, *type;
  GstProps *props;
  GstPropsEntry *entry;

  props = gst_props_empty_new ();

  while (len > 0) {
    got_bytes = gst_bytestream_peek_bytes(bs, (guint8**)&chunk, sizeof(gst_riff_chunk));
    gst_bytestream_flush(bs, sizeof(gst_riff_chunk));
    if (got_bytes != sizeof(gst_riff_chunk))
      return;
    len -= sizeof(gst_riff_chunk);

    /* don't care about empty entries - move on */
    if (chunk->size == 0)
      continue;

    got_bytes = gst_bytestream_peek_bytes(bs, (guint8**)&name, chunk->size);
    gst_bytestream_flush(bs, (chunk->size + 1) &~ 1);
    if (got_bytes != chunk->size)
      return;
    len -= ((chunk->size + 1) &~ 1);

    /* we now have an info string in 'name' of type 'chunk.id' - find 'type' */
    switch (chunk->id) {
      case GST_RIFF_INFO_IARL:
        type = "Location";
        break;
      case GST_RIFF_INFO_IART:
        type = "Artist";
        break;
      case GST_RIFF_INFO_ICMS:
        type = "Commissioner";
        break;
      case GST_RIFF_INFO_ICMT:
        type = "Comment";
        break;
      case GST_RIFF_INFO_ICOP:
        type = "Copyright";
        break;
      case GST_RIFF_INFO_ICRD:
        type = "Creation Date";
        break;
      case GST_RIFF_INFO_ICRP:
        type = "Cropped";
        break;
      case GST_RIFF_INFO_IDIM:
        type = "Dimensions";
        break;
      case GST_RIFF_INFO_IDPI:
        type = "Dots per Inch";
        break;
      case GST_RIFF_INFO_IENG:
        type = "Engineer";
        break;
      case GST_RIFF_INFO_IGNR:
        type = "Genre";
        break;
      case GST_RIFF_INFO_IKEY:
        type = "Keywords";
        break;
      case GST_RIFF_INFO_ILGT:
        type = "Lightness";
        break;
      case GST_RIFF_INFO_IMED:
        type = "Medium";
        break;
      case GST_RIFF_INFO_INAM:
        type = "Title"; /* "Name" */
        break;
      case GST_RIFF_INFO_IPLT:
        type = "Palette";
        break;
      case GST_RIFF_INFO_IPRD:
        type = "Product";
        break;
      case GST_RIFF_INFO_ISBJ:
        type = "Subject";
        break;
      case GST_RIFF_INFO_ISFT:
        type = "Encoder"; /* "Sotware" */
        break;
      case GST_RIFF_INFO_ISHP:
        type = "Sharpness";
        break;
      case GST_RIFF_INFO_ISRC:
        type = "Source";
        break;
      case GST_RIFF_INFO_ISRF:
        type = "Source Form";
        break;
      case GST_RIFF_INFO_ITCH:
        type = "Technician";
        break;
      default:
	type = NULL;
	break;
    }

    if (type) {
      /* create props entry */
      entry = gst_props_entry_new(type, GST_PROPS_STRING(name));
      gst_props_add_entry (props, entry);
    }
  }

  gst_props_debug(props);

  avi_demux->metadata = gst_caps_new("avi_metadata",
                                     "application/x-gst-metadata",
                                     props);

  g_object_notify(G_OBJECT(avi_demux), "metadata");
}

static void
gst_avi_demux_streaminfo (GstAviDemux *avi_demux)
{
  GstProps *props;

  props = gst_props_empty_new ();

  /* compression formats are added later - a bit hacky */

  avi_demux->streaminfo = gst_caps_new("avi_streaminfo",
                                       "application/x-gst-streaminfo",
                                       props);

  /*g_object_notify(G_OBJECT(avi_demux), "streaminfo");*/
}

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
547 548 549 550 551
static void 
gst_avi_demux_strf_vids (GstAviDemux *avi_demux)
{
  gst_riff_strf_vids *strf;
  GstPad *srcpad;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
552
  GstCaps *newcaps = NULL, *capslist = NULL;
Wim Taymans's avatar
Wim Taymans committed
553
  avi_stream_context *stream;
554 555
  GstByteStream  *bs = avi_demux->bs;
  guint32 got_bytes;
556 557
  gchar *codecname;
  GstPropsEntry *entry;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
558

559 560 561
  got_bytes = gst_bytestream_peek_bytes (bs, (guint8 **)&strf, sizeof (gst_riff_strf_vids));
  if (got_bytes != sizeof (gst_riff_strf_vids))
    return;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577

  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context vids");
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  size        %d", GUINT32_FROM_LE (strf->size));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  width       %d", GUINT32_FROM_LE (strf->width));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  height      %d", GUINT32_FROM_LE (strf->height));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  planes      %d", GUINT16_FROM_LE (strf->planes));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  bit_cnt     %d", GUINT16_FROM_LE (strf->bit_cnt));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  compression 0x%08x (%s)", 
		  GUINT32_FROM_LE (strf->compression), gst_riff_id_to_fourcc (strf->compression));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  image_size  %d", GUINT32_FROM_LE (strf->image_size));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  xpels_meter %d", GUINT32_FROM_LE (strf->xpels_meter));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  ypels_meter %d", GUINT32_FROM_LE (strf->ypels_meter));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  num_colors  %d", GUINT32_FROM_LE (strf->num_colors));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  imp_colors  %d", GUINT32_FROM_LE (strf->imp_colors));

  srcpad =  gst_pad_new_from_template (
578
		  GST_PAD_TEMPLATE_GET (src_video_templ), g_strdup_printf ("video_%02d", 
Wim Taymans's avatar
Wim Taymans committed
579
			  avi_demux->num_v_streams));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
580

Ronald S. Bultje's avatar
Ronald S. Bultje committed
581 582
  capslist = gst_caps_append(NULL, GST_CAPS_NEW (
			  "avidemux_video_src",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
583 584 585 586 587 588 589 590 591 592 593 594
			  "video/avi",
			    "format",    	GST_PROPS_STRING ("strf_vids"),
			      "size", 		GST_PROPS_INT (GUINT32_FROM_LE (strf->size)),
			      "width", 		GST_PROPS_INT (GUINT32_FROM_LE (strf->width)),
			      "height", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->height)),
			      "planes", 	GST_PROPS_INT (GUINT16_FROM_LE (strf->planes)),
			      "bit_cnt", 	GST_PROPS_INT (GUINT16_FROM_LE (strf->bit_cnt)),
			      "compression", 	GST_PROPS_FOURCC (GUINT32_FROM_LE (strf->compression)),
			      "image_size", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->image_size)),
			      "xpels_meter", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->xpels_meter)),
			      "ypels_meter", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->ypels_meter)),
			      "num_colors", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->num_colors)),
595 596
			      "imp_colors", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->imp_colors))
			      ));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
597

Ronald S. Bultje's avatar
Ronald S. Bultje committed
598
  /* let's try some gstreamer-like mime-type caps */
Ronald S. Bultje's avatar
Ronald S. Bultje committed
599 600 601 602 603 604 605 606 607 608 609
  switch (GUINT32_FROM_LE(strf->compression))
  {
    case GST_MAKE_FOURCC('I','4','2','0'):
    case GST_MAKE_FOURCC('Y','U','Y','2'):
      newcaps = GST_CAPS_NEW (
                  "avidemux_video_src",
                  "video/raw",
                    "format",  GST_PROPS_FOURCC(GUINT32_FROM_LE(strf->compression)),
                    "width",   GST_PROPS_INT(strf->width),
                    "height",  GST_PROPS_INT(strf->height)
                );
610 611
      codecname = g_strdup_printf("Raw Video (%4.4s)",
                                  (char *) &strf->compression);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
612
      break;
613 614 615 616
    case GST_MAKE_FOURCC('M','J','P','G'): /* YUY2 MJPEG */
    case GST_MAKE_FOURCC('J','P','E','G'): /* generic (mostly RGB) MJPEG */
    case GST_MAKE_FOURCC('P','I','X','L'): /* Miro/Pinnacle fourccs */
    case GST_MAKE_FOURCC('V','I','X','L'): /* Miro/Pinnacle fourccs */
Ronald S. Bultje's avatar
Ronald S. Bultje committed
617 618 619 620 621 622
      newcaps = GST_CAPS_NEW (
                  "avidemux_video_src",
                  "video/jpeg",
                    "width",   GST_PROPS_INT(strf->width),
                    "height",  GST_PROPS_INT(strf->height)
                );
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
      codecname = g_strdup_printf("Motion-JPEG (%4.4s)",
                                  (char *) &strf->compression);
      break;
    case GST_MAKE_FOURCC('H','F','Y','U'):
      codecname = g_strdup_printf("HuffYUV (%4.4s)",
                                  (char *) &strf->compression);
      break;
    case GST_MAKE_FOURCC('M','P','E','G'):
    case GST_MAKE_FOURCC('M','P','G','I'):
      newcaps = GST_CAPS_NEW (
                  "avidemux_video_src",
                  "video/mpeg",
                    "width",   GST_PROPS_INT(strf->width),
                    "height",  GST_PROPS_INT(strf->height)
                );
      codecname = g_strdup_printf("MPEG-1 (%4.4s)",
                                  (char *) &strf->compression);
      break;
    case GST_MAKE_FOURCC('H','2','6','3'):
    case GST_MAKE_FOURCC('i','2','6','3'):
    case GST_MAKE_FOURCC('L','2','6','3'):
    case GST_MAKE_FOURCC('M','2','6','3'):
    case GST_MAKE_FOURCC('V','D','O','W'):
    case GST_MAKE_FOURCC('V','I','V','O'):
    case GST_MAKE_FOURCC('x','2','6','3'):
      codecname = g_strdup_printf("H263-compatible (%4.4s)",
                                  (char *) &strf->compression);
      break;
    case GST_MAKE_FOURCC('d','i','v','x'):
    case GST_MAKE_FOURCC('D','I','V','3'):
    case GST_MAKE_FOURCC('D','I','V','4'):
    case GST_MAKE_FOURCC('D','I','V','5'):
    case GST_MAKE_FOURCC('D','I','V','X'):
    case GST_MAKE_FOURCC('D','X','5','0'):
      newcaps = GST_CAPS_NEW (
                  "avidemux_video_src",
                  "video/divx",
                    "width",   GST_PROPS_INT(strf->width),
                    "height",  GST_PROPS_INT(strf->height)
                );
      codecname = g_strdup_printf("DivX/MPEG-4 (%4.4s)",
                                  (char *) &strf->compression);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
665
      break;
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
    case GST_MAKE_FOURCC('X','V','I','D'):
    case GST_MAKE_FOURCC('x','v','i','d'):
      newcaps = GST_CAPS_NEW (
                  "avidemux_video_src",
                  "video/xvid",
                    "width",   GST_PROPS_INT(strf->width),
                    "height",  GST_PROPS_INT(strf->height)
                );
      codecname = g_strdup_printf("XviD/MPEG-4 (%4.4s)",
                                  (char *) &strf->compression);
      break;
    case GST_MAKE_FOURCC('M','P','G','4'):
    case GST_MAKE_FOURCC('M','P','4','2'):
    case GST_MAKE_FOURCC('M','P','4','3'):
      codecname = g_strdup_printf("MS MPEG-4 (%4.4s)",
                                  (char *) &strf->compression);
      break;
    case GST_MAKE_FOURCC('D','V','S','D'):
Ronald S. Bultje's avatar
Ronald S. Bultje committed
684 685 686 687 688 689 690 691
    case GST_MAKE_FOURCC('d','v','s','d'):
      newcaps = GST_CAPS_NEW (
                  "avidemux_video_src",
                  "video/dv",
                    "format",  GST_PROPS_STRING("NTSC"), /* FIXME??? */
                    "width",   GST_PROPS_INT(strf->width),
                    "height",  GST_PROPS_INT(strf->height)
                );
692 693 694 695 696 697
      codecname = g_strdup_printf("Digital Video (%4.4s)",
                                  (char *) &strf->compression);
      break;
    default:
      codecname = g_strdup_printf("Unknown (%4.4s)",
                                  (char *) &strf->compression);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
698 699 700
      break;
  }

Wim Taymans's avatar
Wim Taymans committed
701
  if (newcaps) capslist = gst_caps_append (capslist, newcaps);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
702

703 704 705 706 707
  /* set video codec info on streaminfo caps */
  entry = gst_props_entry_new("videocodec", GST_PROPS_STRING(codecname));
  gst_props_add_entry(avi_demux->streaminfo->properties, entry);
  g_free(codecname);

Wim Taymans's avatar
Wim Taymans committed
708
  gst_pad_try_set_caps (srcpad, capslist);
709 710
  gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
  gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
Wim Taymans's avatar
Wim Taymans committed
711
  gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
712
  gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
Wim Taymans's avatar
Wim Taymans committed
713
  gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
714
  gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
Wim Taymans's avatar
Wim Taymans committed
715 716 717 718 719 720

  stream = &avi_demux->stream[avi_demux->num_streams];
  stream->pad = srcpad;
  gst_pad_set_element_private (srcpad, stream);
  avi_demux->num_streams++;
  avi_demux->num_v_streams++;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
721

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
722 723 724 725 726 727 728 729
  gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
}

static void 
gst_avi_demux_strf_auds (GstAviDemux *avi_demux)
{
  gst_riff_strf_auds *strf;
  GstPad *srcpad;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
730
  GstCaps *newcaps = NULL, *capslist = NULL;
Wim Taymans's avatar
Wim Taymans committed
731
  avi_stream_context *stream;
732 733
  GstByteStream  *bs = avi_demux->bs;
  guint32 got_bytes;
734 735
  gchar *codecname;
  GstPropsEntry *entry;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
736

737 738 739
  got_bytes = gst_bytestream_peek_bytes (bs, (guint8 **)&strf, sizeof (gst_riff_strf_auds));
  if (got_bytes != sizeof (gst_riff_strf_auds))
    return;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
740 741 742 743 744 745 746 747 748 749

  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context auds");
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  format      %d", GUINT16_FROM_LE (strf->format));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  channels    %d", GUINT16_FROM_LE (strf->channels));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  rate        %d", GUINT32_FROM_LE (strf->rate));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  av_bps      %d", GUINT32_FROM_LE (strf->av_bps));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  blockalign  %d", GUINT16_FROM_LE (strf->blockalign));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  size        %d", GUINT16_FROM_LE (strf->size));

  srcpad =  gst_pad_new_from_template (
750
		  GST_PAD_TEMPLATE_GET (src_audio_templ), g_strdup_printf ("audio_%02d", 
Wim Taymans's avatar
Wim Taymans committed
751
			  avi_demux->num_a_streams));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
752

Ronald S. Bultje's avatar
Ronald S. Bultje committed
753 754
  capslist = gst_caps_append(NULL, GST_CAPS_NEW (
			  "avidemux_audio_src",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
755 756 757 758 759 760 761
			  "video/avi",
			    "format",    	GST_PROPS_STRING ("strf_auds"),
			      "fmt", 		GST_PROPS_INT (GUINT16_FROM_LE (strf->format)),
			      "channels", 	GST_PROPS_INT (GUINT16_FROM_LE (strf->channels)),
			      "rate", 		GST_PROPS_INT (GUINT32_FROM_LE (strf->rate)),
			      "av_bps",		GST_PROPS_INT (GUINT32_FROM_LE (strf->av_bps)),
			      "blockalign",	GST_PROPS_INT (GUINT16_FROM_LE (strf->blockalign)),
762 763
			      "size",		GST_PROPS_INT (GUINT16_FROM_LE (strf->size))
			  ));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
764

Ronald S. Bultje's avatar
Ronald S. Bultje committed
765 766 767
  /* let's try some gstreamer-formatted mime types */
  switch (GUINT16_FROM_LE(strf->format))
  {
768 769
    case GST_RIFF_WAVE_FORMAT_MPEGL3:
    case GST_RIFF_WAVE_FORMAT_MPEGL12: /* mp3 */
Ronald S. Bultje's avatar
Ronald S. Bultje committed
770
      newcaps = gst_caps_new ("avidemux_audio_src",
771
                              "audio/x-mp3",
Ronald S. Bultje's avatar
Ronald S. Bultje committed
772
                                NULL);
773 774
      codecname = g_strdup_printf("MPEG/audio (0x%04x)",
                                  strf->format);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
775
      break;
776
    case GST_RIFF_WAVE_FORMAT_PCM: /* PCM/wav */
Ronald S. Bultje's avatar
Ronald S. Bultje committed
777 778 779 780 781 782 783 784
      newcaps = gst_caps_new ("avidemux_audio_src",
                              "audio/raw",
                              gst_props_new (
                                "format",     GST_PROPS_STRING ("int"),
                                "law",        GST_PROPS_INT (0),
                                "endianness", GST_PROPS_INT (G_BYTE_ORDER),
                                "signed",     GST_PROPS_BOOLEAN ((GUINT16_FROM_LE (strf->size) != 8)),
                                "width",      GST_PROPS_INT ((GUINT16_FROM_LE (strf->blockalign)*8) /
Wim Taymans's avatar
Wim Taymans committed
785
                                                              GUINT16_FROM_LE (strf->channels)),
Ronald S. Bultje's avatar
Ronald S. Bultje committed
786 787 788 789 790
                                "depth",      GST_PROPS_INT (GUINT16_FROM_LE (strf->size)),
                                "rate",       GST_PROPS_INT (GUINT32_FROM_LE (strf->rate)),
                                "channels",   GST_PROPS_INT (GUINT16_FROM_LE (strf->channels)),
                                NULL
                              ));
791 792
      codecname = g_strdup_printf("Raw PCM/WAV (0x%04x)",
                                  strf->format);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
793
      break;
794 795 796 797 798 799 800 801 802
    case GST_RIFF_WAVE_FORMAT_VORBIS1: /* ogg/vorbis mode 1 */
    case GST_RIFF_WAVE_FORMAT_VORBIS2: /* ogg/vorbis mode 2 */
    case GST_RIFF_WAVE_FORMAT_VORBIS3: /* ogg/vorbis mode 3 */
    case GST_RIFF_WAVE_FORMAT_VORBIS1PLUS: /* ogg/vorbis mode 1+ */
    case GST_RIFF_WAVE_FORMAT_VORBIS2PLUS: /* ogg/vorbis mode 2+ */
    case GST_RIFF_WAVE_FORMAT_VORBIS3PLUS: /* ogg/vorbis mode 3+ */
      newcaps = gst_caps_new ("avidemux_audio_src",
                              "application/x-ogg",
                              NULL);
803 804
      codecname = g_strdup_printf("Ogg/Vorbis (0x%04x)",
                                  strf->format);
805
      break;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
806
    case GST_RIFF_WAVE_FORMAT_A52:
Wim Taymans's avatar
Wim Taymans committed
807 808 809
      newcaps = gst_caps_new ("avidemux_audio_src",
                              "audio/a52",
                              NULL);
810 811
      codecname = g_strdup_printf("AC3/AC52 (0x%04x)",
                                  strf->format);
Wim Taymans's avatar
Wim Taymans committed
812 813 814
      break;
    default:
      g_warning ("avidemux: unkown audio format %d", GUINT16_FROM_LE(strf->format));
815 816
      codecname = g_strdup_printf("Unknown (0x%04x)",
                                  strf->format);
Wim Taymans's avatar
Wim Taymans committed
817
      break;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
818 819 820 821
  }

  if (newcaps) capslist = gst_caps_append(capslist, newcaps);

822 823 824 825
  /* set audio codec in streaminfo */
  entry = gst_props_entry_new("audiocodec", GST_PROPS_STRING(codecname));
  gst_props_add_entry(avi_demux->streaminfo->properties, entry);
  g_free(codecname);
Wim Taymans's avatar
Wim Taymans committed
826

Ronald S. Bultje's avatar
Ronald S. Bultje committed
827
  gst_pad_try_set_caps(srcpad, capslist);
828 829
  gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
  gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
Wim Taymans's avatar
Wim Taymans committed
830
  gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
831
  gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
Wim Taymans's avatar
Wim Taymans committed
832
  gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
833
  gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
Wim Taymans's avatar
Wim Taymans committed
834 835 836 837 838 839

  stream = &avi_demux->stream[avi_demux->num_streams];
  stream->pad = srcpad;
  gst_pad_set_element_private (srcpad, stream);
  avi_demux->num_streams++;
  avi_demux->num_a_streams++;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
840

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
841 842 843 844 845 846 847 848
  gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
}

static void 
gst_avi_demux_strf_iavs (GstAviDemux *avi_demux)
{
  gst_riff_strf_iavs *strf;
  GstPad *srcpad;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
849
  GstCaps *newcaps = NULL, *capslist = NULL;
Wim Taymans's avatar
Wim Taymans committed
850
  avi_stream_context *stream;
851 852
  GstByteStream  *bs = avi_demux->bs;
  guint32 got_bytes;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
853

854 855 856
  got_bytes = gst_bytestream_peek_bytes (bs, (guint8 **)&strf, sizeof (gst_riff_strf_iavs));
  if (got_bytes != sizeof (gst_riff_strf_iavs))
    return;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
857 858 859 860 861 862 863 864 865 866 867 868

  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context iavs");
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVAAuxSrc   %08x", GUINT32_FROM_LE (strf->DVAAuxSrc));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVAAuxCtl   %08x", GUINT32_FROM_LE (strf->DVAAuxCtl));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVAAuxSrc1  %08x", GUINT32_FROM_LE (strf->DVAAuxSrc1));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVAAuxCtl1  %08x", GUINT32_FROM_LE (strf->DVAAuxCtl1));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVVAuxSrc   %08x", GUINT32_FROM_LE (strf->DVVAuxSrc));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVVAuxCtl   %08x", GUINT32_FROM_LE (strf->DVVAuxCtl));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVReserved1 %08x", GUINT32_FROM_LE (strf->DVReserved1));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVReserved2 %08x", GUINT32_FROM_LE (strf->DVReserved2));

  srcpad =  gst_pad_new_from_template (
869
		  GST_PAD_TEMPLATE_GET (src_video_templ), g_strdup_printf ("video_%02d", 
Wim Taymans's avatar
Wim Taymans committed
870
			  avi_demux->num_v_streams));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
871

Ronald S. Bultje's avatar
Ronald S. Bultje committed
872 873
  capslist = gst_caps_append(NULL, GST_CAPS_NEW (
			  "avidemux_video_src",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
874 875 876 877 878 879 880 881 882
			  "video/avi",
			    "format",    	GST_PROPS_STRING ("strf_iavs"),
                              "DVAAuxSrc", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxSrc)),
                              "DVAAuxCtl", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxCtl)),
                              "DVAAuxSrc1", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxSrc1)),
                              "DVAAuxCtl1", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxCtl1)),
                              "DVVAuxSrc", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->DVVAuxSrc)),
                              "DVVAuxCtl", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->DVVAuxCtl)),
                              "DVReserved1", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->DVReserved1)),
883 884
                              "DVReserved2", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->DVReserved2))
			 ));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
885

Ronald S. Bultje's avatar
Ronald S. Bultje committed
886 887 888 889 890 891 892 893
  newcaps = gst_caps_new ("avi_type_dv", 
                          "video/dv", 
                          gst_props_new (
                            "format",		GST_PROPS_STRING ("NTSC"), /* FIXME??? */
                            NULL));

  if (newcaps) capslist = gst_caps_append(capslist, newcaps);

Ronald S. Bultje's avatar
Ronald S. Bultje committed
894
  gst_pad_try_set_caps(srcpad, capslist);
895 896
  gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
  gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
Wim Taymans's avatar
Wim Taymans committed
897
  gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
898
  gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
Wim Taymans's avatar
Wim Taymans committed
899
  gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
900
  gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
Wim Taymans's avatar
Wim Taymans committed
901 902 903 904 905 906

  stream = &avi_demux->stream[avi_demux->num_streams];
  stream->pad = srcpad;
  gst_pad_set_element_private (srcpad, stream);
  avi_demux->num_streams++;
  avi_demux->num_v_streams++;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
907

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
908 909 910 911
  gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
}

static void
Wim Taymans's avatar
Wim Taymans committed
912 913
gst_avi_debug_entry (const gchar *prefix, gst_avi_index_entry *entry)
{
914 915
  GST_DEBUG (0, "%s: %05d %d %08llx %05d %14" G_GINT64_FORMAT " %08x %08x (%d) %08x", prefix, entry->index_nr, entry->stream_nr, 
		  (unsigned long long)entry->bytes_before, entry->frames_before, entry->ts, entry->flags, entry->offset, 
Wim Taymans's avatar
Wim Taymans committed
916
		  entry->offset, entry->size);
Wim Taymans's avatar
Wim Taymans committed
917 918 919 920
}

static void
gst_avi_demux_parse_index (GstAviDemux *avi_demux,
Wim Taymans's avatar
Wim Taymans committed
921
		          gulong filepos, gulong offset)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
922 923 924
{
  GstBuffer *buf;
  gulong index_size;
925
  guint32 got_bytes;
Wim Taymans's avatar
Wim Taymans committed
926 927
  gint i;
  gst_riff_index_entry *entry;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
928

Wim Taymans's avatar
Wim Taymans committed
929
  if (!gst_bytestream_seek (avi_demux->bs, filepos + offset, GST_SEEK_METHOD_SET)) {
Wim Taymans's avatar
Wim Taymans committed
930 931 932
    GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not seek to index");
    return;
  }
933
  do {
Wim Taymans's avatar
Wim Taymans committed
934 935 936
    guint32 remaining;
    GstEvent *event;
  
937 938 939 940
    got_bytes = gst_bytestream_read (avi_demux->bs, &buf, 8);
    if (got_bytes == 8)
      break;

Wim Taymans's avatar
Wim Taymans committed
941
    gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
942
    gst_event_unref (event);
943
  } while (TRUE);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
944

Wim Taymans's avatar
Wim Taymans committed
945
  if (GST_BUFFER_OFFSET (buf) != filepos + offset || GST_BUFFER_SIZE (buf) != 8) {
946
    GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not get index, got %" G_GINT64_FORMAT " %d, expected %ld", 
Wim Taymans's avatar
Wim Taymans committed
947
		    GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf), filepos + offset);
Wim Taymans's avatar
Wim Taymans committed
948
    goto end;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
949 950 951 952
  }

  if (gst_riff_fourcc_to_id (GST_BUFFER_DATA (buf)) != GST_RIFF_TAG_idx1) {
    GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: no index found");
Wim Taymans's avatar
Wim Taymans committed
953
    goto end;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
954 955 956
  }

  index_size = GUINT32_FROM_LE(*(guint32 *)(GST_BUFFER_DATA (buf) + 4));
Wim Taymans's avatar
Wim Taymans committed
957
  gst_buffer_unref (buf);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
958

959 960
  gst_bytestream_size_hint (avi_demux->bs, index_size);

961
  got_bytes = gst_bytestream_read (avi_demux->bs, &buf, index_size);
Wim Taymans's avatar
Wim Taymans committed
962 963 964 965
  if (got_bytes < index_size) {
    GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: error reading index");
    goto end;
  }
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
966 967 968 969

  avi_demux->index_size = index_size/sizeof(gst_riff_index_entry);
  GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: index size %lu", avi_demux->index_size);

Wim Taymans's avatar
Wim Taymans committed
970 971 972 973 974 975 976 977
  avi_demux->index_entries = g_malloc (avi_demux->index_size * sizeof (gst_avi_index_entry));

  entry = (gst_riff_index_entry *) GST_BUFFER_DATA (buf);

  for (i = 0; i < avi_demux->index_size; i++) {
    avi_stream_context *stream;
    gint stream_nr;
    gst_avi_index_entry *target = &avi_demux->index_entries[i];
978
    GstFormat format;
Wim Taymans's avatar
Wim Taymans committed
979 980

    stream_nr = CHUNKID_TO_STREAMNR (entry[i].id);
Wim Taymans's avatar
Wim Taymans committed
981 982 983 984 985
    if (stream_nr > avi_demux->num_streams || stream_nr < 0) {
      avi_demux->index_entries[i].stream_nr = -1;
      continue;
    }

Wim Taymans's avatar
Wim Taymans committed
986 987 988 989 990 991 992
    target->stream_nr = stream_nr;
    stream = &avi_demux->stream[stream_nr];

    target->index_nr = i;
    target->flags    = entry[i].flags;
    target->size     = entry[i].size;
    target->offset   = entry[i].offset;
Wim Taymans's avatar
Wim Taymans committed
993

994 995 996
    /* figure out if the index is 0 based or relative to the MOVI start */
    if (i == 0) {
      if (target->offset < filepos)
997
	avi_demux->index_offset = filepos - 4;
998 999 1000 1001
      else
	avi_demux->index_offset = 0;
    }

Wim Taymans's avatar
Wim Taymans committed
1002 1003 1004
    target->bytes_before = stream->total_bytes;
    target->frames_before = stream->total_frames;

1005
    format = GST_FORMAT_TIME;
Wim Taymans's avatar
Wim Taymans committed
1006
    if (stream->strh.type == GST_RIFF_FCC_auds) {
Wim Taymans's avatar
Wim Taymans committed
1007 1008
      /* all audio frames are keyframes */
      target->flags |= GST_RIFF_IF_KEYFRAME;
1009
    }
Wim Taymans's avatar
Wim Taymans committed
1010
      
1011
    /* constant rate stream */
1012
    if (stream->strh.samplesize && stream->strh.type == GST_RIFF_FCC_auds) {
1013 1014
      gst_pad_convert (stream->pad, GST_FORMAT_BYTES, stream->total_bytes,
		                 &format, &target->ts);
Wim Taymans's avatar
Wim Taymans committed
1015
    }
1016
    /* VBR stream */
Wim Taymans's avatar
Wim Taymans committed
1017
    else {
1018 1019
      gst_pad_convert (stream->pad, GST_FORMAT_UNITS, stream->total_frames,
		                 &format, &target->ts);
Wim Taymans's avatar
Wim Taymans committed
1020 1021 1022 1023 1024 1025
    }
    gst_avi_debug_entry ("index", target);

    stream->total_bytes += target->size;
    stream->total_frames++;
  }
1026 1027 1028 1029
  for (i = 0; i < avi_demux->num_streams; i++) {
    avi_stream_context *stream;

    stream = &avi_demux->stream[i];
1030
    GST_DEBUG (GST_CAT_PLUGIN_INFO, "stream %i: %d frames, %" G_GINT64_FORMAT " bytes", 
1031
	       i, stream->total_frames, stream->total_bytes);
1032
  }
Wim Taymans's avatar
Wim Taymans committed
1033
  gst_buffer_unref (buf);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1034

Wim Taymans's avatar
Wim Taymans committed
1035
end:
1036
  GST_DEBUG (GST_CAT_PLUGIN_INFO, "index offset at %08lx", filepos);
Wim Taymans's avatar
Wim Taymans committed
1037 1038

  if (!gst_bytestream_seek (avi_demux->bs, filepos, GST_SEEK_METHOD_SET)) {
Wim Taymans's avatar
Wim Taymans committed
1039 1040
    GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not seek back to movi");
    return;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1041 1042 1043
  }
}

Wim Taymans's avatar
Wim Taymans committed
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
static gst_avi_index_entry*
gst_avi_demux_index_next (GstAviDemux *avi_demux, gint stream_nr, gint start, guint32 flags)
{
  gint i;
  gst_avi_index_entry *entry = NULL;

  for (i = start; i < avi_demux->index_size; i++) {
    entry = &avi_demux->index_entries[i];

    if (entry->stream_nr == stream_nr && (entry->flags & flags) == flags) {
      break;
    }
  }

  return entry;
}

static gst_avi_index_entry*
gst_avi_demux_index_entry_for_time (GstAviDemux *avi_demux, gint stream_nr, guint64 time, guint32 flags)
{
  gst_avi_index_entry *entry = NULL, *last_entry = NULL;
  gint i;

  i = -1;
  do {
    entry = gst_avi_demux_index_next (avi_demux, stream_nr, i + 1, flags);
    if (!entry)
      return NULL;

    i = entry->index_nr;

    if (entry->ts <= time) {
      last_entry = entry;
    }
  }
  while (entry->ts <= time);

  return last_entry;
}

1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
static const GstFormat*
gst_avi_demux_get_src_formats (GstPad *pad) 
{
  avi_stream_context *stream = gst_pad_get_element_private (pad);

  static const GstFormat src_a_formats[] = {
    GST_FORMAT_TIME,
    GST_FORMAT_BYTES,
    GST_FORMAT_UNITS,
    0
  };
  static const GstFormat src_v_formats[] = {
    GST_FORMAT_TIME,
    GST_FORMAT_UNITS,
    0
  };

  return (stream->strh.type == GST_RIFF_FCC_auds ? src_a_formats : src_v_formats);
}

1104 1105 1106 1107 1108 1109 1110
static gboolean
gst_avi_demux_src_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
	                   GstFormat *dest_format, gint64 *dest_value)
{
  gboolean res = TRUE;
  avi_stream_context *stream = gst_pad_get_element_private (pad);

1111
  if (stream->strh.type != GST_RIFF_FCC_auds &&