gst_plugins_good/gst/avi/gstavidemux.c
author hgs
Wed, 24 Mar 2010 18:04:17 -0500
changeset 16 8e837d1bf446
permissions -rw-r--r--
201009
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
16
hgs
parents:
diff changeset
     1
/* GStreamer
hgs
parents:
diff changeset
     2
 * Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
hgs
parents:
diff changeset
     3
 * Copyright (C) <2006> Nokia Corporation (contact <stefan.kost@nokia.com>)
hgs
parents:
diff changeset
     4
 *
hgs
parents:
diff changeset
     5
 * This library is free software; you can redistribute it and/or
hgs
parents:
diff changeset
     6
 * modify it under the terms of the GNU Library General Public
hgs
parents:
diff changeset
     7
 * License as published by the Free Software Foundation; either
hgs
parents:
diff changeset
     8
 * version 2 of the License, or (at your option) any later version.
hgs
parents:
diff changeset
     9
 *
hgs
parents:
diff changeset
    10
 * This library is distributed in the hope that it will be useful,
hgs
parents:
diff changeset
    11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
hgs
parents:
diff changeset
    12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
hgs
parents:
diff changeset
    13
 * Library General Public License for more details.
hgs
parents:
diff changeset
    14
 *
hgs
parents:
diff changeset
    15
 * You should have received a copy of the GNU Library General Public
hgs
parents:
diff changeset
    16
 * License along with this library; if not, write to the
hgs
parents:
diff changeset
    17
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
hgs
parents:
diff changeset
    18
 * Boston, MA 02111-1307, USA.
hgs
parents:
diff changeset
    19
 */
hgs
parents:
diff changeset
    20
/* Element-Checklist-Version: 5 */
hgs
parents:
diff changeset
    21
hgs
parents:
diff changeset
    22
/**
hgs
parents:
diff changeset
    23
 * SECTION:element-avidemux
hgs
parents:
diff changeset
    24
 *
hgs
parents:
diff changeset
    25
 * Demuxes an .avi file into raw or compressed audio and/or video streams.
hgs
parents:
diff changeset
    26
 *
hgs
parents:
diff changeset
    27
 * This element supports both push and pull-based scheduling, depending on the
hgs
parents:
diff changeset
    28
 * capabilities of the upstream elements.
hgs
parents:
diff changeset
    29
 *
hgs
parents:
diff changeset
    30
 * <refsect2>
hgs
parents:
diff changeset
    31
 * <title>Example launch line</title>
hgs
parents:
diff changeset
    32
 * |[
hgs
parents:
diff changeset
    33
 * gst-launch filesrc location=test.avi ! avidemux name=demux  demux.audio_00 ! decodebin ! audioconvert ! audioresample ! autoaudiosink   demux.video_00 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink
hgs
parents:
diff changeset
    34
 * ]| Play (parse and decode) an .avi file and try to output it to
hgs
parents:
diff changeset
    35
 * an automatically detected soundcard and videosink. If the AVI file contains
hgs
parents:
diff changeset
    36
 * compressed audio or video data, this will only work if you have the
hgs
parents:
diff changeset
    37
 * right decoder elements/plugins installed.
hgs
parents:
diff changeset
    38
 * </refsect2>
hgs
parents:
diff changeset
    39
 *
hgs
parents:
diff changeset
    40
 * Last reviewed on 2006-12-29 (0.10.6)
hgs
parents:
diff changeset
    41
 */
hgs
parents:
diff changeset
    42
hgs
parents:
diff changeset
    43
#ifdef HAVE_CONFIG_H
hgs
parents:
diff changeset
    44
#include "config.h"
hgs
parents:
diff changeset
    45
#endif
hgs
parents:
diff changeset
    46
hgs
parents:
diff changeset
    47
#include <string.h>
hgs
parents:
diff changeset
    48
hgs
parents:
diff changeset
    49
#include "gst/riff/riff-media.h"
hgs
parents:
diff changeset
    50
#include "gstavidemux.h"
hgs
parents:
diff changeset
    51
#include "avi-ids.h"
hgs
parents:
diff changeset
    52
#include <gst/gst-i18n-plugin.h>
hgs
parents:
diff changeset
    53
#include <gst/base/gstadapter.h>
hgs
parents:
diff changeset
    54
hgs
parents:
diff changeset
    55
GST_DEBUG_CATEGORY_STATIC (avidemux_debug);
hgs
parents:
diff changeset
    56
#define GST_CAT_DEFAULT avidemux_debug
hgs
parents:
diff changeset
    57
hgs
parents:
diff changeset
    58
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_EVENT);
hgs
parents:
diff changeset
    59
hgs
parents:
diff changeset
    60
static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
hgs
parents:
diff changeset
    61
    GST_PAD_SINK,
hgs
parents:
diff changeset
    62
    GST_PAD_ALWAYS,
hgs
parents:
diff changeset
    63
    GST_STATIC_CAPS ("video/x-msvideo")
hgs
parents:
diff changeset
    64
    );
hgs
parents:
diff changeset
    65
hgs
parents:
diff changeset
    66
static void gst_avi_demux_base_init (GstAviDemuxClass * klass);
hgs
parents:
diff changeset
    67
static void gst_avi_demux_class_init (GstAviDemuxClass * klass);
hgs
parents:
diff changeset
    68
static void gst_avi_demux_init (GstAviDemux * avi);
hgs
parents:
diff changeset
    69
static void gst_avi_demux_finalize (GObject * object);
hgs
parents:
diff changeset
    70
hgs
parents:
diff changeset
    71
static void gst_avi_demux_reset (GstAviDemux * avi);
hgs
parents:
diff changeset
    72
hgs
parents:
diff changeset
    73
#if 0
hgs
parents:
diff changeset
    74
static const GstEventMask *gst_avi_demux_get_event_mask (GstPad * pad);
hgs
parents:
diff changeset
    75
#endif
hgs
parents:
diff changeset
    76
static gboolean gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event);
hgs
parents:
diff changeset
    77
static gboolean gst_avi_demux_handle_sink_event (GstPad * pad,
hgs
parents:
diff changeset
    78
    GstEvent * event);
hgs
parents:
diff changeset
    79
static gboolean gst_avi_demux_push_event (GstAviDemux * avi, GstEvent * event);
hgs
parents:
diff changeset
    80
hgs
parents:
diff changeset
    81
#if 0
hgs
parents:
diff changeset
    82
static const GstFormat *gst_avi_demux_get_src_formats (GstPad * pad);
hgs
parents:
diff changeset
    83
#endif
hgs
parents:
diff changeset
    84
static const GstQueryType *gst_avi_demux_get_src_query_types (GstPad * pad);
hgs
parents:
diff changeset
    85
static gboolean gst_avi_demux_handle_src_query (GstPad * pad, GstQuery * query);
hgs
parents:
diff changeset
    86
static gboolean gst_avi_demux_src_convert (GstPad * pad, GstFormat src_format,
hgs
parents:
diff changeset
    87
    gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
hgs
parents:
diff changeset
    88
hgs
parents:
diff changeset
    89
static gboolean gst_avi_demux_do_seek (GstAviDemux * avi, GstSegment * segment);
hgs
parents:
diff changeset
    90
static gboolean gst_avi_demux_handle_seek (GstAviDemux * avi, GstPad * pad,
hgs
parents:
diff changeset
    91
    GstEvent * event);
hgs
parents:
diff changeset
    92
static void gst_avi_demux_loop (GstPad * pad);
hgs
parents:
diff changeset
    93
static gboolean gst_avi_demux_sink_activate (GstPad * sinkpad);
hgs
parents:
diff changeset
    94
static gboolean gst_avi_demux_sink_activate_pull (GstPad * sinkpad,
hgs
parents:
diff changeset
    95
    gboolean active);
hgs
parents:
diff changeset
    96
static gboolean gst_avi_demux_activate_push (GstPad * pad, gboolean active);
hgs
parents:
diff changeset
    97
static GstFlowReturn gst_avi_demux_chain (GstPad * pad, GstBuffer * buf);
hgs
parents:
diff changeset
    98
hgs
parents:
diff changeset
    99
static GstStateChangeReturn gst_avi_demux_change_state (GstElement * element,
hgs
parents:
diff changeset
   100
    GstStateChange transition);
hgs
parents:
diff changeset
   101
hgs
parents:
diff changeset
   102
static GstElementClass *parent_class = NULL;
hgs
parents:
diff changeset
   103
hgs
parents:
diff changeset
   104
/* GObject methods */
hgs
parents:
diff changeset
   105
hgs
parents:
diff changeset
   106
GType
hgs
parents:
diff changeset
   107
gst_avi_demux_get_type (void)
hgs
parents:
diff changeset
   108
{
hgs
parents:
diff changeset
   109
  static GType avi_demux_type = 0;
hgs
parents:
diff changeset
   110
hgs
parents:
diff changeset
   111
  if (!avi_demux_type) {
hgs
parents:
diff changeset
   112
    static const GTypeInfo avi_demux_info = {
hgs
parents:
diff changeset
   113
      sizeof (GstAviDemuxClass),
hgs
parents:
diff changeset
   114
      (GBaseInitFunc) gst_avi_demux_base_init,
hgs
parents:
diff changeset
   115
      NULL,
hgs
parents:
diff changeset
   116
      (GClassInitFunc) gst_avi_demux_class_init,
hgs
parents:
diff changeset
   117
      NULL,
hgs
parents:
diff changeset
   118
      NULL,
hgs
parents:
diff changeset
   119
      sizeof (GstAviDemux),
hgs
parents:
diff changeset
   120
      0,
hgs
parents:
diff changeset
   121
      (GInstanceInitFunc) gst_avi_demux_init,
hgs
parents:
diff changeset
   122
    };
hgs
parents:
diff changeset
   123
hgs
parents:
diff changeset
   124
    avi_demux_type =
hgs
parents:
diff changeset
   125
        g_type_register_static (GST_TYPE_ELEMENT,
hgs
parents:
diff changeset
   126
        "GstAviDemux", &avi_demux_info, 0);
hgs
parents:
diff changeset
   127
  }
hgs
parents:
diff changeset
   128
hgs
parents:
diff changeset
   129
  return avi_demux_type;
hgs
parents:
diff changeset
   130
}
hgs
parents:
diff changeset
   131
hgs
parents:
diff changeset
   132
static void
hgs
parents:
diff changeset
   133
gst_avi_demux_base_init (GstAviDemuxClass * klass)
hgs
parents:
diff changeset
   134
{
hgs
parents:
diff changeset
   135
  static const GstElementDetails gst_avi_demux_details =
hgs
parents:
diff changeset
   136
      GST_ELEMENT_DETAILS ("Avi demuxer",
hgs
parents:
diff changeset
   137
      "Codec/Demuxer",
hgs
parents:
diff changeset
   138
      "Demultiplex an avi file into audio and video",
hgs
parents:
diff changeset
   139
      "Erik Walthinsen <omega@cse.ogi.edu>\n"
hgs
parents:
diff changeset
   140
      "Wim Taymans <wim.taymans@chello.be>\n"
hgs
parents:
diff changeset
   141
      "Ronald Bultje <rbultje@ronald.bitfreak.net>\n"
hgs
parents:
diff changeset
   142
      "Thijs Vermeir <thijsvermeir@gmail.com>");
hgs
parents:
diff changeset
   143
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
hgs
parents:
diff changeset
   144
  GstPadTemplate *videosrctempl, *audiosrctempl, *subsrctempl;
hgs
parents:
diff changeset
   145
  GstCaps *audcaps, *vidcaps, *subcaps;
hgs
parents:
diff changeset
   146
hgs
parents:
diff changeset
   147
  audcaps = gst_riff_create_audio_template_caps ();
hgs
parents:
diff changeset
   148
  gst_caps_append (audcaps, gst_caps_new_simple ("audio/x-avi-unknown", NULL));
hgs
parents:
diff changeset
   149
  audiosrctempl = gst_pad_template_new ("audio_%02d",
hgs
parents:
diff changeset
   150
      GST_PAD_SRC, GST_PAD_SOMETIMES, audcaps);
hgs
parents:
diff changeset
   151
hgs
parents:
diff changeset
   152
  vidcaps = gst_riff_create_video_template_caps ();
hgs
parents:
diff changeset
   153
  gst_caps_append (vidcaps, gst_riff_create_iavs_template_caps ());
hgs
parents:
diff changeset
   154
  gst_caps_append (vidcaps, gst_caps_new_simple ("video/x-avi-unknown", NULL));
hgs
parents:
diff changeset
   155
  videosrctempl = gst_pad_template_new ("video_%02d",
hgs
parents:
diff changeset
   156
      GST_PAD_SRC, GST_PAD_SOMETIMES, vidcaps);
hgs
parents:
diff changeset
   157
hgs
parents:
diff changeset
   158
  subcaps = gst_caps_new_simple ("application/x-subtitle-avi", NULL);
hgs
parents:
diff changeset
   159
  subsrctempl = gst_pad_template_new ("subtitle_%02d",
hgs
parents:
diff changeset
   160
      GST_PAD_SRC, GST_PAD_SOMETIMES, subcaps);
hgs
parents:
diff changeset
   161
  gst_element_class_add_pad_template (element_class, audiosrctempl);
hgs
parents:
diff changeset
   162
  gst_element_class_add_pad_template (element_class, videosrctempl);
hgs
parents:
diff changeset
   163
  gst_element_class_add_pad_template (element_class, subsrctempl);
hgs
parents:
diff changeset
   164
  gst_element_class_add_pad_template (element_class,
hgs
parents:
diff changeset
   165
      gst_static_pad_template_get (&sink_templ));
hgs
parents:
diff changeset
   166
  gst_element_class_set_details (element_class, &gst_avi_demux_details);
hgs
parents:
diff changeset
   167
}
hgs
parents:
diff changeset
   168
hgs
parents:
diff changeset
   169
static void
hgs
parents:
diff changeset
   170
gst_avi_demux_class_init (GstAviDemuxClass * klass)
hgs
parents:
diff changeset
   171
{
hgs
parents:
diff changeset
   172
  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
hgs
parents:
diff changeset
   173
  GObjectClass *gobject_class = (GObjectClass *) klass;
hgs
parents:
diff changeset
   174
hgs
parents:
diff changeset
   175
  GST_DEBUG_CATEGORY_INIT (avidemux_debug, "avidemux",
hgs
parents:
diff changeset
   176
      0, "Demuxer for AVI streams");
hgs
parents:
diff changeset
   177
hgs
parents:
diff changeset
   178
  parent_class = g_type_class_peek_parent (klass);
hgs
parents:
diff changeset
   179
hgs
parents:
diff changeset
   180
  gobject_class->finalize = gst_avi_demux_finalize;
hgs
parents:
diff changeset
   181
  gstelement_class->change_state =
hgs
parents:
diff changeset
   182
      GST_DEBUG_FUNCPTR (gst_avi_demux_change_state);
hgs
parents:
diff changeset
   183
}
hgs
parents:
diff changeset
   184
hgs
parents:
diff changeset
   185
static void
hgs
parents:
diff changeset
   186
gst_avi_demux_init (GstAviDemux * avi)
hgs
parents:
diff changeset
   187
{
hgs
parents:
diff changeset
   188
  avi->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
hgs
parents:
diff changeset
   189
  gst_pad_set_activate_function (avi->sinkpad,
hgs
parents:
diff changeset
   190
      GST_DEBUG_FUNCPTR (gst_avi_demux_sink_activate));
hgs
parents:
diff changeset
   191
  gst_pad_set_activatepull_function (avi->sinkpad,
hgs
parents:
diff changeset
   192
      GST_DEBUG_FUNCPTR (gst_avi_demux_sink_activate_pull));
hgs
parents:
diff changeset
   193
  gst_pad_set_activatepush_function (avi->sinkpad,
hgs
parents:
diff changeset
   194
      GST_DEBUG_FUNCPTR (gst_avi_demux_activate_push));
hgs
parents:
diff changeset
   195
  gst_pad_set_chain_function (avi->sinkpad,
hgs
parents:
diff changeset
   196
      GST_DEBUG_FUNCPTR (gst_avi_demux_chain));
hgs
parents:
diff changeset
   197
  gst_pad_set_event_function (avi->sinkpad,
hgs
parents:
diff changeset
   198
      GST_DEBUG_FUNCPTR (gst_avi_demux_handle_sink_event));
hgs
parents:
diff changeset
   199
  gst_element_add_pad (GST_ELEMENT (avi), avi->sinkpad);
hgs
parents:
diff changeset
   200
hgs
parents:
diff changeset
   201
  avi->adapter = gst_adapter_new ();
hgs
parents:
diff changeset
   202
hgs
parents:
diff changeset
   203
  gst_avi_demux_reset (avi);
hgs
parents:
diff changeset
   204
}
hgs
parents:
diff changeset
   205
hgs
parents:
diff changeset
   206
static void
hgs
parents:
diff changeset
   207
gst_avi_demux_finalize (GObject * object)
hgs
parents:
diff changeset
   208
{
hgs
parents:
diff changeset
   209
  GstAviDemux *avi = GST_AVI_DEMUX (object);
hgs
parents:
diff changeset
   210
hgs
parents:
diff changeset
   211
  GST_DEBUG ("AVI: finalize");
hgs
parents:
diff changeset
   212
hgs
parents:
diff changeset
   213
  g_object_unref (avi->adapter);
hgs
parents:
diff changeset
   214
hgs
parents:
diff changeset
   215
  G_OBJECT_CLASS (parent_class)->finalize (object);
hgs
parents:
diff changeset
   216
}
hgs
parents:
diff changeset
   217
hgs
parents:
diff changeset
   218
static void
hgs
parents:
diff changeset
   219
gst_avi_demux_reset (GstAviDemux * avi)
hgs
parents:
diff changeset
   220
{
hgs
parents:
diff changeset
   221
  gint i;
hgs
parents:
diff changeset
   222
hgs
parents:
diff changeset
   223
  GST_DEBUG ("AVI: reset");
hgs
parents:
diff changeset
   224
hgs
parents:
diff changeset
   225
  for (i = 0; i < avi->num_streams; i++) {
hgs
parents:
diff changeset
   226
    g_free (avi->stream[i].strh);
hgs
parents:
diff changeset
   227
    g_free (avi->stream[i].strf.data);
hgs
parents:
diff changeset
   228
    if (avi->stream[i].name)
hgs
parents:
diff changeset
   229
      g_free (avi->stream[i].name);
hgs
parents:
diff changeset
   230
    if (avi->stream[i].initdata)
hgs
parents:
diff changeset
   231
      gst_buffer_unref (avi->stream[i].initdata);
hgs
parents:
diff changeset
   232
    if (avi->stream[i].extradata)
hgs
parents:
diff changeset
   233
      gst_buffer_unref (avi->stream[i].extradata);
hgs
parents:
diff changeset
   234
    if (avi->stream[i].pad) {
hgs
parents:
diff changeset
   235
      gst_pad_set_active (avi->stream[i].pad, FALSE);
hgs
parents:
diff changeset
   236
      gst_element_remove_pad (GST_ELEMENT (avi), avi->stream[i].pad);
hgs
parents:
diff changeset
   237
    }
hgs
parents:
diff changeset
   238
    if (avi->stream[i].taglist) {
hgs
parents:
diff changeset
   239
      gst_tag_list_free (avi->stream[i].taglist);
hgs
parents:
diff changeset
   240
      avi->stream[i].taglist = NULL;
hgs
parents:
diff changeset
   241
    }
hgs
parents:
diff changeset
   242
  }
hgs
parents:
diff changeset
   243
  memset (&avi->stream, 0, sizeof (avi->stream));
hgs
parents:
diff changeset
   244
hgs
parents:
diff changeset
   245
  avi->header_state = GST_AVI_DEMUX_HEADER_TAG_LIST;
hgs
parents:
diff changeset
   246
  avi->num_streams = 0;
hgs
parents:
diff changeset
   247
  avi->num_v_streams = 0;
hgs
parents:
diff changeset
   248
  avi->num_a_streams = 0;
hgs
parents:
diff changeset
   249
  avi->num_t_streams = 0;
hgs
parents:
diff changeset
   250
hgs
parents:
diff changeset
   251
  avi->state = GST_AVI_DEMUX_START;
hgs
parents:
diff changeset
   252
  avi->offset = 0;
hgs
parents:
diff changeset
   253
hgs
parents:
diff changeset
   254
  g_free (avi->index_entries);
hgs
parents:
diff changeset
   255
  avi->index_entries = NULL;
hgs
parents:
diff changeset
   256
  avi->index_size = 0;
hgs
parents:
diff changeset
   257
  avi->index_offset = 0;
hgs
parents:
diff changeset
   258
  avi->current_entry = 0;
hgs
parents:
diff changeset
   259
  g_free (avi->avih);
hgs
parents:
diff changeset
   260
  avi->avih = NULL;
hgs
parents:
diff changeset
   261
hgs
parents:
diff changeset
   262
  if (avi->seek_event) {
hgs
parents:
diff changeset
   263
    gst_event_unref (avi->seek_event);
hgs
parents:
diff changeset
   264
    avi->seek_event = NULL;
hgs
parents:
diff changeset
   265
  }
hgs
parents:
diff changeset
   266
hgs
parents:
diff changeset
   267
  if (avi->globaltags)
hgs
parents:
diff changeset
   268
    gst_tag_list_free (avi->globaltags);
hgs
parents:
diff changeset
   269
  avi->globaltags = NULL;
hgs
parents:
diff changeset
   270
hgs
parents:
diff changeset
   271
  avi->got_tags = TRUE;         /* we always want to push global tags */
hgs
parents:
diff changeset
   272
  avi->have_eos = FALSE;
hgs
parents:
diff changeset
   273
hgs
parents:
diff changeset
   274
  gst_adapter_clear (avi->adapter);
hgs
parents:
diff changeset
   275
hgs
parents:
diff changeset
   276
  gst_segment_init (&avi->segment, GST_FORMAT_TIME);
hgs
parents:
diff changeset
   277
}
hgs
parents:
diff changeset
   278
hgs
parents:
diff changeset
   279
/* Index helper */
hgs
parents:
diff changeset
   280
static gst_avi_index_entry *
hgs
parents:
diff changeset
   281
gst_avi_demux_index_last (GstAviDemux * avi, gint stream_nr)
hgs
parents:
diff changeset
   282
{
hgs
parents:
diff changeset
   283
  gint i;
hgs
parents:
diff changeset
   284
  gst_avi_index_entry *result = NULL;
hgs
parents:
diff changeset
   285
hgs
parents:
diff changeset
   286
  for (i = avi->index_size - 1; i >= 0; i--) {
hgs
parents:
diff changeset
   287
    if (avi->index_entries[i].stream_nr == stream_nr) {
hgs
parents:
diff changeset
   288
      result = &avi->index_entries[i];
hgs
parents:
diff changeset
   289
      break;
hgs
parents:
diff changeset
   290
    }
hgs
parents:
diff changeset
   291
  }
hgs
parents:
diff changeset
   292
  return result;
hgs
parents:
diff changeset
   293
}
hgs
parents:
diff changeset
   294
hgs
parents:
diff changeset
   295
static gst_avi_index_entry *
hgs
parents:
diff changeset
   296
gst_avi_demux_index_next (GstAviDemux * avi, gint stream_nr, gint last,
hgs
parents:
diff changeset
   297
    guchar flags)
hgs
parents:
diff changeset
   298
{
hgs
parents:
diff changeset
   299
  gint i;
hgs
parents:
diff changeset
   300
  gst_avi_index_entry *result = NULL, *entry;
hgs
parents:
diff changeset
   301
hgs
parents:
diff changeset
   302
  for (i = last + 1; i < avi->index_size; i++) {
hgs
parents:
diff changeset
   303
    entry = &avi->index_entries[i];
hgs
parents:
diff changeset
   304
hgs
parents:
diff changeset
   305
    if (entry->stream_nr != stream_nr)
hgs
parents:
diff changeset
   306
      continue;
hgs
parents:
diff changeset
   307
hgs
parents:
diff changeset
   308
    if ((entry->flags & flags) == flags) {
hgs
parents:
diff changeset
   309
      result = entry;
hgs
parents:
diff changeset
   310
      break;
hgs
parents:
diff changeset
   311
    }
hgs
parents:
diff changeset
   312
  }
hgs
parents:
diff changeset
   313
  return result;
hgs
parents:
diff changeset
   314
}
hgs
parents:
diff changeset
   315
hgs
parents:
diff changeset
   316
static gst_avi_index_entry *
hgs
parents:
diff changeset
   317
gst_avi_demux_index_prev (GstAviDemux * avi, gint stream_nr, gint last,
hgs
parents:
diff changeset
   318
    guchar flags)
hgs
parents:
diff changeset
   319
{
hgs
parents:
diff changeset
   320
  gint i;
hgs
parents:
diff changeset
   321
  gst_avi_index_entry *result = NULL, *entry;
hgs
parents:
diff changeset
   322
hgs
parents:
diff changeset
   323
  for (i = last - 1; i >= 0; i--) {
hgs
parents:
diff changeset
   324
    entry = &avi->index_entries[i];
hgs
parents:
diff changeset
   325
hgs
parents:
diff changeset
   326
    if (entry->stream_nr != stream_nr)
hgs
parents:
diff changeset
   327
      continue;
hgs
parents:
diff changeset
   328
hgs
parents:
diff changeset
   329
    if ((entry->flags & flags) == flags) {
hgs
parents:
diff changeset
   330
      result = entry;
hgs
parents:
diff changeset
   331
      break;
hgs
parents:
diff changeset
   332
    }
hgs
parents:
diff changeset
   333
  }
hgs
parents:
diff changeset
   334
  return result;
hgs
parents:
diff changeset
   335
}
hgs
parents:
diff changeset
   336
hgs
parents:
diff changeset
   337
static gint
hgs
parents:
diff changeset
   338
gst_avi_demux_index_entry_search (gst_avi_index_entry * entry, guint64 * time)
hgs
parents:
diff changeset
   339
{
hgs
parents:
diff changeset
   340
  if (entry->ts < *time)
hgs
parents:
diff changeset
   341
    return -1;
hgs
parents:
diff changeset
   342
  else if (entry->ts > *time)
hgs
parents:
diff changeset
   343
    return 1;
hgs
parents:
diff changeset
   344
  return 0;
hgs
parents:
diff changeset
   345
}
hgs
parents:
diff changeset
   346
hgs
parents:
diff changeset
   347
/*
hgs
parents:
diff changeset
   348
 * gst_avi_index_entry:
hgs
parents:
diff changeset
   349
 * @avi: Avi object
hgs
parents:
diff changeset
   350
 * @stream_nr: stream number
hgs
parents:
diff changeset
   351
 * @time: seek time position
hgs
parents:
diff changeset
   352
 *
hgs
parents:
diff changeset
   353
 * Finds the index entry which time is less or equal than the requested time.
hgs
parents:
diff changeset
   354
 *
hgs
parents:
diff changeset
   355
 * Returns: the found index entry or %NULL
hgs
parents:
diff changeset
   356
 */
hgs
parents:
diff changeset
   357
static gst_avi_index_entry *
hgs
parents:
diff changeset
   358
gst_avi_demux_index_entry_for_time (GstAviDemux * avi,
hgs
parents:
diff changeset
   359
    gint stream_nr, guint64 time)
hgs
parents:
diff changeset
   360
{
hgs
parents:
diff changeset
   361
  gst_avi_index_entry *entry = NULL;
hgs
parents:
diff changeset
   362
  guint n;
hgs
parents:
diff changeset
   363
hgs
parents:
diff changeset
   364
  GST_LOG_OBJECT (avi, "stream_nr:%d , time:%" GST_TIME_FORMAT,
hgs
parents:
diff changeset
   365
      stream_nr, GST_TIME_ARGS (time));
hgs
parents:
diff changeset
   366
hgs
parents:
diff changeset
   367
  entry = gst_util_array_binary_search (avi->index_entries,
hgs
parents:
diff changeset
   368
      avi->index_size,
hgs
parents:
diff changeset
   369
      sizeof (gst_avi_index_entry),
hgs
parents:
diff changeset
   370
      (GCompareDataFunc) gst_avi_demux_index_entry_search,
hgs
parents:
diff changeset
   371
      GST_SEARCH_MODE_BEFORE, &time, NULL);
hgs
parents:
diff changeset
   372
hgs
parents:
diff changeset
   373
  n = entry - avi->index_entries;
hgs
parents:
diff changeset
   374
  if (entry == NULL) {
hgs
parents:
diff changeset
   375
    entry = &avi->index_entries[0];
hgs
parents:
diff changeset
   376
    n = 0;
hgs
parents:
diff changeset
   377
    while (entry->stream_nr != stream_nr && n < avi->index_size - 1) {
hgs
parents:
diff changeset
   378
      n++;
hgs
parents:
diff changeset
   379
      entry = &avi->index_entries[n];
hgs
parents:
diff changeset
   380
    }
hgs
parents:
diff changeset
   381
  } else if (entry->stream_nr != stream_nr) {
hgs
parents:
diff changeset
   382
    while (entry->stream_nr != stream_nr && n > 0) {
hgs
parents:
diff changeset
   383
      n--;
hgs
parents:
diff changeset
   384
      entry = &avi->index_entries[n];
hgs
parents:
diff changeset
   385
    }
hgs
parents:
diff changeset
   386
  }
hgs
parents:
diff changeset
   387
hgs
parents:
diff changeset
   388
  GST_LOG_OBJECT (avi,
hgs
parents:
diff changeset
   389
      "best at entry %u / ts:%" GST_TIME_FORMAT " / dur:%" GST_TIME_FORMAT
hgs
parents:
diff changeset
   390
      " flags:%02x", n, GST_TIME_ARGS (entry->ts), GST_TIME_ARGS (entry->dur),
hgs
parents:
diff changeset
   391
      entry->flags);
hgs
parents:
diff changeset
   392
hgs
parents:
diff changeset
   393
  return entry;
hgs
parents:
diff changeset
   394
}
hgs
parents:
diff changeset
   395
hgs
parents:
diff changeset
   396
/* GstElement methods */
hgs
parents:
diff changeset
   397
hgs
parents:
diff changeset
   398
#if 0
hgs
parents:
diff changeset
   399
static const GstFormat *
hgs
parents:
diff changeset
   400
gst_avi_demux_get_src_formats (GstPad * pad)
hgs
parents:
diff changeset
   401
{
hgs
parents:
diff changeset
   402
  avi_stream_context *stream = gst_pad_get_element_private (pad);
hgs
parents:
diff changeset
   403
hgs
parents:
diff changeset
   404
  static const GstFormat src_a_formats[] = {
hgs
parents:
diff changeset
   405
    GST_FORMAT_TIME,
hgs
parents:
diff changeset
   406
    GST_FORMAT_BYTES,
hgs
parents:
diff changeset
   407
    GST_FORMAT_DEFAULT,
hgs
parents:
diff changeset
   408
    0
hgs
parents:
diff changeset
   409
  };
hgs
parents:
diff changeset
   410
  static const GstFormat src_v_formats[] = {
hgs
parents:
diff changeset
   411
    GST_FORMAT_TIME,
hgs
parents:
diff changeset
   412
    GST_FORMAT_DEFAULT,
hgs
parents:
diff changeset
   413
    0
hgs
parents:
diff changeset
   414
  };
hgs
parents:
diff changeset
   415
hgs
parents:
diff changeset
   416
  return (stream->strh->type == GST_RIFF_FCC_auds ?
hgs
parents:
diff changeset
   417
      src_a_formats : src_v_formats);
hgs
parents:
diff changeset
   418
}
hgs
parents:
diff changeset
   419
#endif
hgs
parents:
diff changeset
   420
hgs
parents:
diff changeset
   421
/* assumes stream->strf.auds->av_bps != 0 */
hgs
parents:
diff changeset
   422
static inline GstClockTime
hgs
parents:
diff changeset
   423
avi_stream_convert_bytes_to_time_unchecked (avi_stream_context * stream,
hgs
parents:
diff changeset
   424
    guint64 bytes)
hgs
parents:
diff changeset
   425
{
hgs
parents:
diff changeset
   426
  return gst_util_uint64_scale (bytes, GST_SECOND, stream->strf.auds->av_bps);
hgs
parents:
diff changeset
   427
}
hgs
parents:
diff changeset
   428
hgs
parents:
diff changeset
   429
/* assumes stream->strh->rate != 0 */
hgs
parents:
diff changeset
   430
static inline GstClockTime
hgs
parents:
diff changeset
   431
avi_stream_convert_frames_to_time_unchecked (avi_stream_context * stream,
hgs
parents:
diff changeset
   432
    guint64 frames)
hgs
parents:
diff changeset
   433
{
hgs
parents:
diff changeset
   434
  return gst_util_uint64_scale (frames, stream->strh->scale * GST_SECOND,
hgs
parents:
diff changeset
   435
      stream->strh->rate);
hgs
parents:
diff changeset
   436
}
hgs
parents:
diff changeset
   437
hgs
parents:
diff changeset
   438
static gboolean
hgs
parents:
diff changeset
   439
gst_avi_demux_src_convert (GstPad * pad,
hgs
parents:
diff changeset
   440
    GstFormat src_format,
hgs
parents:
diff changeset
   441
    gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
hgs
parents:
diff changeset
   442
{
hgs
parents:
diff changeset
   443
  avi_stream_context *stream = gst_pad_get_element_private (pad);
hgs
parents:
diff changeset
   444
  gboolean res = TRUE;
hgs
parents:
diff changeset
   445
hgs
parents:
diff changeset
   446
  GST_LOG_OBJECT (pad,
hgs
parents:
diff changeset
   447
      "Received  src_format:%s, src_value:%" G_GUINT64_FORMAT
hgs
parents:
diff changeset
   448
      ", dest_format:%s", gst_format_get_name (src_format), src_value,
hgs
parents:
diff changeset
   449
      gst_format_get_name (*dest_format));
hgs
parents:
diff changeset
   450
hgs
parents:
diff changeset
   451
  if (G_UNLIKELY (src_format == *dest_format)) {
hgs
parents:
diff changeset
   452
    *dest_value = src_value;
hgs
parents:
diff changeset
   453
    goto done;
hgs
parents:
diff changeset
   454
  }
hgs
parents:
diff changeset
   455
  if (G_UNLIKELY (!stream->strh || !stream->strf.data)) {
hgs
parents:
diff changeset
   456
    res = FALSE;
hgs
parents:
diff changeset
   457
    goto done;
hgs
parents:
diff changeset
   458
  }
hgs
parents:
diff changeset
   459
  if (G_UNLIKELY (stream->strh->type == GST_RIFF_FCC_vids &&
hgs
parents:
diff changeset
   460
          (src_format == GST_FORMAT_BYTES
hgs
parents:
diff changeset
   461
              || *dest_format == GST_FORMAT_BYTES))) {
hgs
parents:
diff changeset
   462
    res = FALSE;
hgs
parents:
diff changeset
   463
    goto done;
hgs
parents:
diff changeset
   464
  }
hgs
parents:
diff changeset
   465
hgs
parents:
diff changeset
   466
  switch (src_format) {
hgs
parents:
diff changeset
   467
    case GST_FORMAT_TIME:
hgs
parents:
diff changeset
   468
      switch (*dest_format) {
hgs
parents:
diff changeset
   469
        case GST_FORMAT_BYTES:
hgs
parents:
diff changeset
   470
          *dest_value = gst_util_uint64_scale (src_value,
hgs
parents:
diff changeset
   471
              (guint64) stream->strf.auds->av_bps, GST_SECOND);
hgs
parents:
diff changeset
   472
          break;
hgs
parents:
diff changeset
   473
        case GST_FORMAT_DEFAULT:
hgs
parents:
diff changeset
   474
        {
hgs
parents:
diff changeset
   475
          gdouble error;
hgs
parents:
diff changeset
   476
hgs
parents:
diff changeset
   477
          *dest_value = gst_util_uint64_scale (src_value, stream->strh->rate,
hgs
parents:
diff changeset
   478
              stream->strh->scale * GST_SECOND);
hgs
parents:
diff changeset
   479
hgs
parents:
diff changeset
   480
          /* Attempt to round to nearest integer: if the difference is more
hgs
parents:
diff changeset
   481
           * than 0.5 (less than -0.5), it means that gst_util_uint64_scale()
hgs
parents:
diff changeset
   482
           * just truncated an integer, while it had to be rounded
hgs
parents:
diff changeset
   483
           */
hgs
parents:
diff changeset
   484
          error = *dest_value * GST_SECOND -
hgs
parents:
diff changeset
   485
              src_value * stream->strh->rate / stream->strh->scale;
hgs
parents:
diff changeset
   486
          if (error <= -0.5)
hgs
parents:
diff changeset
   487
            *dest_value += 1;
hgs
parents:
diff changeset
   488
          break;
hgs
parents:
diff changeset
   489
        }
hgs
parents:
diff changeset
   490
        default:
hgs
parents:
diff changeset
   491
          res = FALSE;
hgs
parents:
diff changeset
   492
          break;
hgs
parents:
diff changeset
   493
      }
hgs
parents:
diff changeset
   494
      break;
hgs
parents:
diff changeset
   495
    case GST_FORMAT_BYTES:
hgs
parents:
diff changeset
   496
      switch (*dest_format) {
hgs
parents:
diff changeset
   497
        case GST_FORMAT_TIME:
hgs
parents:
diff changeset
   498
          if (stream->strf.auds->av_bps != 0) {
hgs
parents:
diff changeset
   499
            *dest_value = avi_stream_convert_bytes_to_time_unchecked (stream,
hgs
parents:
diff changeset
   500
                src_value);
hgs
parents:
diff changeset
   501
          } else
hgs
parents:
diff changeset
   502
            res = FALSE;
hgs
parents:
diff changeset
   503
          break;
hgs
parents:
diff changeset
   504
        default:
hgs
parents:
diff changeset
   505
          res = FALSE;
hgs
parents:
diff changeset
   506
          break;
hgs
parents:
diff changeset
   507
      }
hgs
parents:
diff changeset
   508
      break;
hgs
parents:
diff changeset
   509
    case GST_FORMAT_DEFAULT:
hgs
parents:
diff changeset
   510
      switch (*dest_format) {
hgs
parents:
diff changeset
   511
        case GST_FORMAT_TIME:
hgs
parents:
diff changeset
   512
          *dest_value =
hgs
parents:
diff changeset
   513
              avi_stream_convert_frames_to_time_unchecked (stream, src_value);
hgs
parents:
diff changeset
   514
          break;
hgs
parents:
diff changeset
   515
        default:
hgs
parents:
diff changeset
   516
          res = FALSE;
hgs
parents:
diff changeset
   517
          break;
hgs
parents:
diff changeset
   518
      }
hgs
parents:
diff changeset
   519
      break;
hgs
parents:
diff changeset
   520
    default:
hgs
parents:
diff changeset
   521
      res = FALSE;
hgs
parents:
diff changeset
   522
  }
hgs
parents:
diff changeset
   523
hgs
parents:
diff changeset
   524
done:
hgs
parents:
diff changeset
   525
  GST_LOG_OBJECT (pad,
hgs
parents:
diff changeset
   526
      "Returning res:%d dest_format:%s dest_value:%" G_GUINT64_FORMAT, res,
hgs
parents:
diff changeset
   527
      gst_format_get_name (*dest_format), *dest_value);
hgs
parents:
diff changeset
   528
  return res;
hgs
parents:
diff changeset
   529
}
hgs
parents:
diff changeset
   530
hgs
parents:
diff changeset
   531
static const GstQueryType *
hgs
parents:
diff changeset
   532
gst_avi_demux_get_src_query_types (GstPad * pad)
hgs
parents:
diff changeset
   533
{
hgs
parents:
diff changeset
   534
  static const GstQueryType src_types[] = {
hgs
parents:
diff changeset
   535
    GST_QUERY_POSITION,
hgs
parents:
diff changeset
   536
    GST_QUERY_DURATION,
hgs
parents:
diff changeset
   537
    GST_QUERY_SEEKING,
hgs
parents:
diff changeset
   538
    GST_QUERY_CONVERT,
hgs
parents:
diff changeset
   539
    0
hgs
parents:
diff changeset
   540
  };
hgs
parents:
diff changeset
   541
hgs
parents:
diff changeset
   542
  return src_types;
hgs
parents:
diff changeset
   543
}
hgs
parents:
diff changeset
   544
hgs
parents:
diff changeset
   545
static gboolean
hgs
parents:
diff changeset
   546
gst_avi_demux_handle_src_query (GstPad * pad, GstQuery * query)
hgs
parents:
diff changeset
   547
{
hgs
parents:
diff changeset
   548
  gboolean res = TRUE;
hgs
parents:
diff changeset
   549
  GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));
hgs
parents:
diff changeset
   550
hgs
parents:
diff changeset
   551
  avi_stream_context *stream = gst_pad_get_element_private (pad);
hgs
parents:
diff changeset
   552
hgs
parents:
diff changeset
   553
  if (!stream->strh || !stream->strf.data)
hgs
parents:
diff changeset
   554
    return gst_pad_query_default (pad, query);
hgs
parents:
diff changeset
   555
hgs
parents:
diff changeset
   556
  switch (GST_QUERY_TYPE (query)) {
hgs
parents:
diff changeset
   557
    case GST_QUERY_POSITION:{
hgs
parents:
diff changeset
   558
      gint64 pos = 0;
hgs
parents:
diff changeset
   559
hgs
parents:
diff changeset
   560
      GST_DEBUG ("pos query for stream %d: frames %d, bytes %" G_GUINT64_FORMAT,
hgs
parents:
diff changeset
   561
          stream->num, stream->current_frame, stream->current_byte);
hgs
parents:
diff changeset
   562
hgs
parents:
diff changeset
   563
      if (stream->strh->type == GST_RIFF_FCC_auds) {
hgs
parents:
diff changeset
   564
        if (stream->is_vbr) {
hgs
parents:
diff changeset
   565
          /* VBR */
hgs
parents:
diff changeset
   566
          pos = gst_util_uint64_scale ((gint64) stream->current_frame *
hgs
parents:
diff changeset
   567
              stream->strh->scale, GST_SECOND, (guint64) stream->strh->rate);
hgs
parents:
diff changeset
   568
          GST_DEBUG_OBJECT (avi, "VBR convert frame %u, time %"
hgs
parents:
diff changeset
   569
              GST_TIME_FORMAT, stream->current_frame, GST_TIME_ARGS (pos));
hgs
parents:
diff changeset
   570
        } else if (stream->strf.auds->av_bps != 0) {
hgs
parents:
diff changeset
   571
          /* CBR */
hgs
parents:
diff changeset
   572
          pos = gst_util_uint64_scale (stream->current_byte, GST_SECOND,
hgs
parents:
diff changeset
   573
              (guint64) stream->strf.auds->av_bps);
hgs
parents:
diff changeset
   574
          GST_DEBUG_OBJECT (avi,
hgs
parents:
diff changeset
   575
              "CBR convert bytes %" G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT,
hgs
parents:
diff changeset
   576
              stream->current_byte, GST_TIME_ARGS (pos));
hgs
parents:
diff changeset
   577
        } else if (stream->total_frames != 0 && stream->total_bytes != 0) {
hgs
parents:
diff changeset
   578
          /* calculate timestamps based on percentage of length */
hgs
parents:
diff changeset
   579
          guint64 xlen = avi->avih->us_frame *
hgs
parents:
diff changeset
   580
              avi->avih->tot_frames * GST_USECOND;
hgs
parents:
diff changeset
   581
hgs
parents:
diff changeset
   582
          if (stream->is_vbr) {
hgs
parents:
diff changeset
   583
            pos = gst_util_uint64_scale (xlen, stream->current_frame,
hgs
parents:
diff changeset
   584
                stream->total_frames);
hgs
parents:
diff changeset
   585
            GST_DEBUG_OBJECT (avi, "VBR perc convert frame %u, time %"
hgs
parents:
diff changeset
   586
                GST_TIME_FORMAT, stream->current_frame, GST_TIME_ARGS (pos));
hgs
parents:
diff changeset
   587
          } else {
hgs
parents:
diff changeset
   588
            pos = gst_util_uint64_scale (xlen, stream->current_byte,
hgs
parents:
diff changeset
   589
                stream->total_bytes);
hgs
parents:
diff changeset
   590
            GST_DEBUG_OBJECT (avi, "CBR perc convert bytes %" G_GUINT64_FORMAT
hgs
parents:
diff changeset
   591
                ", time %" GST_TIME_FORMAT, stream->current_byte,
hgs
parents:
diff changeset
   592
                GST_TIME_ARGS (pos));
hgs
parents:
diff changeset
   593
          }
hgs
parents:
diff changeset
   594
        } else {
hgs
parents:
diff changeset
   595
          /* we don't know */
hgs
parents:
diff changeset
   596
          res = FALSE;
hgs
parents:
diff changeset
   597
        }
hgs
parents:
diff changeset
   598
      } else {
hgs
parents:
diff changeset
   599
        if (stream->strh->rate != 0) {
hgs
parents:
diff changeset
   600
          pos = gst_util_uint64_scale ((guint64) stream->current_frame *
hgs
parents:
diff changeset
   601
              stream->strh->scale, GST_SECOND, (guint64) stream->strh->rate);
hgs
parents:
diff changeset
   602
        } else {
hgs
parents:
diff changeset
   603
          pos = stream->current_frame * avi->avih->us_frame * GST_USECOND;
hgs
parents:
diff changeset
   604
        }
hgs
parents:
diff changeset
   605
      }
hgs
parents:
diff changeset
   606
      if (res) {
hgs
parents:
diff changeset
   607
        GST_DEBUG ("pos query : %" GST_TIME_FORMAT, GST_TIME_ARGS (pos));
hgs
parents:
diff changeset
   608
        gst_query_set_position (query, GST_FORMAT_TIME, pos);
hgs
parents:
diff changeset
   609
      } else
hgs
parents:
diff changeset
   610
        GST_WARNING ("pos query failed");
hgs
parents:
diff changeset
   611
      break;
hgs
parents:
diff changeset
   612
    }
hgs
parents:
diff changeset
   613
    case GST_QUERY_DURATION:
hgs
parents:
diff changeset
   614
    {
hgs
parents:
diff changeset
   615
      GstFormat fmt;
hgs
parents:
diff changeset
   616
hgs
parents:
diff changeset
   617
      if (stream->strh->type != GST_RIFF_FCC_auds &&
hgs
parents:
diff changeset
   618
          stream->strh->type != GST_RIFF_FCC_vids) {
hgs
parents:
diff changeset
   619
        res = FALSE;
hgs
parents:
diff changeset
   620
        break;
hgs
parents:
diff changeset
   621
      }
hgs
parents:
diff changeset
   622
hgs
parents:
diff changeset
   623
      gst_query_parse_duration (query, &fmt, NULL);
hgs
parents:
diff changeset
   624
hgs
parents:
diff changeset
   625
      switch (fmt) {
hgs
parents:
diff changeset
   626
        case GST_FORMAT_TIME:
hgs
parents:
diff changeset
   627
          gst_query_set_duration (query, fmt, stream->duration);
hgs
parents:
diff changeset
   628
          break;
hgs
parents:
diff changeset
   629
        case GST_FORMAT_DEFAULT:
hgs
parents:
diff changeset
   630
        {
hgs
parents:
diff changeset
   631
          gint64 dur;
hgs
parents:
diff changeset
   632
          GST_DEBUG_OBJECT (query, "total frames is %" G_GUINT32_FORMAT,
hgs
parents:
diff changeset
   633
              stream->total_frames);
hgs
parents:
diff changeset
   634
hgs
parents:
diff changeset
   635
          if (stream->total_frames >= 0)
hgs
parents:
diff changeset
   636
            gst_query_set_duration (query, fmt, stream->total_frames);
hgs
parents:
diff changeset
   637
          else if (gst_pad_query_convert (pad, GST_FORMAT_TIME,
hgs
parents:
diff changeset
   638
                  stream->duration, &fmt, &dur))
hgs
parents:
diff changeset
   639
            gst_query_set_duration (query, fmt, dur);
hgs
parents:
diff changeset
   640
          break;
hgs
parents:
diff changeset
   641
        }
hgs
parents:
diff changeset
   642
        default:
hgs
parents:
diff changeset
   643
          res = FALSE;
hgs
parents:
diff changeset
   644
          break;
hgs
parents:
diff changeset
   645
      }
hgs
parents:
diff changeset
   646
      break;
hgs
parents:
diff changeset
   647
    }
hgs
parents:
diff changeset
   648
    case GST_QUERY_SEEKING:{
hgs
parents:
diff changeset
   649
      GstFormat fmt;
hgs
parents:
diff changeset
   650
hgs
parents:
diff changeset
   651
      gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
hgs
parents:
diff changeset
   652
      if (fmt == GST_FORMAT_TIME) {
hgs
parents:
diff changeset
   653
        gboolean seekable = TRUE;
hgs
parents:
diff changeset
   654
hgs
parents:
diff changeset
   655
        if (avi->streaming) {
hgs
parents:
diff changeset
   656
          seekable = FALSE;
hgs
parents:
diff changeset
   657
        } else {
hgs
parents:
diff changeset
   658
          if (avi->index_entries == NULL) {
hgs
parents:
diff changeset
   659
            seekable = FALSE;
hgs
parents:
diff changeset
   660
            /* FIXME: when building index_entried, count keyframes
hgs
parents:
diff changeset
   661
               if (!(avi->key_frame_ct > 1))
hgs
parents:
diff changeset
   662
               seekable = FALSE;
hgs
parents:
diff changeset
   663
             */
hgs
parents:
diff changeset
   664
          }
hgs
parents:
diff changeset
   665
        }
hgs
parents:
diff changeset
   666
hgs
parents:
diff changeset
   667
        gst_query_set_seeking (query, GST_FORMAT_TIME, seekable,
hgs
parents:
diff changeset
   668
            0, stream->duration);
hgs
parents:
diff changeset
   669
        res = TRUE;
hgs
parents:
diff changeset
   670
      }
hgs
parents:
diff changeset
   671
      break;
hgs
parents:
diff changeset
   672
    }
hgs
parents:
diff changeset
   673
    case GST_QUERY_CONVERT:{
hgs
parents:
diff changeset
   674
      GstFormat src_fmt, dest_fmt;
hgs
parents:
diff changeset
   675
      gint64 src_val, dest_val;
hgs
parents:
diff changeset
   676
hgs
parents:
diff changeset
   677
      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
hgs
parents:
diff changeset
   678
      if ((res = gst_avi_demux_src_convert (pad, src_fmt, src_val, &dest_fmt,
hgs
parents:
diff changeset
   679
                  &dest_val)))
hgs
parents:
diff changeset
   680
        gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
hgs
parents:
diff changeset
   681
      else
hgs
parents:
diff changeset
   682
        res = gst_pad_query_default (pad, query);
hgs
parents:
diff changeset
   683
      break;
hgs
parents:
diff changeset
   684
    }
hgs
parents:
diff changeset
   685
    default:
hgs
parents:
diff changeset
   686
      res = gst_pad_query_default (pad, query);
hgs
parents:
diff changeset
   687
      break;
hgs
parents:
diff changeset
   688
  }
hgs
parents:
diff changeset
   689
hgs
parents:
diff changeset
   690
  gst_object_unref (avi);
hgs
parents:
diff changeset
   691
  return res;
hgs
parents:
diff changeset
   692
}
hgs
parents:
diff changeset
   693
hgs
parents:
diff changeset
   694
#if 0
hgs
parents:
diff changeset
   695
static const GstEventMask *
hgs
parents:
diff changeset
   696
gst_avi_demux_get_event_mask (GstPad * pad)
hgs
parents:
diff changeset
   697
{
hgs
parents:
diff changeset
   698
  static const GstEventMask masks[] = {
hgs
parents:
diff changeset
   699
    {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT},
hgs
parents:
diff changeset
   700
    {0,}
hgs
parents:
diff changeset
   701
  };
hgs
parents:
diff changeset
   702
hgs
parents:
diff changeset
   703
  return masks;
hgs
parents:
diff changeset
   704
}
hgs
parents:
diff changeset
   705
#endif
hgs
parents:
diff changeset
   706
hgs
parents:
diff changeset
   707
static gboolean
hgs
parents:
diff changeset
   708
gst_avi_demux_handle_sink_event (GstPad * pad, GstEvent * event)
hgs
parents:
diff changeset
   709
{
hgs
parents:
diff changeset
   710
  gboolean res = TRUE;
hgs
parents:
diff changeset
   711
  GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));
hgs
parents:
diff changeset
   712
hgs
parents:
diff changeset
   713
  GST_DEBUG_OBJECT (avi,
hgs
parents:
diff changeset
   714
      "have event type %s: %p on sink pad", GST_EVENT_TYPE_NAME (event), event);
hgs
parents:
diff changeset
   715
hgs
parents:
diff changeset
   716
  switch (GST_EVENT_TYPE (event)) {
hgs
parents:
diff changeset
   717
    case GST_EVENT_NEWSEGMENT:
hgs
parents:
diff changeset
   718
      /* Drop NEWSEGMENT events, new ones are generated later */
hgs
parents:
diff changeset
   719
      gst_event_unref (event);
hgs
parents:
diff changeset
   720
      break;
hgs
parents:
diff changeset
   721
    case GST_EVENT_EOS:
hgs
parents:
diff changeset
   722
    {
hgs
parents:
diff changeset
   723
      if (avi->state != GST_AVI_DEMUX_MOVI) {
hgs
parents:
diff changeset
   724
        gst_event_unref (event);
hgs
parents:
diff changeset
   725
        GST_ELEMENT_ERROR (avi, STREAM, DEMUX,
hgs
parents:
diff changeset
   726
            (NULL), ("got eos and didn't receive a complete header object"));
hgs
parents:
diff changeset
   727
      } else if (!gst_avi_demux_push_event (avi, event)) {
hgs
parents:
diff changeset
   728
        GST_ELEMENT_ERROR (avi, STREAM, DEMUX,
hgs
parents:
diff changeset
   729
            (NULL), ("got eos but no streams (yet)"));
hgs
parents:
diff changeset
   730
      }
hgs
parents:
diff changeset
   731
      break;
hgs
parents:
diff changeset
   732
    }
hgs
parents:
diff changeset
   733
    default:
hgs
parents:
diff changeset
   734
      res = gst_pad_event_default (pad, event);
hgs
parents:
diff changeset
   735
      break;
hgs
parents:
diff changeset
   736
  }
hgs
parents:
diff changeset
   737
hgs
parents:
diff changeset
   738
  gst_object_unref (avi);
hgs
parents:
diff changeset
   739
hgs
parents:
diff changeset
   740
  return res;
hgs
parents:
diff changeset
   741
}
hgs
parents:
diff changeset
   742
hgs
parents:
diff changeset
   743
static gboolean
hgs
parents:
diff changeset
   744
gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event)
hgs
parents:
diff changeset
   745
{
hgs
parents:
diff changeset
   746
  gboolean res = TRUE;
hgs
parents:
diff changeset
   747
  GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));
hgs
parents:
diff changeset
   748
hgs
parents:
diff changeset
   749
  GST_DEBUG_OBJECT (avi,
hgs
parents:
diff changeset
   750
      "have event type %s: %p on src pad", GST_EVENT_TYPE_NAME (event), event);
hgs
parents:
diff changeset
   751
hgs
parents:
diff changeset
   752
  switch (GST_EVENT_TYPE (event)) {
hgs
parents:
diff changeset
   753
    case GST_EVENT_SEEK:
hgs
parents:
diff changeset
   754
      /* handle seeking only in pull mode */
hgs
parents:
diff changeset
   755
      if (!avi->streaming) {
hgs
parents:
diff changeset
   756
        res = gst_avi_demux_handle_seek (avi, pad, event);
hgs
parents:
diff changeset
   757
        gst_event_unref (event);
hgs
parents:
diff changeset
   758
      } else {
hgs
parents:
diff changeset
   759
        res = gst_pad_event_default (pad, event);
hgs
parents:
diff changeset
   760
      }
hgs
parents:
diff changeset
   761
      break;
hgs
parents:
diff changeset
   762
    case GST_EVENT_QOS:
hgs
parents:
diff changeset
   763
    case GST_EVENT_NAVIGATION:
hgs
parents:
diff changeset
   764
      res = FALSE;
hgs
parents:
diff changeset
   765
      gst_event_unref (event);
hgs
parents:
diff changeset
   766
      break;
hgs
parents:
diff changeset
   767
    default:
hgs
parents:
diff changeset
   768
      res = gst_pad_event_default (pad, event);
hgs
parents:
diff changeset
   769
      break;
hgs
parents:
diff changeset
   770
  }
hgs
parents:
diff changeset
   771
hgs
parents:
diff changeset
   772
  gst_object_unref (avi);
hgs
parents:
diff changeset
   773
hgs
parents:
diff changeset
   774
  return res;
hgs
parents:
diff changeset
   775
}
hgs
parents:
diff changeset
   776
hgs
parents:
diff changeset
   777
/* streaming helper (push) */
hgs
parents:
diff changeset
   778
hgs
parents:
diff changeset
   779
/*
hgs
parents:
diff changeset
   780
 * gst_avi_demux_peek_chunk_info:
hgs
parents:
diff changeset
   781
 * @avi: Avi object
hgs
parents:
diff changeset
   782
 * @tag: holder for tag
hgs
parents:
diff changeset
   783
 * @size: holder for tag size
hgs
parents:
diff changeset
   784
 *
hgs
parents:
diff changeset
   785
 * Peek next chunk info (tag and size)
hgs
parents:
diff changeset
   786
 *
hgs
parents:
diff changeset
   787
 * Returns: TRUE when one chunk info has been got
hgs
parents:
diff changeset
   788
 */
hgs
parents:
diff changeset
   789
static gboolean
hgs
parents:
diff changeset
   790
gst_avi_demux_peek_chunk_info (GstAviDemux * avi, guint32 * tag, guint32 * size)
hgs
parents:
diff changeset
   791
{
hgs
parents:
diff changeset
   792
  const guint8 *data = NULL;
hgs
parents:
diff changeset
   793
hgs
parents:
diff changeset
   794
  if (gst_adapter_available (avi->adapter) < 8) {
hgs
parents:
diff changeset
   795
    return FALSE;
hgs
parents:
diff changeset
   796
  }
hgs
parents:
diff changeset
   797
hgs
parents:
diff changeset
   798
  data = gst_adapter_peek (avi->adapter, 8);
hgs
parents:
diff changeset
   799
  *tag = GST_READ_UINT32_LE (data);
hgs
parents:
diff changeset
   800
  *size = GST_READ_UINT32_LE (data + 4);
hgs
parents:
diff changeset
   801
hgs
parents:
diff changeset
   802
  return TRUE;
hgs
parents:
diff changeset
   803
}
hgs
parents:
diff changeset
   804
hgs
parents:
diff changeset
   805
/*
hgs
parents:
diff changeset
   806
 * gst_avi_demux_peek_chunk:
hgs
parents:
diff changeset
   807
 * @avi: Avi object
hgs
parents:
diff changeset
   808
 * @tag: holder for tag
hgs
parents:
diff changeset
   809
 * @size: holder for tag size
hgs
parents:
diff changeset
   810
 *
hgs
parents:
diff changeset
   811
 * Peek enough data for one full chunk
hgs
parents:
diff changeset
   812
 *
hgs
parents:
diff changeset
   813
 * Returns: %TRUE when one chunk has been got
hgs
parents:
diff changeset
   814
 */
hgs
parents:
diff changeset
   815
static gboolean
hgs
parents:
diff changeset
   816
gst_avi_demux_peek_chunk (GstAviDemux * avi, guint32 * tag, guint32 * size)
hgs
parents:
diff changeset
   817
{
hgs
parents:
diff changeset
   818
  guint32 peek_size = 0;
hgs
parents:
diff changeset
   819
  gint available;
hgs
parents:
diff changeset
   820
hgs
parents:
diff changeset
   821
  if (!gst_avi_demux_peek_chunk_info (avi, tag, size)) {
hgs
parents:
diff changeset
   822
    return FALSE;
hgs
parents:
diff changeset
   823
  }
hgs
parents:
diff changeset
   824
  /* FIXME: shouldn't this check go to gst_avi_demux_peek_chunk_info() already */
hgs
parents:
diff changeset
   825
  if (!(*size) || (*size) == -1) {
hgs
parents:
diff changeset
   826
    GST_INFO ("Invalid chunk size %d for tag %" GST_FOURCC_FORMAT,
hgs
parents:
diff changeset
   827
        *size, GST_FOURCC_ARGS (*tag));
hgs
parents:
diff changeset
   828
    return FALSE;
hgs
parents:
diff changeset
   829
  }
hgs
parents:
diff changeset
   830
  peek_size = (*size + 1) & ~1;
hgs
parents:
diff changeset
   831
  available = gst_adapter_available (avi->adapter);
hgs
parents:
diff changeset
   832
hgs
parents:
diff changeset
   833
  GST_DEBUG ("Need to peek chunk of %d bytes to read chunk %" GST_FOURCC_FORMAT
hgs
parents:
diff changeset
   834
      ", %d bytes available", *size, GST_FOURCC_ARGS (*tag), available);
hgs
parents:
diff changeset
   835
hgs
parents:
diff changeset
   836
  if (available >= (8 + peek_size)) {
hgs
parents:
diff changeset
   837
    return TRUE;
hgs
parents:
diff changeset
   838
  } else {
hgs
parents:
diff changeset
   839
    return FALSE;
hgs
parents:
diff changeset
   840
  }
hgs
parents:
diff changeset
   841
}
hgs
parents:
diff changeset
   842
hgs
parents:
diff changeset
   843
/* AVI init */
hgs
parents:
diff changeset
   844
hgs
parents:
diff changeset
   845
/*
hgs
parents:
diff changeset
   846
 * gst_avi_demux_parse_file_header:
hgs
parents:
diff changeset
   847
 * @element: caller element (used for errors/debug).
hgs
parents:
diff changeset
   848
 * @buf: input data to be used for parsing.
hgs
parents:
diff changeset
   849
 *
hgs
parents:
diff changeset
   850
 * "Open" a RIFF/AVI file. The buffer should be at least 12
hgs
parents:
diff changeset
   851
 * bytes long. Takes ownership of @buf.
hgs
parents:
diff changeset
   852
 *
hgs
parents:
diff changeset
   853
 * Returns: TRUE if the file is a RIFF/AVI file, FALSE otherwise.
hgs
parents:
diff changeset
   854
 *          Throws an error, caller should error out (fatal).
hgs
parents:
diff changeset
   855
 */
hgs
parents:
diff changeset
   856
static gboolean
hgs
parents:
diff changeset
   857
gst_avi_demux_parse_file_header (GstElement * element, GstBuffer * buf)
hgs
parents:
diff changeset
   858
{
hgs
parents:
diff changeset
   859
  guint32 doctype;
hgs
parents:
diff changeset
   860
hgs
parents:
diff changeset
   861
  /* riff_parse posts an error */
hgs
parents:
diff changeset
   862
  if (!gst_riff_parse_file_header (element, buf, &doctype))
hgs
parents:
diff changeset
   863
    return FALSE;
hgs
parents:
diff changeset
   864
hgs
parents:
diff changeset
   865
  if (doctype != GST_RIFF_RIFF_AVI)
hgs
parents:
diff changeset
   866
    goto not_avi;
hgs
parents:
diff changeset
   867
hgs
parents:
diff changeset
   868
  return TRUE;
hgs
parents:
diff changeset
   869
hgs
parents:
diff changeset
   870
  /* ERRORS */
hgs
parents:
diff changeset
   871
not_avi:
hgs
parents:
diff changeset
   872
  {
hgs
parents:
diff changeset
   873
    GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
hgs
parents:
diff changeset
   874
        ("File is not an AVI file: %" GST_FOURCC_FORMAT,
hgs
parents:
diff changeset
   875
            GST_FOURCC_ARGS (doctype)));
hgs
parents:
diff changeset
   876
    return FALSE;
hgs
parents:
diff changeset
   877
  }
hgs
parents:
diff changeset
   878
}
hgs
parents:
diff changeset
   879
hgs
parents:
diff changeset
   880
/*
hgs
parents:
diff changeset
   881
 * Read AVI file tag when streaming
hgs
parents:
diff changeset
   882
 */
hgs
parents:
diff changeset
   883
static GstFlowReturn
hgs
parents:
diff changeset
   884
gst_avi_demux_stream_init_push (GstAviDemux * avi)
hgs
parents:
diff changeset
   885
{
hgs
parents:
diff changeset
   886
  if (gst_adapter_available (avi->adapter) >= 12) {
hgs
parents:
diff changeset
   887
    GstBuffer *tmp;
hgs
parents:
diff changeset
   888
hgs
parents:
diff changeset
   889
    tmp = gst_adapter_take_buffer (avi->adapter, 12);
hgs
parents:
diff changeset
   890
hgs
parents:
diff changeset
   891
    GST_DEBUG ("Parsing avi header");
hgs
parents:
diff changeset
   892
    if (!gst_avi_demux_parse_file_header (GST_ELEMENT (avi), tmp)) {
hgs
parents:
diff changeset
   893
      return GST_FLOW_ERROR;
hgs
parents:
diff changeset
   894
    }
hgs
parents:
diff changeset
   895
    GST_DEBUG ("header ok");
hgs
parents:
diff changeset
   896
    avi->offset += 12;
hgs
parents:
diff changeset
   897
hgs
parents:
diff changeset
   898
    avi->state = GST_AVI_DEMUX_HEADER;
hgs
parents:
diff changeset
   899
  }
hgs
parents:
diff changeset
   900
  return GST_FLOW_OK;
hgs
parents:
diff changeset
   901
}
hgs
parents:
diff changeset
   902
hgs
parents:
diff changeset
   903
/*
hgs
parents:
diff changeset
   904
 * Read AVI file tag
hgs
parents:
diff changeset
   905
 */
hgs
parents:
diff changeset
   906
static GstFlowReturn
hgs
parents:
diff changeset
   907
gst_avi_demux_stream_init_pull (GstAviDemux * avi)
hgs
parents:
diff changeset
   908
{
hgs
parents:
diff changeset
   909
  GstFlowReturn res;
hgs
parents:
diff changeset
   910
  GstBuffer *buf = NULL;
hgs
parents:
diff changeset
   911
hgs
parents:
diff changeset
   912
  res = gst_pad_pull_range (avi->sinkpad, avi->offset, 12, &buf);
hgs
parents:
diff changeset
   913
  if (res != GST_FLOW_OK)
hgs
parents:
diff changeset
   914
    return res;
hgs
parents:
diff changeset
   915
  else if (!gst_avi_demux_parse_file_header (GST_ELEMENT_CAST (avi), buf))
hgs
parents:
diff changeset
   916
    goto wrong_header;
hgs
parents:
diff changeset
   917
hgs
parents:
diff changeset
   918
  avi->offset += 12;
hgs
parents:
diff changeset
   919
hgs
parents:
diff changeset
   920
  return GST_FLOW_OK;
hgs
parents:
diff changeset
   921
hgs
parents:
diff changeset
   922
  /* ERRORS */
hgs
parents:
diff changeset
   923
wrong_header:
hgs
parents:
diff changeset
   924
  {
hgs
parents:
diff changeset
   925
    GST_DEBUG_OBJECT (avi, "error parsing file header");
hgs
parents:
diff changeset
   926
    return GST_FLOW_ERROR;
hgs
parents:
diff changeset
   927
  }
hgs
parents:
diff changeset
   928
}
hgs
parents:
diff changeset
   929
hgs
parents:
diff changeset
   930
/* AVI header handling */
hgs
parents:
diff changeset
   931
hgs
parents:
diff changeset
   932
/*
hgs
parents:
diff changeset
   933
 * gst_avi_demux_parse_avih:
hgs
parents:
diff changeset
   934
 * @element: caller element (used for errors/debug).
hgs
parents:
diff changeset
   935
 * @buf: input data to be used for parsing.
hgs
parents:
diff changeset
   936
 * @avih: pointer to structure (filled in by function) containing
hgs
parents:
diff changeset
   937
 *        stream information (such as flags, number of streams, etc.).
hgs
parents:
diff changeset
   938
 *
hgs
parents:
diff changeset
   939
 * Read 'avih' header. Discards buffer after use.
hgs
parents:
diff changeset
   940
 *
hgs
parents:
diff changeset
   941
 * Returns: TRUE on success, FALSE otherwise. Throws an error if
hgs
parents:
diff changeset
   942
 *          the header is invalid. The caller should error out
hgs
parents:
diff changeset
   943
 *          (fatal).
hgs
parents:
diff changeset
   944
 */
hgs
parents:
diff changeset
   945
static gboolean
hgs
parents:
diff changeset
   946
gst_avi_demux_parse_avih (GstElement * element,
hgs
parents:
diff changeset
   947
    GstBuffer * buf, gst_riff_avih ** _avih)
hgs
parents:
diff changeset
   948
{
hgs
parents:
diff changeset
   949
  gst_riff_avih *avih;
hgs
parents:
diff changeset
   950
hgs
parents:
diff changeset
   951
  if (buf == NULL)
hgs
parents:
diff changeset
   952
    goto no_buffer;
hgs
parents:
diff changeset
   953
hgs
parents:
diff changeset
   954
  if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_avih))
hgs
parents:
diff changeset
   955
    goto avih_too_small;
hgs
parents:
diff changeset
   956
hgs
parents:
diff changeset
   957
  avih = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
hgs
parents:
diff changeset
   958
hgs
parents:
diff changeset
   959
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
hgs
parents:
diff changeset
   960
  avih->us_frame = GUINT32_FROM_LE (avih->us_frame);
hgs
parents:
diff changeset
   961
  avih->max_bps = GUINT32_FROM_LE (avih->max_bps);
hgs
parents:
diff changeset
   962
  avih->pad_gran = GUINT32_FROM_LE (avih->pad_gran);
hgs
parents:
diff changeset
   963
  avih->flags = GUINT32_FROM_LE (avih->flags);
hgs
parents:
diff changeset
   964
  avih->tot_frames = GUINT32_FROM_LE (avih->tot_frames);
hgs
parents:
diff changeset
   965
  avih->init_frames = GUINT32_FROM_LE (avih->init_frames);
hgs
parents:
diff changeset
   966
  avih->streams = GUINT32_FROM_LE (avih->streams);
hgs
parents:
diff changeset
   967
  avih->bufsize = GUINT32_FROM_LE (avih->bufsize);
hgs
parents:
diff changeset
   968
  avih->width = GUINT32_FROM_LE (avih->width);
hgs
parents:
diff changeset
   969
  avih->height = GUINT32_FROM_LE (avih->height);
hgs
parents:
diff changeset
   970
  avih->scale = GUINT32_FROM_LE (avih->scale);
hgs
parents:
diff changeset
   971
  avih->rate = GUINT32_FROM_LE (avih->rate);
hgs
parents:
diff changeset
   972
  avih->start = GUINT32_FROM_LE (avih->start);
hgs
parents:
diff changeset
   973
  avih->length = GUINT32_FROM_LE (avih->length);
hgs
parents:
diff changeset
   974
#endif
hgs
parents:
diff changeset
   975
hgs
parents:
diff changeset
   976
  /* debug stuff */
hgs
parents:
diff changeset
   977
  GST_INFO_OBJECT (element, "avih tag found:");
hgs
parents:
diff changeset
   978
  GST_INFO_OBJECT (element, " us_frame    %u", avih->us_frame);
hgs
parents:
diff changeset
   979
  GST_INFO_OBJECT (element, " max_bps     %u", avih->max_bps);
hgs
parents:
diff changeset
   980
  GST_INFO_OBJECT (element, " pad_gran    %u", avih->pad_gran);
hgs
parents:
diff changeset
   981
  GST_INFO_OBJECT (element, " flags       0x%08x", avih->flags);
hgs
parents:
diff changeset
   982
  GST_INFO_OBJECT (element, " tot_frames  %u", avih->tot_frames);
hgs
parents:
diff changeset
   983
  GST_INFO_OBJECT (element, " init_frames %u", avih->init_frames);
hgs
parents:
diff changeset
   984
  GST_INFO_OBJECT (element, " streams     %u", avih->streams);
hgs
parents:
diff changeset
   985
  GST_INFO_OBJECT (element, " bufsize     %u", avih->bufsize);
hgs
parents:
diff changeset
   986
  GST_INFO_OBJECT (element, " width       %u", avih->width);
hgs
parents:
diff changeset
   987
  GST_INFO_OBJECT (element, " height      %u", avih->height);
hgs
parents:
diff changeset
   988
  GST_INFO_OBJECT (element, " scale       %u", avih->scale);
hgs
parents:
diff changeset
   989
  GST_INFO_OBJECT (element, " rate        %u", avih->rate);
hgs
parents:
diff changeset
   990
  GST_INFO_OBJECT (element, " start       %u", avih->start);
hgs
parents:
diff changeset
   991
  GST_INFO_OBJECT (element, " length      %u", avih->length);
hgs
parents:
diff changeset
   992
hgs
parents:
diff changeset
   993
  *_avih = avih;
hgs
parents:
diff changeset
   994
  gst_buffer_unref (buf);
hgs
parents:
diff changeset
   995
hgs
parents:
diff changeset
   996
  return TRUE;
hgs
parents:
diff changeset
   997
hgs
parents:
diff changeset
   998
  /* ERRORS */
hgs
parents:
diff changeset
   999
no_buffer:
hgs
parents:
diff changeset
  1000
  {
hgs
parents:
diff changeset
  1001
    GST_ELEMENT_ERROR (element, STREAM, DEMUX, (NULL), ("No buffer"));
hgs
parents:
diff changeset
  1002
    return FALSE;
hgs
parents:
diff changeset
  1003
  }
hgs
parents:
diff changeset
  1004
avih_too_small:
hgs
parents:
diff changeset
  1005
  {
hgs
parents:
diff changeset
  1006
    GST_ELEMENT_ERROR (element, STREAM, DEMUX, (NULL),
hgs
parents:
diff changeset
  1007
        ("Too small avih (%d available, %d needed)",
hgs
parents:
diff changeset
  1008
            GST_BUFFER_SIZE (buf), (int) sizeof (gst_riff_avih)));
hgs
parents:
diff changeset
  1009
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  1010
    return FALSE;
hgs
parents:
diff changeset
  1011
  }
hgs
parents:
diff changeset
  1012
}
hgs
parents:
diff changeset
  1013
hgs
parents:
diff changeset
  1014
/*
hgs
parents:
diff changeset
  1015
 * gst_avi_demux_parse_superindex:
hgs
parents:
diff changeset
  1016
 * @avi: caller element (used for debugging/errors).
hgs
parents:
diff changeset
  1017
 * @buf: input data to use for parsing.
hgs
parents:
diff changeset
  1018
 * @locations: locations in the file (byte-offsets) that contain
hgs
parents:
diff changeset
  1019
 *             the actual indexes (see get_avi_demux_parse_subindex()).
hgs
parents:
diff changeset
  1020
 *             The array ends with GST_BUFFER_OFFSET_NONE.
hgs
parents:
diff changeset
  1021
 *
hgs
parents:
diff changeset
  1022
 * Reads superindex (openDML-2 spec stuff) from the provided data.
hgs
parents:
diff changeset
  1023
 *
hgs
parents:
diff changeset
  1024
 * Returns: TRUE on success, FALSE otherwise. Indexes should be skipped
hgs
parents:
diff changeset
  1025
 *          on error, but they are not fatal.
hgs
parents:
diff changeset
  1026
 */
hgs
parents:
diff changeset
  1027
static gboolean
hgs
parents:
diff changeset
  1028
gst_avi_demux_parse_superindex (GstAviDemux * avi,
hgs
parents:
diff changeset
  1029
    GstBuffer * buf, guint64 ** _indexes)
hgs
parents:
diff changeset
  1030
{
hgs
parents:
diff changeset
  1031
  guint8 *data;
hgs
parents:
diff changeset
  1032
  guint16 bpe = 16;
hgs
parents:
diff changeset
  1033
  guint32 num, i;
hgs
parents:
diff changeset
  1034
  guint64 *indexes;
hgs
parents:
diff changeset
  1035
  guint size;
hgs
parents:
diff changeset
  1036
hgs
parents:
diff changeset
  1037
  *_indexes = NULL;
hgs
parents:
diff changeset
  1038
hgs
parents:
diff changeset
  1039
  size = buf ? GST_BUFFER_SIZE (buf) : 0;
hgs
parents:
diff changeset
  1040
  if (size < 24)
hgs
parents:
diff changeset
  1041
    goto too_small;
hgs
parents:
diff changeset
  1042
hgs
parents:
diff changeset
  1043
  data = GST_BUFFER_DATA (buf);
hgs
parents:
diff changeset
  1044
hgs
parents:
diff changeset
  1045
  /* check type of index. The opendml2 specs state that
hgs
parents:
diff changeset
  1046
   * there should be 4 dwords per array entry. Type can be
hgs
parents:
diff changeset
  1047
   * either frame or field (and we don't care). */
hgs
parents:
diff changeset
  1048
  if (GST_READ_UINT16_LE (data) != 4 ||
hgs
parents:
diff changeset
  1049
      (data[2] & 0xfe) != 0x0 || data[3] != 0x0) {
hgs
parents:
diff changeset
  1050
    GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  1051
        "Superindex for stream has unexpected "
hgs
parents:
diff changeset
  1052
        "size_entry %d (bytes) or flags 0x%02x/0x%02x",
hgs
parents:
diff changeset
  1053
        GST_READ_UINT16_LE (data), data[2], data[3]);
hgs
parents:
diff changeset
  1054
    bpe = GST_READ_UINT16_LE (data) * 4;
hgs
parents:
diff changeset
  1055
  }
hgs
parents:
diff changeset
  1056
  num = GST_READ_UINT32_LE (&data[4]);
hgs
parents:
diff changeset
  1057
hgs
parents:
diff changeset
  1058
  indexes = g_new (guint64, num + 1);
hgs
parents:
diff changeset
  1059
  for (i = 0; i < num; i++) {
hgs
parents:
diff changeset
  1060
    if (size < 24 + bpe * (i + 1))
hgs
parents:
diff changeset
  1061
      break;
hgs
parents:
diff changeset
  1062
    indexes[i] = GST_READ_UINT64_LE (&data[24 + bpe * i]);
hgs
parents:
diff changeset
  1063
  }
hgs
parents:
diff changeset
  1064
  indexes[i] = GST_BUFFER_OFFSET_NONE;
hgs
parents:
diff changeset
  1065
  *_indexes = indexes;
hgs
parents:
diff changeset
  1066
hgs
parents:
diff changeset
  1067
  gst_buffer_unref (buf);
hgs
parents:
diff changeset
  1068
hgs
parents:
diff changeset
  1069
  return TRUE;
hgs
parents:
diff changeset
  1070
hgs
parents:
diff changeset
  1071
  /* ERRORS */
hgs
parents:
diff changeset
  1072
too_small:
hgs
parents:
diff changeset
  1073
  {
hgs
parents:
diff changeset
  1074
    GST_ERROR_OBJECT (avi,
hgs
parents:
diff changeset
  1075
        "Not enough data to parse superindex (%d available, 24 needed)", size);
hgs
parents:
diff changeset
  1076
    if (buf)
hgs
parents:
diff changeset
  1077
      gst_buffer_unref (buf);
hgs
parents:
diff changeset
  1078
    return FALSE;
hgs
parents:
diff changeset
  1079
  }
hgs
parents:
diff changeset
  1080
}
hgs
parents:
diff changeset
  1081
hgs
parents:
diff changeset
  1082
/*
hgs
parents:
diff changeset
  1083
 * gst_avi_demux_parse_subindex:
hgs
parents:
diff changeset
  1084
 * @avi: Avi object
hgs
parents:
diff changeset
  1085
 * @buf: input data to use for parsing.
hgs
parents:
diff changeset
  1086
 * @stream: stream context.
hgs
parents:
diff changeset
  1087
 * @entries_list: a list (returned by the function) containing all the
hgs
parents:
diff changeset
  1088
 *           indexes parsed in this specific subindex. The first
hgs
parents:
diff changeset
  1089
 *           entry is also a pointer to allocated memory that needs
hgs
parents:
diff changeset
  1090
 *           to be free´ed. May be NULL if no supported indexes were
hgs
parents:
diff changeset
  1091
 *           found.
hgs
parents:
diff changeset
  1092
 *
hgs
parents:
diff changeset
  1093
 * Reads superindex (openDML-2 spec stuff) from the provided data.
hgs
parents:
diff changeset
  1094
 * The buffer will be discarded after use.
hgs
parents:
diff changeset
  1095
 *
hgs
parents:
diff changeset
  1096
 * Returns: TRUE on success, FALSE otherwise. Errors are fatal, we
hgs
parents:
diff changeset
  1097
 *          throw an error, caller should bail out asap.
hgs
parents:
diff changeset
  1098
 */
hgs
parents:
diff changeset
  1099
static gboolean
hgs
parents:
diff changeset
  1100
gst_avi_demux_parse_subindex (GstAviDemux * avi,
hgs
parents:
diff changeset
  1101
    GstBuffer * buf, avi_stream_context * stream, GList ** _entries_list)
hgs
parents:
diff changeset
  1102
{
hgs
parents:
diff changeset
  1103
  guint8 *data = GST_BUFFER_DATA (buf);
hgs
parents:
diff changeset
  1104
  guint16 bpe;
hgs
parents:
diff changeset
  1105
  guint32 num, i;
hgs
parents:
diff changeset
  1106
  guint64 baseoff;
hgs
parents:
diff changeset
  1107
  gst_avi_index_entry *entries, *entry;
hgs
parents:
diff changeset
  1108
  GList *entries_list = NULL;
hgs
parents:
diff changeset
  1109
  guint size;
hgs
parents:
diff changeset
  1110
hgs
parents:
diff changeset
  1111
  *_entries_list = NULL;
hgs
parents:
diff changeset
  1112
hgs
parents:
diff changeset
  1113
  size = buf ? GST_BUFFER_SIZE (buf) : 0;
hgs
parents:
diff changeset
  1114
hgs
parents:
diff changeset
  1115
  /* check size */
hgs
parents:
diff changeset
  1116
  if (size < 24)
hgs
parents:
diff changeset
  1117
    goto too_small;
hgs
parents:
diff changeset
  1118
hgs
parents:
diff changeset
  1119
  /* We don't support index-data yet */
hgs
parents:
diff changeset
  1120
  if (data[3] & 0x80)
hgs
parents:
diff changeset
  1121
    goto not_implemented;
hgs
parents:
diff changeset
  1122
hgs
parents:
diff changeset
  1123
  /* check type of index. The opendml2 specs state that
hgs
parents:
diff changeset
  1124
   * there should be 4 dwords per array entry. Type can be
hgs
parents:
diff changeset
  1125
   * either frame or field (and we don't care). */
hgs
parents:
diff changeset
  1126
  bpe = (data[2] & 0x01) ? 12 : 8;
hgs
parents:
diff changeset
  1127
  if (GST_READ_UINT16_LE (data) != bpe / 4 ||
hgs
parents:
diff changeset
  1128
      (data[2] & 0xfe) != 0x0 || data[3] != 0x1) {
hgs
parents:
diff changeset
  1129
    GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  1130
        "Superindex for stream %d has unexpected "
hgs
parents:
diff changeset
  1131
        "size_entry %d (bytes) or flags 0x%02x/0x%02x",
hgs
parents:
diff changeset
  1132
        stream->num, GST_READ_UINT16_LE (data), data[2], data[3]);
hgs
parents:
diff changeset
  1133
    bpe = GST_READ_UINT16_LE (data) * 4;
hgs
parents:
diff changeset
  1134
  }
hgs
parents:
diff changeset
  1135
  num = GST_READ_UINT32_LE (&data[4]);
hgs
parents:
diff changeset
  1136
  baseoff = GST_READ_UINT64_LE (&data[12]);
hgs
parents:
diff changeset
  1137
hgs
parents:
diff changeset
  1138
  /* If there's nothing, just return ! */
hgs
parents:
diff changeset
  1139
  if (num == 0)
hgs
parents:
diff changeset
  1140
    return TRUE;
hgs
parents:
diff changeset
  1141
hgs
parents:
diff changeset
  1142
  if (!(entries = g_try_new (gst_avi_index_entry, num)))
hgs
parents:
diff changeset
  1143
    goto out_of_mem;
hgs
parents:
diff changeset
  1144
hgs
parents:
diff changeset
  1145
  for (i = 0; i < num; i++) {
hgs
parents:
diff changeset
  1146
    gint64 next_ts;
hgs
parents:
diff changeset
  1147
hgs
parents:
diff changeset
  1148
    entry = &entries[i];
hgs
parents:
diff changeset
  1149
hgs
parents:
diff changeset
  1150
    if (size < 24 + bpe * (i + 1))
hgs
parents:
diff changeset
  1151
      break;
hgs
parents:
diff changeset
  1152
hgs
parents:
diff changeset
  1153
    /* fill in */
hgs
parents:
diff changeset
  1154
    entry->offset = baseoff + GST_READ_UINT32_LE (&data[24 + bpe * i]);
hgs
parents:
diff changeset
  1155
    entry->size = GST_READ_UINT32_LE (&data[24 + bpe * i + 4]);
hgs
parents:
diff changeset
  1156
    entry->flags =
hgs
parents:
diff changeset
  1157
        (entry->size & 0x80000000) ? 0 : GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME;
hgs
parents:
diff changeset
  1158
    entry->size &= ~0x80000000;
hgs
parents:
diff changeset
  1159
    entry->index_nr = i;
hgs
parents:
diff changeset
  1160
    entry->stream_nr = stream->num;
hgs
parents:
diff changeset
  1161
hgs
parents:
diff changeset
  1162
    /* stream duration unknown, now we can calculate it */
hgs
parents:
diff changeset
  1163
    if (stream->idx_duration == -1)
hgs
parents:
diff changeset
  1164
      stream->idx_duration = 0;
hgs
parents:
diff changeset
  1165
hgs
parents:
diff changeset
  1166
    /* timestamps */
hgs
parents:
diff changeset
  1167
    entry->ts = stream->idx_duration;
hgs
parents:
diff changeset
  1168
    if (stream->is_vbr) {
hgs
parents:
diff changeset
  1169
      /* VBR stream next timestamp */
hgs
parents:
diff changeset
  1170
      if (stream->strh->type == GST_RIFF_FCC_auds) {
hgs
parents:
diff changeset
  1171
        next_ts = avi_stream_convert_frames_to_time_unchecked (stream,
hgs
parents:
diff changeset
  1172
            stream->total_blocks + 1);
hgs
parents:
diff changeset
  1173
      } else {
hgs
parents:
diff changeset
  1174
        next_ts = avi_stream_convert_frames_to_time_unchecked (stream,
hgs
parents:
diff changeset
  1175
            stream->total_frames + 1);
hgs
parents:
diff changeset
  1176
      }
hgs
parents:
diff changeset
  1177
    } else {
hgs
parents:
diff changeset
  1178
      /* CBR get next timestamp */
hgs
parents:
diff changeset
  1179
      next_ts = avi_stream_convert_bytes_to_time_unchecked (stream,
hgs
parents:
diff changeset
  1180
          stream->total_bytes + entry->size);
hgs
parents:
diff changeset
  1181
    }
hgs
parents:
diff changeset
  1182
    /* duration is next - current */
hgs
parents:
diff changeset
  1183
    entry->dur = next_ts - entry->ts;
hgs
parents:
diff changeset
  1184
hgs
parents:
diff changeset
  1185
    /* stream position */
hgs
parents:
diff changeset
  1186
    entry->bytes_before = stream->total_bytes;
hgs
parents:
diff changeset
  1187
    entry->frames_before = stream->total_frames;
hgs
parents:
diff changeset
  1188
hgs
parents:
diff changeset
  1189
    stream->total_bytes += entry->size;
hgs
parents:
diff changeset
  1190
    stream->total_frames++;
hgs
parents:
diff changeset
  1191
    if (stream->strh->type == GST_RIFF_FCC_auds) {
hgs
parents:
diff changeset
  1192
      if (stream->strf.auds->blockalign > 0)
hgs
parents:
diff changeset
  1193
        stream->total_blocks +=
hgs
parents:
diff changeset
  1194
            (entry->size + stream->strf.auds->blockalign -
hgs
parents:
diff changeset
  1195
            1) / stream->strf.auds->blockalign;
hgs
parents:
diff changeset
  1196
      else
hgs
parents:
diff changeset
  1197
        stream->total_blocks++;
hgs
parents:
diff changeset
  1198
    }
hgs
parents:
diff changeset
  1199
    stream->idx_duration = next_ts;
hgs
parents:
diff changeset
  1200
hgs
parents:
diff changeset
  1201
    entries_list = g_list_prepend (entries_list, entry);
hgs
parents:
diff changeset
  1202
  }
hgs
parents:
diff changeset
  1203
hgs
parents:
diff changeset
  1204
  GST_LOG_OBJECT (avi, "Read %d index entries", i);
hgs
parents:
diff changeset
  1205
hgs
parents:
diff changeset
  1206
  gst_buffer_unref (buf);
hgs
parents:
diff changeset
  1207
hgs
parents:
diff changeset
  1208
  if (i > 0) {
hgs
parents:
diff changeset
  1209
    *_entries_list = g_list_reverse (entries_list);
hgs
parents:
diff changeset
  1210
  } else {
hgs
parents:
diff changeset
  1211
    g_free (entries);
hgs
parents:
diff changeset
  1212
  }
hgs
parents:
diff changeset
  1213
hgs
parents:
diff changeset
  1214
  return TRUE;
hgs
parents:
diff changeset
  1215
hgs
parents:
diff changeset
  1216
  /* ERRORS */
hgs
parents:
diff changeset
  1217
too_small:
hgs
parents:
diff changeset
  1218
  {
hgs
parents:
diff changeset
  1219
    GST_ERROR_OBJECT (avi,
hgs
parents:
diff changeset
  1220
        "Not enough data to parse subindex (%d available, 24 needed)", size);
hgs
parents:
diff changeset
  1221
    if (buf)
hgs
parents:
diff changeset
  1222
      gst_buffer_unref (buf);
hgs
parents:
diff changeset
  1223
    return TRUE;                /* continue */
hgs
parents:
diff changeset
  1224
  }
hgs
parents:
diff changeset
  1225
not_implemented:
hgs
parents:
diff changeset
  1226
  {
hgs
parents:
diff changeset
  1227
    GST_ELEMENT_ERROR (avi, STREAM, NOT_IMPLEMENTED, (NULL),
hgs
parents:
diff changeset
  1228
        ("Subindex-is-data is not implemented"));
hgs
parents:
diff changeset
  1229
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  1230
    return FALSE;
hgs
parents:
diff changeset
  1231
  }
hgs
parents:
diff changeset
  1232
out_of_mem:
hgs
parents:
diff changeset
  1233
  {
hgs
parents:
diff changeset
  1234
    GST_ELEMENT_ERROR (avi, RESOURCE, NO_SPACE_LEFT, (NULL),
hgs
parents:
diff changeset
  1235
        ("Cannot allocate memory for %u*%u=%u bytes",
hgs
parents:
diff changeset
  1236
            (guint) sizeof (gst_avi_index_entry), num,
hgs
parents:
diff changeset
  1237
            (guint) sizeof (gst_avi_index_entry) * num));
hgs
parents:
diff changeset
  1238
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  1239
    return FALSE;
hgs
parents:
diff changeset
  1240
  }
hgs
parents:
diff changeset
  1241
}
hgs
parents:
diff changeset
  1242
hgs
parents:
diff changeset
  1243
#if 0
hgs
parents:
diff changeset
  1244
/*
hgs
parents:
diff changeset
  1245
 * Read AVI index when streaming
hgs
parents:
diff changeset
  1246
 */
hgs
parents:
diff changeset
  1247
static void
hgs
parents:
diff changeset
  1248
gst_avi_demux_read_subindexes_push (GstAviDemux * avi,
hgs
parents:
diff changeset
  1249
    GList ** index, GList ** alloc_list)
hgs
parents:
diff changeset
  1250
{
hgs
parents:
diff changeset
  1251
  GList *list = NULL;
hgs
parents:
diff changeset
  1252
  guint32 tag = 0, size;
hgs
parents:
diff changeset
  1253
  GstBuffer *buf = NULL;
hgs
parents:
diff changeset
  1254
  gint i, n;
hgs
parents:
diff changeset
  1255
hgs
parents:
diff changeset
  1256
  GST_DEBUG_OBJECT (avi, "gst_avi_demux_read_subindexes_push for %d streams",
hgs
parents:
diff changeset
  1257
      avi->num_streams);
hgs
parents:
diff changeset
  1258
hgs
parents:
diff changeset
  1259
  for (n = 0; n < avi->num_streams; n++) {
hgs
parents:
diff changeset
  1260
    avi_stream_context *stream = &avi->stream[n];
hgs
parents:
diff changeset
  1261
hgs
parents:
diff changeset
  1262
    for (i = 0; stream->indexes[i] != GST_BUFFER_OFFSET_NONE; i++) {
hgs
parents:
diff changeset
  1263
      if (!gst_avi_demux_peek_chunk (avi, &tag, &size))
hgs
parents:
diff changeset
  1264
        continue;
hgs
parents:
diff changeset
  1265
      else if ((tag != GST_MAKE_FOURCC ('i', 'x', '0' + stream->num / 10,
hgs
parents:
diff changeset
  1266
                  '0' + stream->num % 10)) &&
hgs
parents:
diff changeset
  1267
          (tag != GST_MAKE_FOURCC ('0' + stream->num / 10,
hgs
parents:
diff changeset
  1268
                  '0' + stream->num % 10, 'i', 'x'))) {
hgs
parents:
diff changeset
  1269
        GST_WARNING_OBJECT (avi, "Not an ix## chunk (%" GST_FOURCC_FORMAT ")",
hgs
parents:
diff changeset
  1270
            GST_FOURCC_ARGS (tag));
hgs
parents:
diff changeset
  1271
        continue;
hgs
parents:
diff changeset
  1272
      }
hgs
parents:
diff changeset
  1273
hgs
parents:
diff changeset
  1274
      avi->offset += 8 + ((size + 1) & ~1);
hgs
parents:
diff changeset
  1275
hgs
parents:
diff changeset
  1276
      buf = gst_buffer_new ();
hgs
parents:
diff changeset
  1277
      GST_BUFFER_DATA (buf) = gst_adapter_take (avi->adapter, size);
hgs
parents:
diff changeset
  1278
      GST_BUFFER_SIZE (buf) = size;
hgs
parents:
diff changeset
  1279
hgs
parents:
diff changeset
  1280
      if (!gst_avi_demux_parse_subindex (avi, buf, stream, &list))
hgs
parents:
diff changeset
  1281
        continue;
hgs
parents:
diff changeset
  1282
      if (list) {
hgs
parents:
diff changeset
  1283
        GST_DEBUG_OBJECT (avi, "  adding %d entries", g_list_length (list));
hgs
parents:
diff changeset
  1284
        *alloc_list = g_list_append (*alloc_list, list->data);
hgs
parents:
diff changeset
  1285
        *index = g_list_concat (*index, list);
hgs
parents:
diff changeset
  1286
      }
hgs
parents:
diff changeset
  1287
    }
hgs
parents:
diff changeset
  1288
hgs
parents:
diff changeset
  1289
    g_free (stream->indexes);
hgs
parents:
diff changeset
  1290
    stream->indexes = NULL;
hgs
parents:
diff changeset
  1291
  }
hgs
parents:
diff changeset
  1292
  GST_DEBUG_OBJECT (avi, "index %s", ((*index) ? "!= 0" : "== 0"));
hgs
parents:
diff changeset
  1293
}
hgs
parents:
diff changeset
  1294
#endif
hgs
parents:
diff changeset
  1295
hgs
parents:
diff changeset
  1296
/*
hgs
parents:
diff changeset
  1297
 * Read AVI index
hgs
parents:
diff changeset
  1298
 */
hgs
parents:
diff changeset
  1299
static void
hgs
parents:
diff changeset
  1300
gst_avi_demux_read_subindexes_pull (GstAviDemux * avi,
hgs
parents:
diff changeset
  1301
    GList ** index, GList ** alloc_list)
hgs
parents:
diff changeset
  1302
{
hgs
parents:
diff changeset
  1303
  GList *list = NULL;
hgs
parents:
diff changeset
  1304
  guint32 tag;
hgs
parents:
diff changeset
  1305
  GstBuffer *buf;
hgs
parents:
diff changeset
  1306
  gint i, n;
hgs
parents:
diff changeset
  1307
hgs
parents:
diff changeset
  1308
  GST_DEBUG_OBJECT (avi, "gst_avi_demux_read_subindexes_pull for %d streams",
hgs
parents:
diff changeset
  1309
      avi->num_streams);
hgs
parents:
diff changeset
  1310
hgs
parents:
diff changeset
  1311
  for (n = 0; n < avi->num_streams; n++) {
hgs
parents:
diff changeset
  1312
    avi_stream_context *stream = &avi->stream[n];
hgs
parents:
diff changeset
  1313
hgs
parents:
diff changeset
  1314
    for (i = 0; stream->indexes[i] != GST_BUFFER_OFFSET_NONE; i++) {
hgs
parents:
diff changeset
  1315
      if (gst_riff_read_chunk (GST_ELEMENT (avi), avi->sinkpad,
hgs
parents:
diff changeset
  1316
              &stream->indexes[i], &tag, &buf) != GST_FLOW_OK)
hgs
parents:
diff changeset
  1317
        continue;
hgs
parents:
diff changeset
  1318
      else if ((tag != GST_MAKE_FOURCC ('i', 'x', '0' + stream->num / 10,
hgs
parents:
diff changeset
  1319
                  '0' + stream->num % 10)) &&
hgs
parents:
diff changeset
  1320
          (tag != GST_MAKE_FOURCC ('0' + stream->num / 10,
hgs
parents:
diff changeset
  1321
                  '0' + stream->num % 10, 'i', 'x'))) {
hgs
parents:
diff changeset
  1322
        /* Some ODML files (created by god knows what muxer) have a ##ix format
hgs
parents:
diff changeset
  1323
         * instead of the 'official' ix##. They are still valid though. */
hgs
parents:
diff changeset
  1324
        GST_WARNING_OBJECT (avi, "Not an ix## chunk (%" GST_FOURCC_FORMAT ")",
hgs
parents:
diff changeset
  1325
            GST_FOURCC_ARGS (tag));
hgs
parents:
diff changeset
  1326
        gst_buffer_unref (buf);
hgs
parents:
diff changeset
  1327
        continue;
hgs
parents:
diff changeset
  1328
      }
hgs
parents:
diff changeset
  1329
hgs
parents:
diff changeset
  1330
      if (!gst_avi_demux_parse_subindex (avi, buf, stream, &list))
hgs
parents:
diff changeset
  1331
        continue;
hgs
parents:
diff changeset
  1332
      if (list) {
hgs
parents:
diff changeset
  1333
        GST_DEBUG_OBJECT (avi, "  adding %5d entries, total %2d %5d",
hgs
parents:
diff changeset
  1334
            g_list_length (list), g_list_length (*alloc_list),
hgs
parents:
diff changeset
  1335
            g_list_length (*index));
hgs
parents:
diff changeset
  1336
        *alloc_list = g_list_append (*alloc_list, list->data);
hgs
parents:
diff changeset
  1337
        *index = g_list_concat (*index, list);
hgs
parents:
diff changeset
  1338
      }
hgs
parents:
diff changeset
  1339
    }
hgs
parents:
diff changeset
  1340
hgs
parents:
diff changeset
  1341
    g_free (stream->indexes);
hgs
parents:
diff changeset
  1342
    stream->indexes = NULL;
hgs
parents:
diff changeset
  1343
  }
hgs
parents:
diff changeset
  1344
  GST_DEBUG_OBJECT (avi, "index %s", ((*index) ? "!= 0" : "== 0"));
hgs
parents:
diff changeset
  1345
}
hgs
parents:
diff changeset
  1346
hgs
parents:
diff changeset
  1347
/*
hgs
parents:
diff changeset
  1348
 * gst_avi_demux_riff_parse_vprp:
hgs
parents:
diff changeset
  1349
 * @element: caller element (used for debugging/error).
hgs
parents:
diff changeset
  1350
 * @buf: input data to be used for parsing, stripped from header.
hgs
parents:
diff changeset
  1351
 * @vprp: a pointer (returned by this function) to a filled-in vprp
hgs
parents:
diff changeset
  1352
 *        structure. Caller should free it.
hgs
parents:
diff changeset
  1353
 *
hgs
parents:
diff changeset
  1354
 * Parses a video stream´s vprp. This function takes ownership of @buf.
hgs
parents:
diff changeset
  1355
 *
hgs
parents:
diff changeset
  1356
 * Returns: TRUE if parsing succeeded, otherwise FALSE. The stream
hgs
parents:
diff changeset
  1357
 *          should be skipped on error, but it is not fatal.
hgs
parents:
diff changeset
  1358
 */
hgs
parents:
diff changeset
  1359
static gboolean
hgs
parents:
diff changeset
  1360
gst_avi_demux_riff_parse_vprp (GstElement * element,
hgs
parents:
diff changeset
  1361
    GstBuffer * buf, gst_riff_vprp ** _vprp)
hgs
parents:
diff changeset
  1362
{
hgs
parents:
diff changeset
  1363
  gst_riff_vprp *vprp;
hgs
parents:
diff changeset
  1364
  gint k;
hgs
parents:
diff changeset
  1365
hgs
parents:
diff changeset
  1366
  g_return_val_if_fail (buf != NULL, FALSE);
hgs
parents:
diff changeset
  1367
  g_return_val_if_fail (_vprp != NULL, FALSE);
hgs
parents:
diff changeset
  1368
hgs
parents:
diff changeset
  1369
  if (GST_BUFFER_SIZE (buf) < G_STRUCT_OFFSET (gst_riff_vprp, field_info))
hgs
parents:
diff changeset
  1370
    goto too_small;
hgs
parents:
diff changeset
  1371
hgs
parents:
diff changeset
  1372
  vprp = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
hgs
parents:
diff changeset
  1373
hgs
parents:
diff changeset
  1374
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
hgs
parents:
diff changeset
  1375
  vprp->format_token = GUINT32_FROM_LE (vprp->format_token);
hgs
parents:
diff changeset
  1376
  vprp->standard = GUINT32_FROM_LE (vprp->standard);
hgs
parents:
diff changeset
  1377
  vprp->vert_rate = GUINT32_FROM_LE (vprp->vert_rate);
hgs
parents:
diff changeset
  1378
  vprp->hor_t_total = GUINT32_FROM_LE (vprp->hor_t_total);
hgs
parents:
diff changeset
  1379
  vprp->vert_lines = GUINT32_FROM_LE (vprp->vert_lines);
hgs
parents:
diff changeset
  1380
  vprp->aspect = GUINT32_FROM_LE (vprp->aspect);
hgs
parents:
diff changeset
  1381
  vprp->width = GUINT32_FROM_LE (vprp->width);
hgs
parents:
diff changeset
  1382
  vprp->height = GUINT32_FROM_LE (vprp->height);
hgs
parents:
diff changeset
  1383
  vprp->fields = GUINT32_FROM_LE (vprp->fields);
hgs
parents:
diff changeset
  1384
#endif
hgs
parents:
diff changeset
  1385
hgs
parents:
diff changeset
  1386
  /* size checking */
hgs
parents:
diff changeset
  1387
  /* calculate fields based on size */
hgs
parents:
diff changeset
  1388
  k = (GST_BUFFER_SIZE (buf) - G_STRUCT_OFFSET (gst_riff_vprp, field_info)) /
hgs
parents:
diff changeset
  1389
      vprp->fields;
hgs
parents:
diff changeset
  1390
  if (vprp->fields > k) {
hgs
parents:
diff changeset
  1391
    GST_WARNING_OBJECT (element,
hgs
parents:
diff changeset
  1392
        "vprp header indicated %d fields, only %d available", vprp->fields, k);
hgs
parents:
diff changeset
  1393
    vprp->fields = k;
hgs
parents:
diff changeset
  1394
  }
hgs
parents:
diff changeset
  1395
  if (vprp->fields > GST_RIFF_VPRP_VIDEO_FIELDS) {
hgs
parents:
diff changeset
  1396
    GST_WARNING_OBJECT (element,
hgs
parents:
diff changeset
  1397
        "vprp header indicated %d fields, at most %d supported", vprp->fields,
hgs
parents:
diff changeset
  1398
        GST_RIFF_VPRP_VIDEO_FIELDS);
hgs
parents:
diff changeset
  1399
    vprp->fields = GST_RIFF_VPRP_VIDEO_FIELDS;
hgs
parents:
diff changeset
  1400
  }
hgs
parents:
diff changeset
  1401
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
hgs
parents:
diff changeset
  1402
  for (k = 0; k < vprp->fields; k++) {
hgs
parents:
diff changeset
  1403
    gst_riff_vprp_video_field_desc *fd;
hgs
parents:
diff changeset
  1404
hgs
parents:
diff changeset
  1405
    fd = &vprp->field_info[k];
hgs
parents:
diff changeset
  1406
    fd->compressed_bm_height = GUINT32_FROM_LE (fd->compressed_bm_height);
hgs
parents:
diff changeset
  1407
    fd->compressed_bm_width = GUINT32_FROM_LE (fd->compressed_bm_width);
hgs
parents:
diff changeset
  1408
    fd->valid_bm_height = GUINT32_FROM_LE (fd->valid_bm_height);
hgs
parents:
diff changeset
  1409
    fd->valid_bm_width = GUINT16_FROM_LE (fd->valid_bm_width);
hgs
parents:
diff changeset
  1410
    fd->valid_bm_x_offset = GUINT16_FROM_LE (fd->valid_bm_x_offset);
hgs
parents:
diff changeset
  1411
    fd->valid_bm_y_offset = GUINT32_FROM_LE (fd->valid_bm_y_offset);
hgs
parents:
diff changeset
  1412
    fd->video_x_t_offset = GUINT32_FROM_LE (fd->video_x_t_offset);
hgs
parents:
diff changeset
  1413
    fd->video_y_start = GUINT32_FROM_LE (fd->video_y_start);
hgs
parents:
diff changeset
  1414
  }
hgs
parents:
diff changeset
  1415
#endif
hgs
parents:
diff changeset
  1416
hgs
parents:
diff changeset
  1417
  /* debug */
hgs
parents:
diff changeset
  1418
  GST_INFO_OBJECT (element, "vprp tag found in context vids:");
hgs
parents:
diff changeset
  1419
  GST_INFO_OBJECT (element, " format_token  %d", vprp->format_token);
hgs
parents:
diff changeset
  1420
  GST_INFO_OBJECT (element, " standard      %d", vprp->standard);
hgs
parents:
diff changeset
  1421
  GST_INFO_OBJECT (element, " vert_rate     %d", vprp->vert_rate);
hgs
parents:
diff changeset
  1422
  GST_INFO_OBJECT (element, " hor_t_total   %d", vprp->hor_t_total);
hgs
parents:
diff changeset
  1423
  GST_INFO_OBJECT (element, " vert_lines    %d", vprp->vert_lines);
hgs
parents:
diff changeset
  1424
  GST_INFO_OBJECT (element, " aspect        %d:%d", vprp->aspect >> 16,
hgs
parents:
diff changeset
  1425
      vprp->aspect & 0xffff);
hgs
parents:
diff changeset
  1426
  GST_INFO_OBJECT (element, " width         %d", vprp->width);
hgs
parents:
diff changeset
  1427
  GST_INFO_OBJECT (element, " height        %d", vprp->height);
hgs
parents:
diff changeset
  1428
  GST_INFO_OBJECT (element, " fields        %d", vprp->fields);
hgs
parents:
diff changeset
  1429
  for (k = 0; k < vprp->fields; k++) {
hgs
parents:
diff changeset
  1430
    gst_riff_vprp_video_field_desc *fd;
hgs
parents:
diff changeset
  1431
hgs
parents:
diff changeset
  1432
    fd = &(vprp->field_info[k]);
hgs
parents:
diff changeset
  1433
    GST_INFO_OBJECT (element, " field %u description:", k);
hgs
parents:
diff changeset
  1434
    GST_INFO_OBJECT (element, "  compressed_bm_height  %d",
hgs
parents:
diff changeset
  1435
        fd->compressed_bm_height);
hgs
parents:
diff changeset
  1436
    GST_INFO_OBJECT (element, "  compressed_bm_width  %d",
hgs
parents:
diff changeset
  1437
        fd->compressed_bm_width);
hgs
parents:
diff changeset
  1438
    GST_INFO_OBJECT (element, "  valid_bm_height       %d",
hgs
parents:
diff changeset
  1439
        fd->valid_bm_height);
hgs
parents:
diff changeset
  1440
    GST_INFO_OBJECT (element, "  valid_bm_width        %d", fd->valid_bm_width);
hgs
parents:
diff changeset
  1441
    GST_INFO_OBJECT (element, "  valid_bm_x_offset     %d",
hgs
parents:
diff changeset
  1442
        fd->valid_bm_x_offset);
hgs
parents:
diff changeset
  1443
    GST_INFO_OBJECT (element, "  valid_bm_y_offset     %d",
hgs
parents:
diff changeset
  1444
        fd->valid_bm_y_offset);
hgs
parents:
diff changeset
  1445
    GST_INFO_OBJECT (element, "  video_x_t_offset      %d",
hgs
parents:
diff changeset
  1446
        fd->video_x_t_offset);
hgs
parents:
diff changeset
  1447
    GST_INFO_OBJECT (element, "  video_y_start         %d", fd->video_y_start);
hgs
parents:
diff changeset
  1448
  }
hgs
parents:
diff changeset
  1449
hgs
parents:
diff changeset
  1450
  gst_buffer_unref (buf);
hgs
parents:
diff changeset
  1451
hgs
parents:
diff changeset
  1452
  *_vprp = vprp;
hgs
parents:
diff changeset
  1453
hgs
parents:
diff changeset
  1454
  return TRUE;
hgs
parents:
diff changeset
  1455
hgs
parents:
diff changeset
  1456
  /* ERRORS */
hgs
parents:
diff changeset
  1457
too_small:
hgs
parents:
diff changeset
  1458
  {
hgs
parents:
diff changeset
  1459
    GST_ERROR_OBJECT (element,
hgs
parents:
diff changeset
  1460
        "Too small vprp (%d available, at least %d needed)",
hgs
parents:
diff changeset
  1461
        GST_BUFFER_SIZE (buf),
hgs
parents:
diff changeset
  1462
        (int) G_STRUCT_OFFSET (gst_riff_vprp, field_info));
hgs
parents:
diff changeset
  1463
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  1464
    return FALSE;
hgs
parents:
diff changeset
  1465
  }
hgs
parents:
diff changeset
  1466
}
hgs
parents:
diff changeset
  1467
hgs
parents:
diff changeset
  1468
/*
hgs
parents:
diff changeset
  1469
 * gst_avi_demux_parse_stream:
hgs
parents:
diff changeset
  1470
 * @avi: calling element (used for debugging/errors).
hgs
parents:
diff changeset
  1471
 * @buf: input buffer used to parse the stream.
hgs
parents:
diff changeset
  1472
 *
hgs
parents:
diff changeset
  1473
 * Parses all subchunks in a strl chunk (which defines a single
hgs
parents:
diff changeset
  1474
 * stream). Discards the buffer after use. This function will
hgs
parents:
diff changeset
  1475
 * increment the stream counter internally.
hgs
parents:
diff changeset
  1476
 *
hgs
parents:
diff changeset
  1477
 * Returns: whether the stream was identified successfully.
hgs
parents:
diff changeset
  1478
 *          Errors are not fatal. It does indicate the stream
hgs
parents:
diff changeset
  1479
 *          was skipped.
hgs
parents:
diff changeset
  1480
 */
hgs
parents:
diff changeset
  1481
static gboolean
hgs
parents:
diff changeset
  1482
gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf)
hgs
parents:
diff changeset
  1483
{
hgs
parents:
diff changeset
  1484
  avi_stream_context *stream;
hgs
parents:
diff changeset
  1485
  GstElementClass *klass;
hgs
parents:
diff changeset
  1486
  GstPadTemplate *templ;
hgs
parents:
diff changeset
  1487
  GstBuffer *sub = NULL;
hgs
parents:
diff changeset
  1488
  guint offset = 4;
hgs
parents:
diff changeset
  1489
  guint32 tag = 0;
hgs
parents:
diff changeset
  1490
  gchar *codec_name = NULL, *padname = NULL;
hgs
parents:
diff changeset
  1491
  const gchar *tag_name;
hgs
parents:
diff changeset
  1492
  GstCaps *caps = NULL;
hgs
parents:
diff changeset
  1493
  GstPad *pad;
hgs
parents:
diff changeset
  1494
  GstElement *element;
hgs
parents:
diff changeset
  1495
  gboolean got_strh = FALSE, got_strf = FALSE, got_vprp = FALSE;
hgs
parents:
diff changeset
  1496
  gst_riff_vprp *vprp = NULL;
hgs
parents:
diff changeset
  1497
hgs
parents:
diff changeset
  1498
  element = GST_ELEMENT_CAST (avi);
hgs
parents:
diff changeset
  1499
hgs
parents:
diff changeset
  1500
  GST_DEBUG_OBJECT (avi, "Parsing stream");
hgs
parents:
diff changeset
  1501
hgs
parents:
diff changeset
  1502
  if (avi->num_streams >= GST_AVI_DEMUX_MAX_STREAMS) {
hgs
parents:
diff changeset
  1503
    GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  1504
        "maximum no of streams (%d) exceeded, ignoring stream",
hgs
parents:
diff changeset
  1505
        GST_AVI_DEMUX_MAX_STREAMS);
hgs
parents:
diff changeset
  1506
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  1507
    /* not a fatal error, let's say */
hgs
parents:
diff changeset
  1508
    return TRUE;
hgs
parents:
diff changeset
  1509
  }
hgs
parents:
diff changeset
  1510
hgs
parents:
diff changeset
  1511
  stream = &avi->stream[avi->num_streams];
hgs
parents:
diff changeset
  1512
hgs
parents:
diff changeset
  1513
  /* initial settings */
hgs
parents:
diff changeset
  1514
  stream->idx_duration = GST_CLOCK_TIME_NONE;
hgs
parents:
diff changeset
  1515
  stream->hdr_duration = GST_CLOCK_TIME_NONE;
hgs
parents:
diff changeset
  1516
  stream->duration = GST_CLOCK_TIME_NONE;
hgs
parents:
diff changeset
  1517
hgs
parents:
diff changeset
  1518
  while (gst_riff_parse_chunk (element, buf, &offset, &tag, &sub)) {
hgs
parents:
diff changeset
  1519
    /* sub can be NULL if the chunk is empty */
hgs
parents:
diff changeset
  1520
    if (sub == NULL) {
hgs
parents:
diff changeset
  1521
      GST_DEBUG_OBJECT (avi, "ignoring empty chunk %" GST_FOURCC_FORMAT,
hgs
parents:
diff changeset
  1522
          GST_FOURCC_ARGS (tag));
hgs
parents:
diff changeset
  1523
      continue;
hgs
parents:
diff changeset
  1524
    }
hgs
parents:
diff changeset
  1525
    switch (tag) {
hgs
parents:
diff changeset
  1526
      case GST_RIFF_TAG_strh:
hgs
parents:
diff changeset
  1527
      {
hgs
parents:
diff changeset
  1528
        gst_riff_strh *strh;
hgs
parents:
diff changeset
  1529
hgs
parents:
diff changeset
  1530
        if (got_strh) {
hgs
parents:
diff changeset
  1531
          GST_WARNING_OBJECT (avi, "Ignoring additional strh chunk");
hgs
parents:
diff changeset
  1532
          break;
hgs
parents:
diff changeset
  1533
        }
hgs
parents:
diff changeset
  1534
        if (!gst_riff_parse_strh (element, sub, &stream->strh)) {
hgs
parents:
diff changeset
  1535
          /* ownership given away */
hgs
parents:
diff changeset
  1536
          sub = NULL;
hgs
parents:
diff changeset
  1537
          GST_WARNING_OBJECT (avi, "Failed to parse strh chunk");
hgs
parents:
diff changeset
  1538
          goto fail;
hgs
parents:
diff changeset
  1539
        }
hgs
parents:
diff changeset
  1540
        sub = NULL;
hgs
parents:
diff changeset
  1541
        strh = stream->strh;
hgs
parents:
diff changeset
  1542
        /* sanity check; stream header frame rate matches global header
hgs
parents:
diff changeset
  1543
         * frame duration */
hgs
parents:
diff changeset
  1544
        if (stream->strh->type == GST_RIFF_FCC_vids) {
hgs
parents:
diff changeset
  1545
          GstClockTime s_dur;
hgs
parents:
diff changeset
  1546
          GstClockTime h_dur = avi->avih->us_frame * GST_USECOND;
hgs
parents:
diff changeset
  1547
hgs
parents:
diff changeset
  1548
          s_dur = gst_util_uint64_scale (GST_SECOND, strh->scale, strh->rate);
hgs
parents:
diff changeset
  1549
          GST_DEBUG_OBJECT (avi, "verifying stream framerate %d/%d, "
hgs
parents:
diff changeset
  1550
              "frame duration = %d ms", strh->rate, strh->scale,
hgs
parents:
diff changeset
  1551
              s_dur / GST_MSECOND);
hgs
parents:
diff changeset
  1552
          if (h_dur > (10 * GST_MSECOND) && (s_dur > 10 * h_dur)) {
hgs
parents:
diff changeset
  1553
            strh->rate = GST_SECOND / GST_USECOND;
hgs
parents:
diff changeset
  1554
            strh->scale = h_dur / GST_USECOND;
hgs
parents:
diff changeset
  1555
            GST_DEBUG_OBJECT (avi, "correcting stream framerate to %d/%d",
hgs
parents:
diff changeset
  1556
                strh->rate, strh->scale);
hgs
parents:
diff changeset
  1557
          }
hgs
parents:
diff changeset
  1558
        }
hgs
parents:
diff changeset
  1559
        /* determine duration as indicated by header */
hgs
parents:
diff changeset
  1560
        stream->hdr_duration = gst_util_uint64_scale ((guint64) strh->length *
hgs
parents:
diff changeset
  1561
            strh->scale, GST_SECOND, (guint64) strh->rate);
hgs
parents:
diff changeset
  1562
        GST_INFO ("Stream duration according to header: %" GST_TIME_FORMAT,
hgs
parents:
diff changeset
  1563
            GST_TIME_ARGS (stream->hdr_duration));
hgs
parents:
diff changeset
  1564
        if (stream->hdr_duration == 0)
hgs
parents:
diff changeset
  1565
          stream->hdr_duration = GST_CLOCK_TIME_NONE;
hgs
parents:
diff changeset
  1566
hgs
parents:
diff changeset
  1567
        got_strh = TRUE;
hgs
parents:
diff changeset
  1568
        break;
hgs
parents:
diff changeset
  1569
      }
hgs
parents:
diff changeset
  1570
      case GST_RIFF_TAG_strf:
hgs
parents:
diff changeset
  1571
      {
hgs
parents:
diff changeset
  1572
        gboolean res = FALSE;
hgs
parents:
diff changeset
  1573
hgs
parents:
diff changeset
  1574
        if (got_strf) {
hgs
parents:
diff changeset
  1575
          GST_WARNING_OBJECT (avi, "Ignoring additional strf chunk");
hgs
parents:
diff changeset
  1576
          break;
hgs
parents:
diff changeset
  1577
        }
hgs
parents:
diff changeset
  1578
        if (!got_strh) {
hgs
parents:
diff changeset
  1579
          GST_ERROR_OBJECT (avi, "Found strf chunk before strh chunk");
hgs
parents:
diff changeset
  1580
          goto fail;
hgs
parents:
diff changeset
  1581
        }
hgs
parents:
diff changeset
  1582
        switch (stream->strh->type) {
hgs
parents:
diff changeset
  1583
          case GST_RIFF_FCC_vids:
hgs
parents:
diff changeset
  1584
            stream->is_vbr = TRUE;
hgs
parents:
diff changeset
  1585
            res = gst_riff_parse_strf_vids (element, sub,
hgs
parents:
diff changeset
  1586
                &stream->strf.vids, &stream->extradata);
hgs
parents:
diff changeset
  1587
            sub = NULL;
hgs
parents:
diff changeset
  1588
            GST_DEBUG_OBJECT (element, "marking video as VBR, res %d", res);
hgs
parents:
diff changeset
  1589
            break;
hgs
parents:
diff changeset
  1590
          case GST_RIFF_FCC_auds:
hgs
parents:
diff changeset
  1591
            stream->is_vbr = (stream->strh->samplesize == 0)
hgs
parents:
diff changeset
  1592
                && stream->strh->scale > 1;
hgs
parents:
diff changeset
  1593
            res =
hgs
parents:
diff changeset
  1594
                gst_riff_parse_strf_auds (element, sub, &stream->strf.auds,
hgs
parents:
diff changeset
  1595
                &stream->extradata);
hgs
parents:
diff changeset
  1596
            sub = NULL;
hgs
parents:
diff changeset
  1597
            GST_DEBUG_OBJECT (element, "marking audio as VBR:%d, res %d",
hgs
parents:
diff changeset
  1598
                stream->is_vbr, res);
hgs
parents:
diff changeset
  1599
            break;
hgs
parents:
diff changeset
  1600
          case GST_RIFF_FCC_iavs:
hgs
parents:
diff changeset
  1601
            stream->is_vbr = TRUE;
hgs
parents:
diff changeset
  1602
            res = gst_riff_parse_strf_iavs (element, sub,
hgs
parents:
diff changeset
  1603
                &stream->strf.iavs, &stream->extradata);
hgs
parents:
diff changeset
  1604
            sub = NULL;
hgs
parents:
diff changeset
  1605
            GST_DEBUG_OBJECT (element, "marking iavs as VBR, res %d", res);
hgs
parents:
diff changeset
  1606
            break;
hgs
parents:
diff changeset
  1607
          case GST_RIFF_FCC_txts:
hgs
parents:
diff changeset
  1608
            /* nothing to parse here */
hgs
parents:
diff changeset
  1609
            stream->is_vbr = (stream->strh->samplesize == 0)
hgs
parents:
diff changeset
  1610
                && (stream->strh->scale > 1);
hgs
parents:
diff changeset
  1611
            res = TRUE;
hgs
parents:
diff changeset
  1612
            break;
hgs
parents:
diff changeset
  1613
          default:
hgs
parents:
diff changeset
  1614
            GST_ERROR_OBJECT (avi,
hgs
parents:
diff changeset
  1615
                "Don´t know how to handle stream type %" GST_FOURCC_FORMAT,
hgs
parents:
diff changeset
  1616
                GST_FOURCC_ARGS (stream->strh->type));
hgs
parents:
diff changeset
  1617
            break;
hgs
parents:
diff changeset
  1618
        }
hgs
parents:
diff changeset
  1619
        if (sub) {
hgs
parents:
diff changeset
  1620
          gst_buffer_unref (sub);
hgs
parents:
diff changeset
  1621
          sub = NULL;
hgs
parents:
diff changeset
  1622
        }
hgs
parents:
diff changeset
  1623
        if (!res)
hgs
parents:
diff changeset
  1624
          goto fail;
hgs
parents:
diff changeset
  1625
        got_strf = TRUE;
hgs
parents:
diff changeset
  1626
        break;
hgs
parents:
diff changeset
  1627
      }
hgs
parents:
diff changeset
  1628
      case GST_RIFF_TAG_vprp:
hgs
parents:
diff changeset
  1629
      {
hgs
parents:
diff changeset
  1630
        if (got_vprp) {
hgs
parents:
diff changeset
  1631
          GST_WARNING_OBJECT (avi, "Ignoring additional vprp chunk");
hgs
parents:
diff changeset
  1632
          break;
hgs
parents:
diff changeset
  1633
        }
hgs
parents:
diff changeset
  1634
        if (!got_strh) {
hgs
parents:
diff changeset
  1635
          GST_ERROR_OBJECT (avi, "Found vprp chunk before strh chunk");
hgs
parents:
diff changeset
  1636
          goto fail;
hgs
parents:
diff changeset
  1637
        }
hgs
parents:
diff changeset
  1638
        if (!got_strf) {
hgs
parents:
diff changeset
  1639
          GST_ERROR_OBJECT (avi, "Found vprp chunk before strf chunk");
hgs
parents:
diff changeset
  1640
          goto fail;
hgs
parents:
diff changeset
  1641
        }
hgs
parents:
diff changeset
  1642
hgs
parents:
diff changeset
  1643
        if (!gst_avi_demux_riff_parse_vprp (element, sub, &vprp)) {
hgs
parents:
diff changeset
  1644
          GST_WARNING_OBJECT (avi, "Failed to parse vprp chunk");
hgs
parents:
diff changeset
  1645
          /* not considered fatal */
hgs
parents:
diff changeset
  1646
          g_free (vprp);
hgs
parents:
diff changeset
  1647
          vprp = NULL;
hgs
parents:
diff changeset
  1648
        } else
hgs
parents:
diff changeset
  1649
          got_vprp = TRUE;
hgs
parents:
diff changeset
  1650
        sub = NULL;
hgs
parents:
diff changeset
  1651
        break;
hgs
parents:
diff changeset
  1652
      }
hgs
parents:
diff changeset
  1653
      case GST_RIFF_TAG_strd:
hgs
parents:
diff changeset
  1654
        if (stream->initdata)
hgs
parents:
diff changeset
  1655
          gst_buffer_unref (stream->initdata);
hgs
parents:
diff changeset
  1656
        stream->initdata = sub;
hgs
parents:
diff changeset
  1657
        sub = NULL;
hgs
parents:
diff changeset
  1658
        break;
hgs
parents:
diff changeset
  1659
      case GST_RIFF_TAG_strn:
hgs
parents:
diff changeset
  1660
        g_free (stream->name);
hgs
parents:
diff changeset
  1661
        if (sub != NULL) {
hgs
parents:
diff changeset
  1662
          stream->name =
hgs
parents:
diff changeset
  1663
              g_strndup ((gchar *) GST_BUFFER_DATA (sub),
hgs
parents:
diff changeset
  1664
              (gsize) GST_BUFFER_SIZE (sub));
hgs
parents:
diff changeset
  1665
          gst_buffer_unref (sub);
hgs
parents:
diff changeset
  1666
          sub = NULL;
hgs
parents:
diff changeset
  1667
        } else {
hgs
parents:
diff changeset
  1668
          stream->name = g_strdup ("");
hgs
parents:
diff changeset
  1669
        }
hgs
parents:
diff changeset
  1670
        GST_DEBUG_OBJECT (avi, "stream name: %s", stream->name);
hgs
parents:
diff changeset
  1671
        break;
hgs
parents:
diff changeset
  1672
      default:
hgs
parents:
diff changeset
  1673
        if (tag == GST_MAKE_FOURCC ('i', 'n', 'd', 'x') ||
hgs
parents:
diff changeset
  1674
            tag == GST_MAKE_FOURCC ('i', 'x', '0' + avi->num_streams / 10,
hgs
parents:
diff changeset
  1675
                '0' + avi->num_streams % 10)) {
hgs
parents:
diff changeset
  1676
          g_free (stream->indexes);
hgs
parents:
diff changeset
  1677
          gst_avi_demux_parse_superindex (avi, sub, &stream->indexes);
hgs
parents:
diff changeset
  1678
          stream->superindex = TRUE;
hgs
parents:
diff changeset
  1679
          sub = NULL;
hgs
parents:
diff changeset
  1680
          break;
hgs
parents:
diff changeset
  1681
        }
hgs
parents:
diff changeset
  1682
        GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  1683
            "Unknown stream header tag %" GST_FOURCC_FORMAT ", ignoring",
hgs
parents:
diff changeset
  1684
            GST_FOURCC_ARGS (tag));
hgs
parents:
diff changeset
  1685
        /* fall-through */
hgs
parents:
diff changeset
  1686
      case GST_RIFF_TAG_JUNK:
hgs
parents:
diff changeset
  1687
        break;
hgs
parents:
diff changeset
  1688
    }
hgs
parents:
diff changeset
  1689
    if (sub != NULL) {
hgs
parents:
diff changeset
  1690
      gst_buffer_unref (sub);
hgs
parents:
diff changeset
  1691
      sub = NULL;
hgs
parents:
diff changeset
  1692
    }
hgs
parents:
diff changeset
  1693
  }
hgs
parents:
diff changeset
  1694
hgs
parents:
diff changeset
  1695
  if (!got_strh) {
hgs
parents:
diff changeset
  1696
    GST_WARNING_OBJECT (avi, "Failed to find strh chunk");
hgs
parents:
diff changeset
  1697
    goto fail;
hgs
parents:
diff changeset
  1698
  }
hgs
parents:
diff changeset
  1699
hgs
parents:
diff changeset
  1700
  if (!got_strf) {
hgs
parents:
diff changeset
  1701
    GST_WARNING_OBJECT (avi, "Failed to find strf chunk");
hgs
parents:
diff changeset
  1702
    goto fail;
hgs
parents:
diff changeset
  1703
  }
hgs
parents:
diff changeset
  1704
hgs
parents:
diff changeset
  1705
  /* get class to figure out the template */
hgs
parents:
diff changeset
  1706
  klass = GST_ELEMENT_GET_CLASS (avi);
hgs
parents:
diff changeset
  1707
hgs
parents:
diff changeset
  1708
  /* we now have all info, let´s set up a pad and a caps and be done */
hgs
parents:
diff changeset
  1709
  /* create stream name + pad */
hgs
parents:
diff changeset
  1710
  switch (stream->strh->type) {
hgs
parents:
diff changeset
  1711
    case GST_RIFF_FCC_vids:{
hgs
parents:
diff changeset
  1712
      guint32 fourcc;
hgs
parents:
diff changeset
  1713
hgs
parents:
diff changeset
  1714
      fourcc = (stream->strf.vids->compression) ?
hgs
parents:
diff changeset
  1715
          stream->strf.vids->compression : stream->strh->fcc_handler;
hgs
parents:
diff changeset
  1716
      padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
hgs
parents:
diff changeset
  1717
      templ = gst_element_class_get_pad_template (klass, "video_%02d");
hgs
parents:
diff changeset
  1718
      caps = gst_riff_create_video_caps (fourcc, stream->strh,
hgs
parents:
diff changeset
  1719
          stream->strf.vids, stream->extradata, stream->initdata, &codec_name);
hgs
parents:
diff changeset
  1720
      if (!caps) {
hgs
parents:
diff changeset
  1721
        caps = gst_caps_new_simple ("video/x-avi-unknown", "fourcc",
hgs
parents:
diff changeset
  1722
            GST_TYPE_FOURCC, fourcc, NULL);
hgs
parents:
diff changeset
  1723
      } else if (got_vprp && vprp) {
hgs
parents:
diff changeset
  1724
        guint32 aspect_n, aspect_d;
hgs
parents:
diff changeset
  1725
        gint n, d;
hgs
parents:
diff changeset
  1726
hgs
parents:
diff changeset
  1727
        aspect_n = vprp->aspect >> 16;
hgs
parents:
diff changeset
  1728
        aspect_d = vprp->aspect & 0xffff;
hgs
parents:
diff changeset
  1729
        /* calculate the pixel aspect ratio using w/h and aspect ratio */
hgs
parents:
diff changeset
  1730
        n = aspect_n * stream->strf.vids->height;
hgs
parents:
diff changeset
  1731
        d = aspect_d * stream->strf.vids->width;
hgs
parents:
diff changeset
  1732
        if (n && d)
hgs
parents:
diff changeset
  1733
          gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
hgs
parents:
diff changeset
  1734
              n, d, NULL);
hgs
parents:
diff changeset
  1735
        /* very local, not needed elsewhere */
hgs
parents:
diff changeset
  1736
        g_free (vprp);
hgs
parents:
diff changeset
  1737
        vprp = NULL;
hgs
parents:
diff changeset
  1738
      }
hgs
parents:
diff changeset
  1739
      tag_name = GST_TAG_VIDEO_CODEC;
hgs
parents:
diff changeset
  1740
      avi->num_v_streams++;
hgs
parents:
diff changeset
  1741
      break;
hgs
parents:
diff changeset
  1742
    }
hgs
parents:
diff changeset
  1743
    case GST_RIFF_FCC_auds:{
hgs
parents:
diff changeset
  1744
      padname = g_strdup_printf ("audio_%02d", avi->num_a_streams);
hgs
parents:
diff changeset
  1745
      templ = gst_element_class_get_pad_template (klass, "audio_%02d");
hgs
parents:
diff changeset
  1746
      caps = gst_riff_create_audio_caps (stream->strf.auds->format,
hgs
parents:
diff changeset
  1747
          stream->strh, stream->strf.auds, stream->extradata,
hgs
parents:
diff changeset
  1748
          stream->initdata, &codec_name);
hgs
parents:
diff changeset
  1749
      if (!caps) {
hgs
parents:
diff changeset
  1750
        caps = gst_caps_new_simple ("audio/x-avi-unknown", "codec_id",
hgs
parents:
diff changeset
  1751
            G_TYPE_INT, stream->strf.auds->format, NULL);
hgs
parents:
diff changeset
  1752
      }
hgs
parents:
diff changeset
  1753
      tag_name = GST_TAG_AUDIO_CODEC;
hgs
parents:
diff changeset
  1754
      avi->num_a_streams++;
hgs
parents:
diff changeset
  1755
      break;
hgs
parents:
diff changeset
  1756
    }
hgs
parents:
diff changeset
  1757
    case GST_RIFF_FCC_iavs:{
hgs
parents:
diff changeset
  1758
      guint32 fourcc = stream->strh->fcc_handler;
hgs
parents:
diff changeset
  1759
hgs
parents:
diff changeset
  1760
      padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
hgs
parents:
diff changeset
  1761
      templ = gst_element_class_get_pad_template (klass, "video_%02d");
hgs
parents:
diff changeset
  1762
      caps = gst_riff_create_iavs_caps (fourcc, stream->strh,
hgs
parents:
diff changeset
  1763
          stream->strf.iavs, stream->extradata, stream->initdata, &codec_name);
hgs
parents:
diff changeset
  1764
      if (!caps) {
hgs
parents:
diff changeset
  1765
        caps = gst_caps_new_simple ("video/x-avi-unknown", "fourcc",
hgs
parents:
diff changeset
  1766
            GST_TYPE_FOURCC, fourcc, NULL);
hgs
parents:
diff changeset
  1767
      }
hgs
parents:
diff changeset
  1768
      tag_name = GST_TAG_VIDEO_CODEC;
hgs
parents:
diff changeset
  1769
      avi->num_v_streams++;
hgs
parents:
diff changeset
  1770
      break;
hgs
parents:
diff changeset
  1771
    }
hgs
parents:
diff changeset
  1772
    case GST_RIFF_FCC_txts:{
hgs
parents:
diff changeset
  1773
      padname = g_strdup_printf ("subtitle_%02d", avi->num_t_streams);
hgs
parents:
diff changeset
  1774
      templ = gst_element_class_get_pad_template (klass, "subtitle_%02d");
hgs
parents:
diff changeset
  1775
      caps = gst_caps_new_simple ("application/x-subtitle-avi", NULL);
hgs
parents:
diff changeset
  1776
      tag_name = NULL;
hgs
parents:
diff changeset
  1777
      avi->num_t_streams++;
hgs
parents:
diff changeset
  1778
      break;
hgs
parents:
diff changeset
  1779
    }
hgs
parents:
diff changeset
  1780
    default:
hgs
parents:
diff changeset
  1781
      g_assert_not_reached ();
hgs
parents:
diff changeset
  1782
  }
hgs
parents:
diff changeset
  1783
hgs
parents:
diff changeset
  1784
  /* no caps means no stream */
hgs
parents:
diff changeset
  1785
  if (!caps) {
hgs
parents:
diff changeset
  1786
    GST_ERROR_OBJECT (element, "Did not find caps for stream %s", padname);
hgs
parents:
diff changeset
  1787
    goto fail;
hgs
parents:
diff changeset
  1788
  }
hgs
parents:
diff changeset
  1789
hgs
parents:
diff changeset
  1790
  GST_DEBUG_OBJECT (element, "codec-name=%s",
hgs
parents:
diff changeset
  1791
      (codec_name ? codec_name : "NULL"));
hgs
parents:
diff changeset
  1792
  GST_DEBUG_OBJECT (element, "caps=%" GST_PTR_FORMAT, caps);
hgs
parents:
diff changeset
  1793
hgs
parents:
diff changeset
  1794
  /* set proper settings and add it */
hgs
parents:
diff changeset
  1795
  if (stream->pad)
hgs
parents:
diff changeset
  1796
    gst_object_unref (stream->pad);
hgs
parents:
diff changeset
  1797
  pad = stream->pad = gst_pad_new_from_template (templ, padname);
hgs
parents:
diff changeset
  1798
  stream->last_flow = GST_FLOW_OK;
hgs
parents:
diff changeset
  1799
  stream->discont = TRUE;
hgs
parents:
diff changeset
  1800
  g_free (padname);
hgs
parents:
diff changeset
  1801
hgs
parents:
diff changeset
  1802
  gst_pad_use_fixed_caps (pad);
hgs
parents:
diff changeset
  1803
#if 0
hgs
parents:
diff changeset
  1804
  gst_pad_set_formats_function (pad,
hgs
parents:
diff changeset
  1805
      GST_DEBUG_FUNCPTR (gst_avi_demux_get_src_formats));
hgs
parents:
diff changeset
  1806
  gst_pad_set_event_mask_function (pad,
hgs
parents:
diff changeset
  1807
      GST_DEBUG_FUNCPTR (gst_avi_demux_get_event_mask));
hgs
parents:
diff changeset
  1808
#endif
hgs
parents:
diff changeset
  1809
  gst_pad_set_event_function (pad,
hgs
parents:
diff changeset
  1810
      GST_DEBUG_FUNCPTR (gst_avi_demux_handle_src_event));
hgs
parents:
diff changeset
  1811
  gst_pad_set_query_type_function (pad,
hgs
parents:
diff changeset
  1812
      GST_DEBUG_FUNCPTR (gst_avi_demux_get_src_query_types));
hgs
parents:
diff changeset
  1813
  gst_pad_set_query_function (pad,
hgs
parents:
diff changeset
  1814
      GST_DEBUG_FUNCPTR (gst_avi_demux_handle_src_query));
hgs
parents:
diff changeset
  1815
#if 0
hgs
parents:
diff changeset
  1816
  gst_pad_set_convert_function (pad,
hgs
parents:
diff changeset
  1817
      GST_DEBUG_FUNCPTR (gst_avi_demux_src_convert));
hgs
parents:
diff changeset
  1818
#endif
hgs
parents:
diff changeset
  1819
hgs
parents:
diff changeset
  1820
  stream->num = avi->num_streams;
hgs
parents:
diff changeset
  1821
  stream->total_bytes = 0;
hgs
parents:
diff changeset
  1822
  stream->total_frames = 0;
hgs
parents:
diff changeset
  1823
  stream->total_blocks = 0;
hgs
parents:
diff changeset
  1824
  stream->current_frame = 0;
hgs
parents:
diff changeset
  1825
  stream->current_byte = 0;
hgs
parents:
diff changeset
  1826
  gst_pad_set_element_private (pad, stream);
hgs
parents:
diff changeset
  1827
  avi->num_streams++;
hgs
parents:
diff changeset
  1828
  gst_pad_set_caps (pad, caps);
hgs
parents:
diff changeset
  1829
  gst_pad_set_active (pad, TRUE);
hgs
parents:
diff changeset
  1830
  gst_element_add_pad (GST_ELEMENT (avi), pad);
hgs
parents:
diff changeset
  1831
  GST_LOG_OBJECT (element, "Added pad %s with caps %" GST_PTR_FORMAT,
hgs
parents:
diff changeset
  1832
      GST_PAD_NAME (pad), caps);
hgs
parents:
diff changeset
  1833
  gst_caps_unref (caps);
hgs
parents:
diff changeset
  1834
hgs
parents:
diff changeset
  1835
  /* make tags */
hgs
parents:
diff changeset
  1836
  if (codec_name) {
hgs
parents:
diff changeset
  1837
    if (!stream->taglist)
hgs
parents:
diff changeset
  1838
      stream->taglist = gst_tag_list_new ();
hgs
parents:
diff changeset
  1839
hgs
parents:
diff changeset
  1840
    avi->got_tags = TRUE;
hgs
parents:
diff changeset
  1841
hgs
parents:
diff changeset
  1842
    gst_tag_list_add (stream->taglist, GST_TAG_MERGE_APPEND, tag_name,
hgs
parents:
diff changeset
  1843
        codec_name, NULL);
hgs
parents:
diff changeset
  1844
    g_free (codec_name);
hgs
parents:
diff changeset
  1845
  }
hgs
parents:
diff changeset
  1846
hgs
parents:
diff changeset
  1847
  gst_buffer_unref (buf);
hgs
parents:
diff changeset
  1848
hgs
parents:
diff changeset
  1849
  return TRUE;
hgs
parents:
diff changeset
  1850
hgs
parents:
diff changeset
  1851
  /* ERRORS */
hgs
parents:
diff changeset
  1852
fail:
hgs
parents:
diff changeset
  1853
  {
hgs
parents:
diff changeset
  1854
    /* unref any mem that may be in use */
hgs
parents:
diff changeset
  1855
    if (buf)
hgs
parents:
diff changeset
  1856
      gst_buffer_unref (buf);
hgs
parents:
diff changeset
  1857
    if (sub)
hgs
parents:
diff changeset
  1858
      gst_buffer_unref (sub);
hgs
parents:
diff changeset
  1859
    g_free (vprp);
hgs
parents:
diff changeset
  1860
    g_free (codec_name);
hgs
parents:
diff changeset
  1861
    g_free (stream->strh);
hgs
parents:
diff changeset
  1862
    g_free (stream->strf.data);
hgs
parents:
diff changeset
  1863
    g_free (stream->name);
hgs
parents:
diff changeset
  1864
    g_free (stream->indexes);
hgs
parents:
diff changeset
  1865
    if (stream->initdata)
hgs
parents:
diff changeset
  1866
      gst_buffer_unref (stream->initdata);
hgs
parents:
diff changeset
  1867
    if (stream->extradata)
hgs
parents:
diff changeset
  1868
      gst_buffer_unref (stream->extradata);
hgs
parents:
diff changeset
  1869
    memset (stream, 0, sizeof (avi_stream_context));
hgs
parents:
diff changeset
  1870
    avi->num_streams++;
hgs
parents:
diff changeset
  1871
    return FALSE;
hgs
parents:
diff changeset
  1872
  }
hgs
parents:
diff changeset
  1873
}
hgs
parents:
diff changeset
  1874
hgs
parents:
diff changeset
  1875
/*
hgs
parents:
diff changeset
  1876
 * gst_avi_demux_parse_odml:
hgs
parents:
diff changeset
  1877
 * @avi: calling element (used for debug/error).
hgs
parents:
diff changeset
  1878
 * @buf: input buffer to be used for parsing.
hgs
parents:
diff changeset
  1879
 *
hgs
parents:
diff changeset
  1880
 * Read an openDML-2.0 extension header. Fills in the frame number
hgs
parents:
diff changeset
  1881
 * in the avi demuxer object when reading succeeds.
hgs
parents:
diff changeset
  1882
 */
hgs
parents:
diff changeset
  1883
static void
hgs
parents:
diff changeset
  1884
gst_avi_demux_parse_odml (GstAviDemux * avi, GstBuffer * buf)
hgs
parents:
diff changeset
  1885
{
hgs
parents:
diff changeset
  1886
  guint32 tag = 0;
hgs
parents:
diff changeset
  1887
  guint offset = 4;
hgs
parents:
diff changeset
  1888
  GstBuffer *sub = NULL;
hgs
parents:
diff changeset
  1889
hgs
parents:
diff changeset
  1890
  while (gst_riff_parse_chunk (GST_ELEMENT_CAST (avi), buf, &offset, &tag,
hgs
parents:
diff changeset
  1891
          &sub)) {
hgs
parents:
diff changeset
  1892
    switch (tag) {
hgs
parents:
diff changeset
  1893
      case GST_RIFF_TAG_dmlh:{
hgs
parents:
diff changeset
  1894
        gst_riff_dmlh dmlh, *_dmlh;
hgs
parents:
diff changeset
  1895
        guint size;
hgs
parents:
diff changeset
  1896
hgs
parents:
diff changeset
  1897
        /* sub == NULL is possible and means an empty buffer */
hgs
parents:
diff changeset
  1898
        size = sub ? GST_BUFFER_SIZE (sub) : 0;
hgs
parents:
diff changeset
  1899
hgs
parents:
diff changeset
  1900
        /* check size */
hgs
parents:
diff changeset
  1901
        if (size < sizeof (gst_riff_dmlh)) {
hgs
parents:
diff changeset
  1902
          GST_ERROR_OBJECT (avi,
hgs
parents:
diff changeset
  1903
              "DMLH entry is too small (%d bytes, %d needed)",
hgs
parents:
diff changeset
  1904
              size, (int) sizeof (gst_riff_dmlh));
hgs
parents:
diff changeset
  1905
          goto next;
hgs
parents:
diff changeset
  1906
        }
hgs
parents:
diff changeset
  1907
        _dmlh = (gst_riff_dmlh *) GST_BUFFER_DATA (sub);
hgs
parents:
diff changeset
  1908
        dmlh.totalframes = GST_READ_UINT32_LE (&_dmlh->totalframes);
hgs
parents:
diff changeset
  1909
hgs
parents:
diff changeset
  1910
        GST_INFO_OBJECT (avi, "dmlh tag found:");
hgs
parents:
diff changeset
  1911
        GST_INFO_OBJECT (avi, " totalframes: %u", dmlh.totalframes);
hgs
parents:
diff changeset
  1912
hgs
parents:
diff changeset
  1913
        avi->avih->tot_frames = dmlh.totalframes;
hgs
parents:
diff changeset
  1914
        goto next;
hgs
parents:
diff changeset
  1915
      }
hgs
parents:
diff changeset
  1916
hgs
parents:
diff changeset
  1917
      default:
hgs
parents:
diff changeset
  1918
        GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  1919
            "Unknown tag %" GST_FOURCC_FORMAT " in ODML header",
hgs
parents:
diff changeset
  1920
            GST_FOURCC_ARGS (tag));
hgs
parents:
diff changeset
  1921
        /* fall-through */
hgs
parents:
diff changeset
  1922
      case GST_RIFF_TAG_JUNK:
hgs
parents:
diff changeset
  1923
      next:
hgs
parents:
diff changeset
  1924
        /* skip and move to next chunk */
hgs
parents:
diff changeset
  1925
        if (sub) {
hgs
parents:
diff changeset
  1926
          gst_buffer_unref (sub);
hgs
parents:
diff changeset
  1927
          sub = NULL;
hgs
parents:
diff changeset
  1928
        }
hgs
parents:
diff changeset
  1929
        break;
hgs
parents:
diff changeset
  1930
    }
hgs
parents:
diff changeset
  1931
  }
hgs
parents:
diff changeset
  1932
  if (buf)
hgs
parents:
diff changeset
  1933
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  1934
}
hgs
parents:
diff changeset
  1935
hgs
parents:
diff changeset
  1936
/*
hgs
parents:
diff changeset
  1937
 * Sort helper for index entries that sorts by index time.
hgs
parents:
diff changeset
  1938
 * If times are equal we sort by stream number.
hgs
parents:
diff changeset
  1939
 */
hgs
parents:
diff changeset
  1940
static gint
hgs
parents:
diff changeset
  1941
sort (gst_avi_index_entry * a, gst_avi_index_entry * b)
hgs
parents:
diff changeset
  1942
{
hgs
parents:
diff changeset
  1943
  if (a->ts > b->ts)
hgs
parents:
diff changeset
  1944
    return 1;
hgs
parents:
diff changeset
  1945
  else if (a->ts < b->ts)
hgs
parents:
diff changeset
  1946
    return -1;
hgs
parents:
diff changeset
  1947
  else
hgs
parents:
diff changeset
  1948
    return a->stream_nr - b->stream_nr;
hgs
parents:
diff changeset
  1949
}
hgs
parents:
diff changeset
  1950
hgs
parents:
diff changeset
  1951
/*
hgs
parents:
diff changeset
  1952
 * gst_avi_demux_parse_index:
hgs
parents:
diff changeset
  1953
 * @avi: calling element (used for debugging/errors).
hgs
parents:
diff changeset
  1954
 * @buf: buffer containing the full index.
hgs
parents:
diff changeset
  1955
 * @entries_list: list (returned by this function) containing the index
hgs
parents:
diff changeset
  1956
 *                entries parsed from the buffer. The first in the list
hgs
parents:
diff changeset
  1957
 *                is also a pointer to the allocated data and should be
hgs
parents:
diff changeset
  1958
 *                free'ed at some point.
hgs
parents:
diff changeset
  1959
 *
hgs
parents:
diff changeset
  1960
 * Read index entries from the provided buffer. Takes ownership of @buf.
hgs
parents:
diff changeset
  1961
 */
hgs
parents:
diff changeset
  1962
static void
hgs
parents:
diff changeset
  1963
gst_avi_demux_parse_index (GstAviDemux * avi,
hgs
parents:
diff changeset
  1964
    GstBuffer * buf, GList ** _entries_list)
hgs
parents:
diff changeset
  1965
{
hgs
parents:
diff changeset
  1966
  guint64 pos_before = avi->offset;
hgs
parents:
diff changeset
  1967
  gst_avi_index_entry *entries = NULL;
hgs
parents:
diff changeset
  1968
  guint8 *data;
hgs
parents:
diff changeset
  1969
  GList *entries_list = NULL;
hgs
parents:
diff changeset
  1970
  guint i, num, n;
hgs
parents:
diff changeset
  1971
hgs
parents:
diff changeset
  1972
#ifndef GST_DISABLE_GST_DEBUG
hgs
parents:
diff changeset
  1973
  gulong _nr_keyframes = 0;
hgs
parents:
diff changeset
  1974
#endif
hgs
parents:
diff changeset
  1975
hgs
parents:
diff changeset
  1976
  if (!buf || !GST_BUFFER_SIZE (buf)) {
hgs
parents:
diff changeset
  1977
    *_entries_list = NULL;
hgs
parents:
diff changeset
  1978
    GST_DEBUG ("empty index");
hgs
parents:
diff changeset
  1979
    if (buf)
hgs
parents:
diff changeset
  1980
      gst_buffer_unref (buf);
hgs
parents:
diff changeset
  1981
    return;
hgs
parents:
diff changeset
  1982
  }
hgs
parents:
diff changeset
  1983
hgs
parents:
diff changeset
  1984
  data = GST_BUFFER_DATA (buf);
hgs
parents:
diff changeset
  1985
  num = GST_BUFFER_SIZE (buf) / sizeof (gst_riff_index_entry);
hgs
parents:
diff changeset
  1986
  if (!(entries = g_try_new (gst_avi_index_entry, num)))
hgs
parents:
diff changeset
  1987
    goto out_of_mem;
hgs
parents:
diff changeset
  1988
hgs
parents:
diff changeset
  1989
  GST_INFO ("Parsing index, nr_entries = %6d", num);
hgs
parents:
diff changeset
  1990
hgs
parents:
diff changeset
  1991
  for (i = 0, n = 0; i < num; i++) {
hgs
parents:
diff changeset
  1992
    gint64 next_ts;
hgs
parents:
diff changeset
  1993
    gst_riff_index_entry entry, *_entry;
hgs
parents:
diff changeset
  1994
    avi_stream_context *stream;
hgs
parents:
diff changeset
  1995
    guint stream_nr;
hgs
parents:
diff changeset
  1996
    gst_avi_index_entry *target;
hgs
parents:
diff changeset
  1997
hgs
parents:
diff changeset
  1998
    _entry = &((gst_riff_index_entry *) data)[i];
hgs
parents:
diff changeset
  1999
    entry.id = GST_READ_UINT32_LE (&_entry->id);
hgs
parents:
diff changeset
  2000
    entry.offset = GST_READ_UINT32_LE (&_entry->offset);
hgs
parents:
diff changeset
  2001
    entry.flags = GST_READ_UINT32_LE (&_entry->flags);
hgs
parents:
diff changeset
  2002
    entry.size = GST_READ_UINT32_LE (&_entry->size);
hgs
parents:
diff changeset
  2003
    target = &entries[n];
hgs
parents:
diff changeset
  2004
hgs
parents:
diff changeset
  2005
    if (entry.id == GST_RIFF_rec || entry.id == 0 ||
hgs
parents:
diff changeset
  2006
        (entry.offset == 0 && n > 0))
hgs
parents:
diff changeset
  2007
      continue;
hgs
parents:
diff changeset
  2008
hgs
parents:
diff changeset
  2009
    stream_nr = CHUNKID_TO_STREAMNR (entry.id);
hgs
parents:
diff changeset
  2010
    if (stream_nr >= avi->num_streams) {
hgs
parents:
diff changeset
  2011
      GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  2012
          "Index entry %d has invalid stream nr %d", i, stream_nr);
hgs
parents:
diff changeset
  2013
      continue;
hgs
parents:
diff changeset
  2014
    }
hgs
parents:
diff changeset
  2015
    target->stream_nr = stream_nr;
hgs
parents:
diff changeset
  2016
    stream = &avi->stream[stream_nr];
hgs
parents:
diff changeset
  2017
hgs
parents:
diff changeset
  2018
    if (!stream->strh) {
hgs
parents:
diff changeset
  2019
      GST_WARNING_OBJECT (avi, "Unhandled stream %d, skipping", stream_nr);
hgs
parents:
diff changeset
  2020
      continue;
hgs
parents:
diff changeset
  2021
    }
hgs
parents:
diff changeset
  2022
hgs
parents:
diff changeset
  2023
    target->index_nr = i;
hgs
parents:
diff changeset
  2024
    target->flags =
hgs
parents:
diff changeset
  2025
        (entry.flags & GST_RIFF_IF_KEYFRAME) ? GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME
hgs
parents:
diff changeset
  2026
        : 0;
hgs
parents:
diff changeset
  2027
    target->size = entry.size;
hgs
parents:
diff changeset
  2028
    target->offset = entry.offset + 8;
hgs
parents:
diff changeset
  2029
hgs
parents:
diff changeset
  2030
    /* figure out if the index is 0 based or relative to the MOVI start */
hgs
parents:
diff changeset
  2031
    if (n == 0) {
hgs
parents:
diff changeset
  2032
      if (target->offset < pos_before)
hgs
parents:
diff changeset
  2033
        avi->index_offset = pos_before + 8;
hgs
parents:
diff changeset
  2034
      else
hgs
parents:
diff changeset
  2035
        avi->index_offset = 0;
hgs
parents:
diff changeset
  2036
      GST_DEBUG ("index_offset = %" G_GUINT64_FORMAT, avi->index_offset);
hgs
parents:
diff changeset
  2037
    }
hgs
parents:
diff changeset
  2038
hgs
parents:
diff changeset
  2039
    if (stream->strh->type == GST_RIFF_FCC_auds) {
hgs
parents:
diff changeset
  2040
      /* all audio frames are keyframes */
hgs
parents:
diff changeset
  2041
      target->flags |= GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME;
hgs
parents:
diff changeset
  2042
    }
hgs
parents:
diff changeset
  2043
#ifndef GST_DISABLE_GST_DEBUG
hgs
parents:
diff changeset
  2044
    if (target->flags & GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME)
hgs
parents:
diff changeset
  2045
      _nr_keyframes++;
hgs
parents:
diff changeset
  2046
#endif
hgs
parents:
diff changeset
  2047
hgs
parents:
diff changeset
  2048
    /* stream duration unknown, now we can calculate it */
hgs
parents:
diff changeset
  2049
    if (stream->idx_duration == -1)
hgs
parents:
diff changeset
  2050
      stream->idx_duration = 0;
hgs
parents:
diff changeset
  2051
hgs
parents:
diff changeset
  2052
    /* timestamps */
hgs
parents:
diff changeset
  2053
    target->ts = stream->idx_duration;
hgs
parents:
diff changeset
  2054
    if (stream->is_vbr) {
hgs
parents:
diff changeset
  2055
      /* VBR stream next timestamp */
hgs
parents:
diff changeset
  2056
      if (stream->strh->type == GST_RIFF_FCC_auds) {
hgs
parents:
diff changeset
  2057
        next_ts = avi_stream_convert_frames_to_time_unchecked (stream,
hgs
parents:
diff changeset
  2058
            stream->total_blocks + 1);
hgs
parents:
diff changeset
  2059
      } else {
hgs
parents:
diff changeset
  2060
        next_ts = avi_stream_convert_frames_to_time_unchecked (stream,
hgs
parents:
diff changeset
  2061
            stream->total_frames + 1);
hgs
parents:
diff changeset
  2062
      }
hgs
parents:
diff changeset
  2063
    } else {
hgs
parents:
diff changeset
  2064
      /* constant rate stream */
hgs
parents:
diff changeset
  2065
      next_ts = avi_stream_convert_bytes_to_time_unchecked (stream,
hgs
parents:
diff changeset
  2066
          stream->total_bytes + target->size);
hgs
parents:
diff changeset
  2067
    }
hgs
parents:
diff changeset
  2068
    /* duration is next - current */
hgs
parents:
diff changeset
  2069
    target->dur = next_ts - target->ts;
hgs
parents:
diff changeset
  2070
hgs
parents:
diff changeset
  2071
    /* stream position */
hgs
parents:
diff changeset
  2072
    target->bytes_before = stream->total_bytes;
hgs
parents:
diff changeset
  2073
    target->frames_before = stream->total_frames;
hgs
parents:
diff changeset
  2074
hgs
parents:
diff changeset
  2075
    stream->total_bytes += target->size;
hgs
parents:
diff changeset
  2076
    stream->total_frames++;
hgs
parents:
diff changeset
  2077
    if (stream->strh->type == GST_RIFF_FCC_auds) {
hgs
parents:
diff changeset
  2078
      if (stream->strf.auds->blockalign > 0)
hgs
parents:
diff changeset
  2079
        stream->total_blocks +=
hgs
parents:
diff changeset
  2080
            (target->size + stream->strf.auds->blockalign -
hgs
parents:
diff changeset
  2081
            1) / stream->strf.auds->blockalign;
hgs
parents:
diff changeset
  2082
      else
hgs
parents:
diff changeset
  2083
        stream->total_blocks++;
hgs
parents:
diff changeset
  2084
    }
hgs
parents:
diff changeset
  2085
    stream->idx_duration = next_ts;
hgs
parents:
diff changeset
  2086
hgs
parents:
diff changeset
  2087
    GST_LOG_OBJECT (avi,
hgs
parents:
diff changeset
  2088
        "Adding index entry %d (%6u), flags %02x, stream %d, size %u "
hgs
parents:
diff changeset
  2089
        ", offset %" G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT ", dur %"
hgs
parents:
diff changeset
  2090
        GST_TIME_FORMAT,
hgs
parents:
diff changeset
  2091
        target->index_nr, stream->total_frames - 1, target->flags,
hgs
parents:
diff changeset
  2092
        target->stream_nr, target->size, target->offset,
hgs
parents:
diff changeset
  2093
        GST_TIME_ARGS (target->ts), GST_TIME_ARGS (target->dur));
hgs
parents:
diff changeset
  2094
    entries_list = g_list_prepend (entries_list, target);
hgs
parents:
diff changeset
  2095
hgs
parents:
diff changeset
  2096
    n++;
hgs
parents:
diff changeset
  2097
  }
hgs
parents:
diff changeset
  2098
hgs
parents:
diff changeset
  2099
  GST_INFO ("Parsed index, %6d entries, %5ld keyframes, entry size = %2d, "
hgs
parents:
diff changeset
  2100
      "total size = %10d", num, _nr_keyframes,
hgs
parents:
diff changeset
  2101
      (gint) sizeof (gst_avi_index_entry),
hgs
parents:
diff changeset
  2102
      (gint) (num * sizeof (gst_avi_index_entry)));
hgs
parents:
diff changeset
  2103
hgs
parents:
diff changeset
  2104
  gst_buffer_unref (buf);
hgs
parents:
diff changeset
  2105
hgs
parents:
diff changeset
  2106
  if (n > 0) {
hgs
parents:
diff changeset
  2107
    *_entries_list = g_list_reverse (entries_list);
hgs
parents:
diff changeset
  2108
  } else {
hgs
parents:
diff changeset
  2109
    g_free (entries);
hgs
parents:
diff changeset
  2110
  }
hgs
parents:
diff changeset
  2111
  return;
hgs
parents:
diff changeset
  2112
hgs
parents:
diff changeset
  2113
  /* ERRORS */
hgs
parents:
diff changeset
  2114
out_of_mem:
hgs
parents:
diff changeset
  2115
  {
hgs
parents:
diff changeset
  2116
    GST_ELEMENT_ERROR (avi, RESOURCE, NO_SPACE_LEFT, (NULL),
hgs
parents:
diff changeset
  2117
        ("Cannot allocate memory for %u*%u=%u bytes",
hgs
parents:
diff changeset
  2118
            (guint) sizeof (gst_avi_index_entry), num,
hgs
parents:
diff changeset
  2119
            (guint) sizeof (gst_avi_index_entry) * num));
hgs
parents:
diff changeset
  2120
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  2121
  }
hgs
parents:
diff changeset
  2122
}
hgs
parents:
diff changeset
  2123
hgs
parents:
diff changeset
  2124
/*
hgs
parents:
diff changeset
  2125
 * gst_avi_demux_stream_index:
hgs
parents:
diff changeset
  2126
 * @avi: avi demuxer object.
hgs
parents:
diff changeset
  2127
 * @index: list of index entries, returned by this function.
hgs
parents:
diff changeset
  2128
 * @alloc_list: list of allocated data, returned by this function.
hgs
parents:
diff changeset
  2129
 *
hgs
parents:
diff changeset
  2130
 * Seeks to index and reads it.
hgs
parents:
diff changeset
  2131
 */
hgs
parents:
diff changeset
  2132
static void
hgs
parents:
diff changeset
  2133
gst_avi_demux_stream_index (GstAviDemux * avi,
hgs
parents:
diff changeset
  2134
    GList ** index, GList ** alloc_list)
hgs
parents:
diff changeset
  2135
{
hgs
parents:
diff changeset
  2136
  GstFlowReturn res;
hgs
parents:
diff changeset
  2137
  guint64 offset = avi->offset;
hgs
parents:
diff changeset
  2138
  GstBuffer *buf;
hgs
parents:
diff changeset
  2139
  guint32 tag;
hgs
parents:
diff changeset
  2140
  guint32 size;
hgs
parents:
diff changeset
  2141
  gint i;
hgs
parents:
diff changeset
  2142
hgs
parents:
diff changeset
  2143
  GST_DEBUG ("demux stream index at offset %" G_GUINT64_FORMAT, offset);
hgs
parents:
diff changeset
  2144
hgs
parents:
diff changeset
  2145
  *alloc_list = NULL;
hgs
parents:
diff changeset
  2146
  *index = NULL;
hgs
parents:
diff changeset
  2147
hgs
parents:
diff changeset
  2148
  /* get chunk information */
hgs
parents:
diff changeset
  2149
  res = gst_pad_pull_range (avi->sinkpad, offset, 8, &buf);
hgs
parents:
diff changeset
  2150
  if (res != GST_FLOW_OK)
hgs
parents:
diff changeset
  2151
    goto pull_failed;
hgs
parents:
diff changeset
  2152
  else if (GST_BUFFER_SIZE (buf) < 8)
hgs
parents:
diff changeset
  2153
    goto too_small;
hgs
parents:
diff changeset
  2154
hgs
parents:
diff changeset
  2155
  /* check tag first before blindy trying to read 'size' bytes */
hgs
parents:
diff changeset
  2156
  tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
hgs
parents:
diff changeset
  2157
  size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4);
hgs
parents:
diff changeset
  2158
  if (tag == GST_RIFF_TAG_LIST) {
hgs
parents:
diff changeset
  2159
    /* this is the movi tag */
hgs
parents:
diff changeset
  2160
    GST_DEBUG_OBJECT (avi, "skip LIST chunk, size %" G_GUINT32_FORMAT,
hgs
parents:
diff changeset
  2161
        (8 + ((size + 1) & ~1)));
hgs
parents:
diff changeset
  2162
    offset += 8 + ((size + 1) & ~1);
hgs
parents:
diff changeset
  2163
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  2164
    res = gst_pad_pull_range (avi->sinkpad, offset, 8, &buf);
hgs
parents:
diff changeset
  2165
    if (res != GST_FLOW_OK)
hgs
parents:
diff changeset
  2166
      goto pull_failed;
hgs
parents:
diff changeset
  2167
    else if (GST_BUFFER_SIZE (buf) < 8)
hgs
parents:
diff changeset
  2168
      goto too_small;
hgs
parents:
diff changeset
  2169
    tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
hgs
parents:
diff changeset
  2170
    size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4);
hgs
parents:
diff changeset
  2171
  }
hgs
parents:
diff changeset
  2172
hgs
parents:
diff changeset
  2173
  if (tag != GST_RIFF_TAG_idx1)
hgs
parents:
diff changeset
  2174
    goto no_index;
hgs
parents:
diff changeset
  2175
  if (!size)
hgs
parents:
diff changeset
  2176
    goto zero_index;
hgs
parents:
diff changeset
  2177
hgs
parents:
diff changeset
  2178
  gst_buffer_unref (buf);
hgs
parents:
diff changeset
  2179
hgs
parents:
diff changeset
  2180
  GST_DEBUG ("index found at offset %" G_GUINT64_FORMAT, offset);
hgs
parents:
diff changeset
  2181
hgs
parents:
diff changeset
  2182
  /* read chunk, advance offset */
hgs
parents:
diff changeset
  2183
  if (gst_riff_read_chunk (GST_ELEMENT_CAST (avi),
hgs
parents:
diff changeset
  2184
          avi->sinkpad, &offset, &tag, &buf) != GST_FLOW_OK)
hgs
parents:
diff changeset
  2185
    return;
hgs
parents:
diff changeset
  2186
hgs
parents:
diff changeset
  2187
  GST_INFO ("will parse index chunk size %u for tag %"
hgs
parents:
diff changeset
  2188
      GST_FOURCC_FORMAT, GST_BUFFER_SIZE (buf), GST_FOURCC_ARGS (tag));
hgs
parents:
diff changeset
  2189
hgs
parents:
diff changeset
  2190
  gst_avi_demux_parse_index (avi, buf, index);
hgs
parents:
diff changeset
  2191
  if (*index)
hgs
parents:
diff changeset
  2192
    *alloc_list = g_list_append (*alloc_list, (*index)->data);
hgs
parents:
diff changeset
  2193
hgs
parents:
diff changeset
  2194
  /* debug our indexes */
hgs
parents:
diff changeset
  2195
  for (i = 0; i < avi->num_streams; i++) {
hgs
parents:
diff changeset
  2196
    avi_stream_context *stream;
hgs
parents:
diff changeset
  2197
hgs
parents:
diff changeset
  2198
    stream = &avi->stream[i];
hgs
parents:
diff changeset
  2199
    GST_DEBUG_OBJECT (avi, "stream %u: %u frames, %" G_GINT64_FORMAT " bytes",
hgs
parents:
diff changeset
  2200
        i, stream->total_frames, stream->total_bytes);
hgs
parents:
diff changeset
  2201
  }
hgs
parents:
diff changeset
  2202
  return;
hgs
parents:
diff changeset
  2203
hgs
parents:
diff changeset
  2204
  /* ERRORS */
hgs
parents:
diff changeset
  2205
pull_failed:
hgs
parents:
diff changeset
  2206
  {
hgs
parents:
diff changeset
  2207
    GST_DEBUG_OBJECT (avi,
hgs
parents:
diff changeset
  2208
        "pull range failed: pos=%" G_GUINT64_FORMAT " size=8", offset);
hgs
parents:
diff changeset
  2209
    return;
hgs
parents:
diff changeset
  2210
  }
hgs
parents:
diff changeset
  2211
too_small:
hgs
parents:
diff changeset
  2212
  {
hgs
parents:
diff changeset
  2213
    GST_DEBUG_OBJECT (avi, "Buffer is too small");
hgs
parents:
diff changeset
  2214
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  2215
    return;
hgs
parents:
diff changeset
  2216
  }
hgs
parents:
diff changeset
  2217
no_index:
hgs
parents:
diff changeset
  2218
  {
hgs
parents:
diff changeset
  2219
    GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  2220
        "No index data (idx1) after movi chunk, but %" GST_FOURCC_FORMAT,
hgs
parents:
diff changeset
  2221
        GST_FOURCC_ARGS (tag));
hgs
parents:
diff changeset
  2222
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  2223
    return;
hgs
parents:
diff changeset
  2224
  }
hgs
parents:
diff changeset
  2225
zero_index:
hgs
parents:
diff changeset
  2226
  {
hgs
parents:
diff changeset
  2227
    GST_WARNING_OBJECT (avi, "Empty index data (idx1) after movi chunk");
hgs
parents:
diff changeset
  2228
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  2229
    return;
hgs
parents:
diff changeset
  2230
  }
hgs
parents:
diff changeset
  2231
}
hgs
parents:
diff changeset
  2232
hgs
parents:
diff changeset
  2233
#if 0
hgs
parents:
diff changeset
  2234
/*
hgs
parents:
diff changeset
  2235
 * Sync to next data chunk.
hgs
parents:
diff changeset
  2236
 */
hgs
parents:
diff changeset
  2237
static gboolean
hgs
parents:
diff changeset
  2238
gst_avi_demux_skip (GstAviDemux * avi, gboolean prevent_eos)
hgs
parents:
diff changeset
  2239
{
hgs
parents:
diff changeset
  2240
  GstRiffRead *riff = GST_RIFF_READ (avi);
hgs
parents:
diff changeset
  2241
hgs
parents:
diff changeset
  2242
  if (prevent_eos) {
hgs
parents:
diff changeset
  2243
    guint64 pos, length;
hgs
parents:
diff changeset
  2244
    guint size;
hgs
parents:
diff changeset
  2245
    guint8 *data;
hgs
parents:
diff changeset
  2246
hgs
parents:
diff changeset
  2247
    pos = gst_bytestream_tell (riff->bs);
hgs
parents:
diff changeset
  2248
    length = gst_bytestream_length (riff->bs);
hgs
parents:
diff changeset
  2249
hgs
parents:
diff changeset
  2250
    if (pos + 8 > length)
hgs
parents:
diff changeset
  2251
      return FALSE;
hgs
parents:
diff changeset
  2252
hgs
parents:
diff changeset
  2253
    if (gst_bytestream_peek_bytes (riff->bs, &data, 8) != 8)
hgs
parents:
diff changeset
  2254
      return FALSE;
hgs
parents:
diff changeset
  2255
hgs
parents:
diff changeset
  2256
    size = GST_READ_UINT32_LE (&data[4]);
hgs
parents:
diff changeset
  2257
    if (size & 1)
hgs
parents:
diff changeset
  2258
      size++;
hgs
parents:
diff changeset
  2259
hgs
parents:
diff changeset
  2260
    /* Note, we're going to skip which might involve seeks. Therefore,
hgs
parents:
diff changeset
  2261
     * we need 1 byte more! */
hgs
parents:
diff changeset
  2262
    if (pos + 8 + size >= length)
hgs
parents:
diff changeset
  2263
      return FALSE;
hgs
parents:
diff changeset
  2264
  }
hgs
parents:
diff changeset
  2265
hgs
parents:
diff changeset
  2266
  return gst_riff_read_skip (riff);
hgs
parents:
diff changeset
  2267
}
hgs
parents:
diff changeset
  2268
hgs
parents:
diff changeset
  2269
static gboolean
hgs
parents:
diff changeset
  2270
gst_avi_demux_sync (GstAviDemux * avi, guint32 * ret_tag, gboolean prevent_eos)
hgs
parents:
diff changeset
  2271
{
hgs
parents:
diff changeset
  2272
  GstRiffRead *riff = GST_RIFF_READ (avi);
hgs
parents:
diff changeset
  2273
  guint32 tag;
hgs
parents:
diff changeset
  2274
  guint64 length = gst_bytestream_length (riff->bs);
hgs
parents:
diff changeset
  2275
hgs
parents:
diff changeset
  2276
  if (prevent_eos && gst_bytestream_tell (riff->bs) + 12 >= length)
hgs
parents:
diff changeset
  2277
    return FALSE;
hgs
parents:
diff changeset
  2278
hgs
parents:
diff changeset
  2279
  /* peek first (for the end of this 'list/movi' section) */
hgs
parents:
diff changeset
  2280
  if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
hgs
parents:
diff changeset
  2281
    return FALSE;
hgs
parents:
diff changeset
  2282
hgs
parents:
diff changeset
  2283
  /* if we're at top-level, we didn't read the 'movi'
hgs
parents:
diff changeset
  2284
   * list tag yet. This can also be 'AVIX' in case of
hgs
parents:
diff changeset
  2285
   * openDML-2.0 AVI files. Lastly, it might be idx1,
hgs
parents:
diff changeset
  2286
   * in which case we skip it so we come at EOS. */
hgs
parents:
diff changeset
  2287
  while (1) {
hgs
parents:
diff changeset
  2288
    if (prevent_eos && gst_bytestream_tell (riff->bs) + 12 >= length)
hgs
parents:
diff changeset
  2289
      return FALSE;
hgs
parents:
diff changeset
  2290
hgs
parents:
diff changeset
  2291
    if (!(tag = gst_riff_peek_tag (riff, NULL)))
hgs
parents:
diff changeset
  2292
      return FALSE;
hgs
parents:
diff changeset
  2293
hgs
parents:
diff changeset
  2294
    switch (tag) {
hgs
parents:
diff changeset
  2295
      case GST_RIFF_TAG_LIST:
hgs
parents:
diff changeset
  2296
        if (!(tag = gst_riff_peek_list (riff)))
hgs
parents:
diff changeset
  2297
          return FALSE;
hgs
parents:
diff changeset
  2298
hgs
parents:
diff changeset
  2299
        switch (tag) {
hgs
parents:
diff changeset
  2300
          case GST_RIFF_LIST_AVIX:
hgs
parents:
diff changeset
  2301
            if (!gst_riff_read_list (riff, &tag))
hgs
parents:
diff changeset
  2302
              return FALSE;
hgs
parents:
diff changeset
  2303
            break;
hgs
parents:
diff changeset
  2304
hgs
parents:
diff changeset
  2305
          case GST_RIFF_LIST_movi:
hgs
parents:
diff changeset
  2306
            if (!gst_riff_read_list (riff, &tag))
hgs
parents:
diff changeset
  2307
              return FALSE;
hgs
parents:
diff changeset
  2308
            /* fall-through */
hgs
parents:
diff changeset
  2309
hgs
parents:
diff changeset
  2310
          case GST_RIFF_rec:
hgs
parents:
diff changeset
  2311
            goto done;
hgs
parents:
diff changeset
  2312
hgs
parents:
diff changeset
  2313
          default:
hgs
parents:
diff changeset
  2314
            GST_WARNING ("Unknown list %" GST_FOURCC_FORMAT " before AVI data",
hgs
parents:
diff changeset
  2315
                GST_FOURCC_ARGS (tag));
hgs
parents:
diff changeset
  2316
            /* fall-through */
hgs
parents:
diff changeset
  2317
hgs
parents:
diff changeset
  2318
          case GST_RIFF_TAG_JUNK:
hgs
parents:
diff changeset
  2319
            if (!gst_avi_demux_skip (avi, prevent_eos))
hgs
parents:
diff changeset
  2320
              return FALSE;
hgs
parents:
diff changeset
  2321
            break;
hgs
parents:
diff changeset
  2322
        }
hgs
parents:
diff changeset
  2323
        break;
hgs
parents:
diff changeset
  2324
hgs
parents:
diff changeset
  2325
      default:
hgs
parents:
diff changeset
  2326
        if ((tag & 0xff) >= '0' && (tag & 0xff) <= '9' &&
hgs
parents:
diff changeset
  2327
            ((tag >> 8) & 0xff) >= '0' && ((tag >> 8) & 0xff) <= '9') {
hgs
parents:
diff changeset
  2328
          goto done;
hgs
parents:
diff changeset
  2329
        }
hgs
parents:
diff changeset
  2330
        /* pass-through */
hgs
parents:
diff changeset
  2331
hgs
parents:
diff changeset
  2332
      case GST_RIFF_TAG_idx1:
hgs
parents:
diff changeset
  2333
      case GST_RIFF_TAG_JUNK:
hgs
parents:
diff changeset
  2334
        if (!gst_avi_demux_skip (avi, prevent_eos)) {
hgs
parents:
diff changeset
  2335
          return FALSE;
hgs
parents:
diff changeset
  2336
        }
hgs
parents:
diff changeset
  2337
        break;
hgs
parents:
diff changeset
  2338
    }
hgs
parents:
diff changeset
  2339
  }
hgs
parents:
diff changeset
  2340
done:
hgs
parents:
diff changeset
  2341
  /* And then, we get the data */
hgs
parents:
diff changeset
  2342
  if (prevent_eos && gst_bytestream_tell (riff->bs) + 12 >= length)
hgs
parents:
diff changeset
  2343
    return FALSE;
hgs
parents:
diff changeset
  2344
hgs
parents:
diff changeset
  2345
  if (!(tag = gst_riff_peek_tag (riff, NULL)))
hgs
parents:
diff changeset
  2346
    return FALSE;
hgs
parents:
diff changeset
  2347
hgs
parents:
diff changeset
  2348
  /* Support for rec-list files */
hgs
parents:
diff changeset
  2349
  switch (tag) {
hgs
parents:
diff changeset
  2350
    case GST_RIFF_TAG_LIST:
hgs
parents:
diff changeset
  2351
      if (!(tag = gst_riff_peek_list (riff)))
hgs
parents:
diff changeset
  2352
        return FALSE;
hgs
parents:
diff changeset
  2353
      if (tag == GST_RIFF_rec) {
hgs
parents:
diff changeset
  2354
        /* Simply skip the list */
hgs
parents:
diff changeset
  2355
        if (!gst_riff_read_list (riff, &tag))
hgs
parents:
diff changeset
  2356
          return FALSE;
hgs
parents:
diff changeset
  2357
        if (!(tag = gst_riff_peek_tag (riff, NULL)))
hgs
parents:
diff changeset
  2358
          return FALSE;
hgs
parents:
diff changeset
  2359
      }
hgs
parents:
diff changeset
  2360
      break;
hgs
parents:
diff changeset
  2361
hgs
parents:
diff changeset
  2362
    case GST_RIFF_TAG_JUNK:
hgs
parents:
diff changeset
  2363
      gst_avi_demux_skip (avi, prevent_eos);
hgs
parents:
diff changeset
  2364
      return FALSE;
hgs
parents:
diff changeset
  2365
  }
hgs
parents:
diff changeset
  2366
hgs
parents:
diff changeset
  2367
  if (ret_tag)
hgs
parents:
diff changeset
  2368
    *ret_tag = tag;
hgs
parents:
diff changeset
  2369
hgs
parents:
diff changeset
  2370
  return TRUE;
hgs
parents:
diff changeset
  2371
}
hgs
parents:
diff changeset
  2372
#endif
hgs
parents:
diff changeset
  2373
hgs
parents:
diff changeset
  2374
/*
hgs
parents:
diff changeset
  2375
 * gst_avi_demux_peek_tag:
hgs
parents:
diff changeset
  2376
 *
hgs
parents:
diff changeset
  2377
 * Returns the tag and size of the next chunk
hgs
parents:
diff changeset
  2378
 */
hgs
parents:
diff changeset
  2379
static GstFlowReturn
hgs
parents:
diff changeset
  2380
gst_avi_demux_peek_tag (GstAviDemux * avi, guint64 offset, guint32 * tag,
hgs
parents:
diff changeset
  2381
    guint * size)
hgs
parents:
diff changeset
  2382
{
hgs
parents:
diff changeset
  2383
  GstFlowReturn res = GST_FLOW_OK;
hgs
parents:
diff changeset
  2384
  GstBuffer *buf = NULL;
hgs
parents:
diff changeset
  2385
  guint bufsize;
hgs
parents:
diff changeset
  2386
hgs
parents:
diff changeset
  2387
  res = gst_pad_pull_range (avi->sinkpad, offset, 8, &buf);
hgs
parents:
diff changeset
  2388
  if (res != GST_FLOW_OK)
hgs
parents:
diff changeset
  2389
    goto pull_failed;
hgs
parents:
diff changeset
  2390
hgs
parents:
diff changeset
  2391
  bufsize = GST_BUFFER_SIZE (buf);
hgs
parents:
diff changeset
  2392
  if (bufsize != 8)
hgs
parents:
diff changeset
  2393
    goto wrong_size;
hgs
parents:
diff changeset
  2394
hgs
parents:
diff changeset
  2395
  *tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
hgs
parents:
diff changeset
  2396
  *size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4);
hgs
parents:
diff changeset
  2397
hgs
parents:
diff changeset
  2398
  GST_LOG_OBJECT (avi, "Tag[%" GST_FOURCC_FORMAT "] (size:%d) %"
hgs
parents:
diff changeset
  2399
      G_GINT64_FORMAT " -- %" G_GINT64_FORMAT, GST_FOURCC_ARGS (*tag),
hgs
parents:
diff changeset
  2400
      *size, offset + 8, offset + 8 + (gint64) * size);
hgs
parents:
diff changeset
  2401
done:
hgs
parents:
diff changeset
  2402
  gst_buffer_unref (buf);
hgs
parents:
diff changeset
  2403
hgs
parents:
diff changeset
  2404
  return res;
hgs
parents:
diff changeset
  2405
hgs
parents:
diff changeset
  2406
  /* ERRORS */
hgs
parents:
diff changeset
  2407
pull_failed:
hgs
parents:
diff changeset
  2408
  {
hgs
parents:
diff changeset
  2409
    GST_DEBUG_OBJECT (avi, "pull_ranged returned %s", gst_flow_get_name (res));
hgs
parents:
diff changeset
  2410
    return res;
hgs
parents:
diff changeset
  2411
  }
hgs
parents:
diff changeset
  2412
wrong_size:
hgs
parents:
diff changeset
  2413
  {
hgs
parents:
diff changeset
  2414
    GST_DEBUG_OBJECT (avi, "got %d bytes which is <> 8 bytes", bufsize);
hgs
parents:
diff changeset
  2415
    res = GST_FLOW_ERROR;
hgs
parents:
diff changeset
  2416
    goto done;
hgs
parents:
diff changeset
  2417
  }
hgs
parents:
diff changeset
  2418
}
hgs
parents:
diff changeset
  2419
hgs
parents:
diff changeset
  2420
/*
hgs
parents:
diff changeset
  2421
 * gst_avi_demux_next_data_buffer:
hgs
parents:
diff changeset
  2422
 *
hgs
parents:
diff changeset
  2423
 * Returns the offset and size of the next buffer
hgs
parents:
diff changeset
  2424
 * Position is the position of the buffer (after tag and size)
hgs
parents:
diff changeset
  2425
 */
hgs
parents:
diff changeset
  2426
static GstFlowReturn
hgs
parents:
diff changeset
  2427
gst_avi_demux_next_data_buffer (GstAviDemux * avi, guint64 * offset,
hgs
parents:
diff changeset
  2428
    guint32 * tag, guint * size)
hgs
parents:
diff changeset
  2429
{
hgs
parents:
diff changeset
  2430
  guint64 off = *offset;
hgs
parents:
diff changeset
  2431
  guint _size = 0;
hgs
parents:
diff changeset
  2432
  GstFlowReturn res;
hgs
parents:
diff changeset
  2433
hgs
parents:
diff changeset
  2434
  do {
hgs
parents:
diff changeset
  2435
    res = gst_avi_demux_peek_tag (avi, off, tag, &_size);
hgs
parents:
diff changeset
  2436
    if (res != GST_FLOW_OK)
hgs
parents:
diff changeset
  2437
      break;
hgs
parents:
diff changeset
  2438
    if (*tag == GST_RIFF_TAG_LIST || *tag == GST_RIFF_TAG_RIFF)
hgs
parents:
diff changeset
  2439
      off += 8 + 4;             /* skip tag + size + subtag */
hgs
parents:
diff changeset
  2440
    else {
hgs
parents:
diff changeset
  2441
      *offset = off + 8;
hgs
parents:
diff changeset
  2442
      *size = _size;
hgs
parents:
diff changeset
  2443
      break;
hgs
parents:
diff changeset
  2444
    }
hgs
parents:
diff changeset
  2445
  } while (TRUE);
hgs
parents:
diff changeset
  2446
hgs
parents:
diff changeset
  2447
  return res;
hgs
parents:
diff changeset
  2448
}
hgs
parents:
diff changeset
  2449
hgs
parents:
diff changeset
  2450
/*
hgs
parents:
diff changeset
  2451
 * gst_avi_demux_stream_scan:
hgs
parents:
diff changeset
  2452
 * @avi: calling element (used for debugging/errors).
hgs
parents:
diff changeset
  2453
 * @index: list of index entries, returned by this function.
hgs
parents:
diff changeset
  2454
 * @alloc_list: list of allocated data, returned by this function.
hgs
parents:
diff changeset
  2455
 *
hgs
parents:
diff changeset
  2456
 * Scan the file for all chunks to "create" a new index.
hgs
parents:
diff changeset
  2457
 * Return value indicates if we can continue reading the stream. It
hgs
parents:
diff changeset
  2458
 * does not say anything about whether we created an index.
hgs
parents:
diff changeset
  2459
 *
hgs
parents:
diff changeset
  2460
 * pull-range based
hgs
parents:
diff changeset
  2461
 */
hgs
parents:
diff changeset
  2462
static gboolean
hgs
parents:
diff changeset
  2463
gst_avi_demux_stream_scan (GstAviDemux * avi,
hgs
parents:
diff changeset
  2464
    GList ** index, GList ** alloc_list)
hgs
parents:
diff changeset
  2465
{
hgs
parents:
diff changeset
  2466
  GstFlowReturn res;
hgs
parents:
diff changeset
  2467
  gst_avi_index_entry *entry, *entries = NULL;
hgs
parents:
diff changeset
  2468
  avi_stream_context *stream;
hgs
parents:
diff changeset
  2469
  GstFormat format;
hgs
parents:
diff changeset
  2470
  guint64 pos = avi->offset;
hgs
parents:
diff changeset
  2471
  guint64 length;
hgs
parents:
diff changeset
  2472
  gint64 tmplength;
hgs
parents:
diff changeset
  2473
  guint32 tag = 0;
hgs
parents:
diff changeset
  2474
  GList *list = NULL;
hgs
parents:
diff changeset
  2475
  guint index_size = 0;
hgs
parents:
diff changeset
  2476
hgs
parents:
diff changeset
  2477
  /* FIXME:
hgs
parents:
diff changeset
  2478
   * - implement non-seekable source support.
hgs
parents:
diff changeset
  2479
   */
hgs
parents:
diff changeset
  2480
  GST_DEBUG_OBJECT (avi,
hgs
parents:
diff changeset
  2481
      "Creating index %s existing index, starting at offset %" G_GUINT64_FORMAT,
hgs
parents:
diff changeset
  2482
      ((*index) ? "with" : "without"), pos);
hgs
parents:
diff changeset
  2483
hgs
parents:
diff changeset
  2484
  format = GST_FORMAT_BYTES;
hgs
parents:
diff changeset
  2485
  if (!gst_pad_query_peer_duration (avi->sinkpad, &format, &tmplength))
hgs
parents:
diff changeset
  2486
    return FALSE;
hgs
parents:
diff changeset
  2487
hgs
parents:
diff changeset
  2488
  length = tmplength;
hgs
parents:
diff changeset
  2489
hgs
parents:
diff changeset
  2490
  if (*index) {
hgs
parents:
diff changeset
  2491
    entry = g_list_last (*index)->data;
hgs
parents:
diff changeset
  2492
    pos = entry->offset + avi->index_offset + entry->size;
hgs
parents:
diff changeset
  2493
    if (entry->size & 1)
hgs
parents:
diff changeset
  2494
      pos++;
hgs
parents:
diff changeset
  2495
hgs
parents:
diff changeset
  2496
    if (pos >= length) {
hgs
parents:
diff changeset
  2497
      GST_LOG_OBJECT (avi, "Complete index, we're done");
hgs
parents:
diff changeset
  2498
      return TRUE;
hgs
parents:
diff changeset
  2499
    }
hgs
parents:
diff changeset
  2500
hgs
parents:
diff changeset
  2501
    GST_LOG_OBJECT (avi, "Incomplete index, seeking to last valid entry @ %"
hgs
parents:
diff changeset
  2502
        G_GUINT64_FORMAT " of %" G_GUINT64_FORMAT " (%"
hgs
parents:
diff changeset
  2503
        G_GUINT64_FORMAT "+%u)", pos, length, entry->offset, entry->size);
hgs
parents:
diff changeset
  2504
  }
hgs
parents:
diff changeset
  2505
hgs
parents:
diff changeset
  2506
  while (TRUE) {
hgs
parents:
diff changeset
  2507
    guint stream_nr;
hgs
parents:
diff changeset
  2508
    guint size = 0;
hgs
parents:
diff changeset
  2509
hgs
parents:
diff changeset
  2510
    res = gst_avi_demux_next_data_buffer (avi, &pos, &tag, &size);
hgs
parents:
diff changeset
  2511
    if (G_UNLIKELY (res != GST_FLOW_OK))
hgs
parents:
diff changeset
  2512
      break;
hgs
parents:
diff changeset
  2513
hgs
parents:
diff changeset
  2514
    /* check valid stream */
hgs
parents:
diff changeset
  2515
    stream_nr = CHUNKID_TO_STREAMNR (tag);
hgs
parents:
diff changeset
  2516
    if (G_UNLIKELY (stream_nr >= avi->num_streams)) {
hgs
parents:
diff changeset
  2517
      GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  2518
          "Index entry has invalid stream nr %d", stream_nr);
hgs
parents:
diff changeset
  2519
      goto next;
hgs
parents:
diff changeset
  2520
    }
hgs
parents:
diff changeset
  2521
hgs
parents:
diff changeset
  2522
    stream = &avi->stream[stream_nr];
hgs
parents:
diff changeset
  2523
    if (G_UNLIKELY (stream->pad == NULL)) {
hgs
parents:
diff changeset
  2524
      GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  2525
          "Stream %d does not have an output pad, can't create new index",
hgs
parents:
diff changeset
  2526
          stream_nr);
hgs
parents:
diff changeset
  2527
      goto next;
hgs
parents:
diff changeset
  2528
    }
hgs
parents:
diff changeset
  2529
hgs
parents:
diff changeset
  2530
    /* pre-allocate */
hgs
parents:
diff changeset
  2531
    if (G_UNLIKELY (index_size % 1024 == 0)) {
hgs
parents:
diff changeset
  2532
      entries = g_new (gst_avi_index_entry, 1024);
hgs
parents:
diff changeset
  2533
      *alloc_list = g_list_prepend (*alloc_list, entries);
hgs
parents:
diff changeset
  2534
    }
hgs
parents:
diff changeset
  2535
    entry = &entries[index_size % 1024];
hgs
parents:
diff changeset
  2536
hgs
parents:
diff changeset
  2537
    entry->index_nr = index_size++;
hgs
parents:
diff changeset
  2538
    entry->stream_nr = stream_nr;
hgs
parents:
diff changeset
  2539
    entry->flags = GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME;
hgs
parents:
diff changeset
  2540
    entry->offset = pos - avi->index_offset;
hgs
parents:
diff changeset
  2541
    entry->size = size;
hgs
parents:
diff changeset
  2542
hgs
parents:
diff changeset
  2543
    /* timestamps, get timestamps of two consecutive frames to calculate
hgs
parents:
diff changeset
  2544
     * timestamp and duration. */
hgs
parents:
diff changeset
  2545
    format = GST_FORMAT_TIME;
hgs
parents:
diff changeset
  2546
    if (stream->is_vbr) {
hgs
parents:
diff changeset
  2547
      /* VBR stream */
hgs
parents:
diff changeset
  2548
      entry->ts = avi_stream_convert_frames_to_time_unchecked (stream,
hgs
parents:
diff changeset
  2549
          stream->total_frames);
hgs
parents:
diff changeset
  2550
      entry->dur = avi_stream_convert_frames_to_time_unchecked (stream,
hgs
parents:
diff changeset
  2551
          stream->total_frames + 1);
hgs
parents:
diff changeset
  2552
    } else {
hgs
parents:
diff changeset
  2553
      /* constant rate stream */
hgs
parents:
diff changeset
  2554
      entry->ts = avi_stream_convert_bytes_to_time_unchecked (stream,
hgs
parents:
diff changeset
  2555
          stream->total_bytes);
hgs
parents:
diff changeset
  2556
      entry->dur = avi_stream_convert_bytes_to_time_unchecked (stream,
hgs
parents:
diff changeset
  2557
          stream->total_bytes + entry->size);
hgs
parents:
diff changeset
  2558
    }
hgs
parents:
diff changeset
  2559
    entry->dur -= entry->ts;
hgs
parents:
diff changeset
  2560
hgs
parents:
diff changeset
  2561
    /* stream position */
hgs
parents:
diff changeset
  2562
    entry->bytes_before = stream->total_bytes;
hgs
parents:
diff changeset
  2563
    stream->total_bytes += entry->size;
hgs
parents:
diff changeset
  2564
    entry->frames_before = stream->total_frames;
hgs
parents:
diff changeset
  2565
    stream->total_frames++;
hgs
parents:
diff changeset
  2566
    stream->idx_duration = entry->ts + entry->dur;
hgs
parents:
diff changeset
  2567
hgs
parents:
diff changeset
  2568
    list = g_list_prepend (list, entry);
hgs
parents:
diff changeset
  2569
    GST_DEBUG_OBJECT (avi, "Added index entry %d (in stream: %d), offset %"
hgs
parents:
diff changeset
  2570
        G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT " for stream %d",
hgs
parents:
diff changeset
  2571
        index_size - 1, entry->frames_before, entry->offset,
hgs
parents:
diff changeset
  2572
        GST_TIME_ARGS (entry->ts), entry->stream_nr);
hgs
parents:
diff changeset
  2573
hgs
parents:
diff changeset
  2574
  next:
hgs
parents:
diff changeset
  2575
    /* update position */
hgs
parents:
diff changeset
  2576
    pos += GST_ROUND_UP_2 (size);
hgs
parents:
diff changeset
  2577
    if (G_UNLIKELY (pos > length)) {
hgs
parents:
diff changeset
  2578
      GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  2579
          "Stopping index lookup since we are further than EOF");
hgs
parents:
diff changeset
  2580
      break;
hgs
parents:
diff changeset
  2581
    }
hgs
parents:
diff changeset
  2582
  }
hgs
parents:
diff changeset
  2583
hgs
parents:
diff changeset
  2584
  /* FIXME: why is this disabled */
hgs
parents:
diff changeset
  2585
#if 0
hgs
parents:
diff changeset
  2586
  while (gst_avi_demux_sync (avi, &tag, TRUE)) {
hgs
parents:
diff changeset
  2587
    guint stream_nr = CHUNKID_TO_STREAMNR (tag);
hgs
parents:
diff changeset
  2588
    guint8 *data;
hgs
parents:
diff changeset
  2589
    GstFormat format = GST_FORMAT_TIME;
hgs
parents:
diff changeset
  2590
hgs
parents:
diff changeset
  2591
    if (stream_nr >= avi->num_streams)
hgs
parents:
diff changeset
  2592
      goto next;
hgs
parents:
diff changeset
  2593
    stream = &avi->stream[stream_nr];
hgs
parents:
diff changeset
  2594
hgs
parents:
diff changeset
  2595
    /* get chunk size */
hgs
parents:
diff changeset
  2596
    if (gst_bytestream_peek_bytes (riff->bs, &data, 8) != 8)
hgs
parents:
diff changeset
  2597
      goto next;
hgs
parents:
diff changeset
  2598
hgs
parents:
diff changeset
  2599
    /* fill in */
hgs
parents:
diff changeset
  2600
    entry->index_nr = index_size++;
hgs
parents:
diff changeset
  2601
    entry->stream_nr = stream_nr;
hgs
parents:
diff changeset
  2602
    entry->flags = GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME;
hgs
parents:
diff changeset
  2603
    entry->offset = gst_bytestream_tell (riff->bs) + 8 - avi->index_offset;
hgs
parents:
diff changeset
  2604
    entry->size = GST_READ_UINT32_LE (&data[4]);
hgs
parents:
diff changeset
  2605
hgs
parents:
diff changeset
  2606
    /* timestamps */
hgs
parents:
diff changeset
  2607
    if (stream->is_vbr) {
hgs
parents:
diff changeset
  2608
      /* VBR stream */
hgs
parents:
diff changeset
  2609
      entry->ts = avi_stream_convert_frames_to_time_unchecked (stream,
hgs
parents:
diff changeset
  2610
          stream->total_frames);
hgs
parents:
diff changeset
  2611
      entry->dur = avi_stream_convert_frames_to_time_unchecked (stream,
hgs
parents:
diff changeset
  2612
          stream->total_frames + 1);
hgs
parents:
diff changeset
  2613
    } else {
hgs
parents:
diff changeset
  2614
      /* constant rate stream */
hgs
parents:
diff changeset
  2615
      entry->ts = avi_stream_convert_bytes_to_time_unchecked (stream,
hgs
parents:
diff changeset
  2616
          stream->total_bytes);
hgs
parents:
diff changeset
  2617
      entry->dur = avi_stream_convert_bytes_to_time_unchecked (stream,
hgs
parents:
diff changeset
  2618
          stream->total_bytes + entry->size);
hgs
parents:
diff changeset
  2619
    }
hgs
parents:
diff changeset
  2620
    entry->dur -= entry->ts;
hgs
parents:
diff changeset
  2621
hgs
parents:
diff changeset
  2622
    /* stream position */
hgs
parents:
diff changeset
  2623
    entry->bytes_before = stream->total_bytes;
hgs
parents:
diff changeset
  2624
    stream->total_bytes += entry->size;
hgs
parents:
diff changeset
  2625
    entry->frames_before = stream->total_frames;
hgs
parents:
diff changeset
  2626
    stream->total_frames++;
hgs
parents:
diff changeset
  2627
hgs
parents:
diff changeset
  2628
    list = g_list_prepend (list, entry);
hgs
parents:
diff changeset
  2629
    GST_DEBUG_OBJECT (avi, "Added index entry %d (in stream: %d), offset %"
hgs
parents:
diff changeset
  2630
        G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT " for stream %d",
hgs
parents:
diff changeset
  2631
        index_size - 1, entry->frames_before, entry->offset,
hgs
parents:
diff changeset
  2632
        GST_TIME_ARGS (entry->ts), entry->stream_nr);
hgs
parents:
diff changeset
  2633
hgs
parents:
diff changeset
  2634
  next:
hgs
parents:
diff changeset
  2635
    if (!gst_avi_demux_skip (avi, TRUE))
hgs
parents:
diff changeset
  2636
      break;
hgs
parents:
diff changeset
  2637
  }
hgs
parents:
diff changeset
  2638
  /* seek back */
hgs
parents:
diff changeset
  2639
  if (!(event = gst_riff_read_seek (riff, pos))) {
hgs
parents:
diff changeset
  2640
    g_list_free (list);
hgs
parents:
diff changeset
  2641
    return FALSE;
hgs
parents:
diff changeset
  2642
  }
hgs
parents:
diff changeset
  2643
  gst_event_unref (event);
hgs
parents:
diff changeset
  2644
hgs
parents:
diff changeset
  2645
#endif
hgs
parents:
diff changeset
  2646
hgs
parents:
diff changeset
  2647
  GST_DEBUG_OBJECT (avi, "index created, %d items", index_size);
hgs
parents:
diff changeset
  2648
hgs
parents:
diff changeset
  2649
  *index = g_list_concat (*index, g_list_reverse (list));
hgs
parents:
diff changeset
  2650
hgs
parents:
diff changeset
  2651
  return TRUE;
hgs
parents:
diff changeset
  2652
}
hgs
parents:
diff changeset
  2653
hgs
parents:
diff changeset
  2654
/*
hgs
parents:
diff changeset
  2655
 * gst_avi_demux_massage_index:
hgs
parents:
diff changeset
  2656
 * @avi: calling element (used for debugging/errors).
hgs
parents:
diff changeset
  2657
 *
hgs
parents:
diff changeset
  2658
 * We're going to go over each entry in the index and finetune
hgs
parents:
diff changeset
  2659
 * some things we don't like about AVI. For example, a single
hgs
parents:
diff changeset
  2660
 * chunk might be too long. Also, individual streams might be
hgs
parents:
diff changeset
  2661
 * out-of-sync. In the first case, we cut the chunk in several
hgs
parents:
diff changeset
  2662
 * smaller pieces. In the second case, we re-order chunk reading
hgs
parents:
diff changeset
  2663
 * order. The end result should be a smoother playing AVI.
hgs
parents:
diff changeset
  2664
 */
hgs
parents:
diff changeset
  2665
static gboolean
hgs
parents:
diff changeset
  2666
gst_avi_demux_massage_index (GstAviDemux * avi,
hgs
parents:
diff changeset
  2667
    GList * list, GList * alloc_list)
hgs
parents:
diff changeset
  2668
{
hgs
parents:
diff changeset
  2669
  gst_avi_index_entry *entry;
hgs
parents:
diff changeset
  2670
  avi_stream_context *stream;
hgs
parents:
diff changeset
  2671
  guint i;
hgs
parents:
diff changeset
  2672
  GList *node;
hgs
parents:
diff changeset
  2673
  gint64 delay = G_GINT64_CONSTANT (0);
hgs
parents:
diff changeset
  2674
hgs
parents:
diff changeset
  2675
  GST_LOG_OBJECT (avi, "Starting index massage, nr_entries = %d",
hgs
parents:
diff changeset
  2676
      list ? g_list_length (list) : 0);
hgs
parents:
diff changeset
  2677
hgs
parents:
diff changeset
  2678
  if (list) {
hgs
parents:
diff changeset
  2679
#ifndef GST_DISABLE_GST_DEBUG
hgs
parents:
diff changeset
  2680
    guint num_added_total = 0;
hgs
parents:
diff changeset
  2681
    guint num_per_stream[GST_AVI_DEMUX_MAX_STREAMS] = { 0, };
hgs
parents:
diff changeset
  2682
#endif
hgs
parents:
diff changeset
  2683
    GST_LOG_OBJECT (avi,
hgs
parents:
diff changeset
  2684
        "I'm now going to cut large chunks into smaller pieces");
hgs
parents:
diff changeset
  2685
hgs
parents:
diff changeset
  2686
    /* cut chunks in small (seekable) pieces
hgs
parents:
diff changeset
  2687
     * FIXME: this should be a property where a value of
hgs
parents:
diff changeset
  2688
     * GST_CLOCK_TIME_NONE would disable the chunking
hgs
parents:
diff changeset
  2689
     */
hgs
parents:
diff changeset
  2690
#define MAX_DURATION (GST_SECOND / 2)
hgs
parents:
diff changeset
  2691
    for (i = 0; i < avi->num_streams; i++) {
hgs
parents:
diff changeset
  2692
      /* only chop streams that have exactly *one* chunk */
hgs
parents:
diff changeset
  2693
      if (avi->stream[i].total_frames != 1)
hgs
parents:
diff changeset
  2694
        continue;
hgs
parents:
diff changeset
  2695
hgs
parents:
diff changeset
  2696
      for (node = list; node != NULL; node = node->next) {
hgs
parents:
diff changeset
  2697
        entry = node->data;
hgs
parents:
diff changeset
  2698
hgs
parents:
diff changeset
  2699
        if (entry->stream_nr != i)
hgs
parents:
diff changeset
  2700
          continue;
hgs
parents:
diff changeset
  2701
hgs
parents:
diff changeset
  2702
        /* check for max duration of a single buffer. I suppose that
hgs
parents:
diff changeset
  2703
         * the allocation of index entries could be improved. */
hgs
parents:
diff changeset
  2704
        stream = &avi->stream[entry->stream_nr];
hgs
parents:
diff changeset
  2705
        if (entry->dur > MAX_DURATION
hgs
parents:
diff changeset
  2706
            && stream->strh->type == GST_RIFF_FCC_auds) {
hgs
parents:
diff changeset
  2707
          guint32 ideal_size;
hgs
parents:
diff changeset
  2708
          gst_avi_index_entry *entries;
hgs
parents:
diff changeset
  2709
          guint old_size, num_added;
hgs
parents:
diff changeset
  2710
          GList *node2;
hgs
parents:
diff changeset
  2711
hgs
parents:
diff changeset
  2712
          /* cut in 1/10th of a second */
hgs
parents:
diff changeset
  2713
          ideal_size = stream->strf.auds->av_bps / 10;
hgs
parents:
diff changeset
  2714
hgs
parents:
diff changeset
  2715
          /* ensure chunk size is multiple of blockalign */
hgs
parents:
diff changeset
  2716
          if (stream->strf.auds->blockalign > 1)
hgs
parents:
diff changeset
  2717
            ideal_size -= ideal_size % stream->strf.auds->blockalign;
hgs
parents:
diff changeset
  2718
hgs
parents:
diff changeset
  2719
          /* copy index */
hgs
parents:
diff changeset
  2720
          old_size = entry->size;
hgs
parents:
diff changeset
  2721
          num_added = (entry->size - 1) / ideal_size;
hgs
parents:
diff changeset
  2722
          avi->index_size += num_added;
hgs
parents:
diff changeset
  2723
          entries = g_malloc (sizeof (gst_avi_index_entry) * num_added);
hgs
parents:
diff changeset
  2724
          alloc_list = g_list_prepend (alloc_list, entries);
hgs
parents:
diff changeset
  2725
          for (node2 = node->next; node2 != NULL; node2 = node2->next) {
hgs
parents:
diff changeset
  2726
            gst_avi_index_entry *entry2 = node2->data;
hgs
parents:
diff changeset
  2727
hgs
parents:
diff changeset
  2728
            entry2->index_nr += num_added;
hgs
parents:
diff changeset
  2729
            if (entry2->stream_nr == entry->stream_nr)
hgs
parents:
diff changeset
  2730
              entry2->frames_before += num_added;
hgs
parents:
diff changeset
  2731
          }
hgs
parents:
diff changeset
  2732
hgs
parents:
diff changeset
  2733
          /* new sized index chunks */
hgs
parents:
diff changeset
  2734
          for (i = 0; i < num_added + 1; i++) {
hgs
parents:
diff changeset
  2735
            gst_avi_index_entry *entry2;
hgs
parents:
diff changeset
  2736
hgs
parents:
diff changeset
  2737
            if (i == 0) {
hgs
parents:
diff changeset
  2738
              entry2 = entry;
hgs
parents:
diff changeset
  2739
            } else {
hgs
parents:
diff changeset
  2740
              entry2 = &entries[i - 1];
hgs
parents:
diff changeset
  2741
              list = g_list_insert_before (list, node->next, entry2);
hgs
parents:
diff changeset
  2742
              entry = node->data;
hgs
parents:
diff changeset
  2743
              node = node->next;
hgs
parents:
diff changeset
  2744
              memcpy (entry2, entry, sizeof (gst_avi_index_entry));
hgs
parents:
diff changeset
  2745
            }
hgs
parents:
diff changeset
  2746
hgs
parents:
diff changeset
  2747
            if (old_size >= ideal_size) {
hgs
parents:
diff changeset
  2748
              entry2->size = ideal_size;
hgs
parents:
diff changeset
  2749
              old_size -= ideal_size;
hgs
parents:
diff changeset
  2750
            } else {
hgs
parents:
diff changeset
  2751
              entry2->size = old_size;
hgs
parents:
diff changeset
  2752
            }
hgs
parents:
diff changeset
  2753
hgs
parents:
diff changeset
  2754
            entry2->dur = GST_SECOND * entry2->size / stream->strf.auds->av_bps;
hgs
parents:
diff changeset
  2755
            if (i != 0) {
hgs
parents:
diff changeset
  2756
              entry2->index_nr++;
hgs
parents:
diff changeset
  2757
              entry2->ts += entry->dur;
hgs
parents:
diff changeset
  2758
              entry2->offset += entry->size;
hgs
parents:
diff changeset
  2759
              entry2->bytes_before += entry->size;
hgs
parents:
diff changeset
  2760
              entry2->frames_before++;
hgs
parents:
diff changeset
  2761
            }
hgs
parents:
diff changeset
  2762
          }
hgs
parents:
diff changeset
  2763
#ifndef GST_DISABLE_GST_DEBUG
hgs
parents:
diff changeset
  2764
          num_added_total += num_added;
hgs
parents:
diff changeset
  2765
#endif
hgs
parents:
diff changeset
  2766
        }
hgs
parents:
diff changeset
  2767
      }
hgs
parents:
diff changeset
  2768
    }
hgs
parents:
diff changeset
  2769
#ifndef GST_DISABLE_GST_DEBUG
hgs
parents:
diff changeset
  2770
    if (num_added_total)
hgs
parents:
diff changeset
  2771
      GST_LOG ("added %u new index entries", num_added_total);
hgs
parents:
diff changeset
  2772
#endif
hgs
parents:
diff changeset
  2773
hgs
parents:
diff changeset
  2774
    GST_LOG_OBJECT (avi, "I'm now going to reorder the index entries for time");
hgs
parents:
diff changeset
  2775
hgs
parents:
diff changeset
  2776
    /* re-order for time */
hgs
parents:
diff changeset
  2777
    list = g_list_sort (list, (GCompareFunc) sort);
hgs
parents:
diff changeset
  2778
hgs
parents:
diff changeset
  2779
    /* make a continous array out of the list */
hgs
parents:
diff changeset
  2780
    avi->index_size = g_list_length (list);
hgs
parents:
diff changeset
  2781
    avi->index_entries = g_try_new (gst_avi_index_entry, avi->index_size);
hgs
parents:
diff changeset
  2782
    if (!avi->index_entries)
hgs
parents:
diff changeset
  2783
      goto out_of_mem;
hgs
parents:
diff changeset
  2784
hgs
parents:
diff changeset
  2785
    entry = (gst_avi_index_entry *) (list->data);
hgs
parents:
diff changeset
  2786
    delay = entry->ts;
hgs
parents:
diff changeset
  2787
hgs
parents:
diff changeset
  2788
    GST_LOG_OBJECT (avi,
hgs
parents:
diff changeset
  2789
        "Building index array, nr_entries = %d (time offset = %"
hgs
parents:
diff changeset
  2790
        GST_TIME_FORMAT, avi->index_size, GST_TIME_ARGS (delay));
hgs
parents:
diff changeset
  2791
hgs
parents:
diff changeset
  2792
    for (i = 0, node = list; node != NULL; node = node->next, i++) {
hgs
parents:
diff changeset
  2793
      entry = node->data;
hgs
parents:
diff changeset
  2794
      entry->index_nr = i;
hgs
parents:
diff changeset
  2795
      entry->ts -= delay;
hgs
parents:
diff changeset
  2796
      memcpy (&avi->index_entries[i], entry, sizeof (gst_avi_index_entry));
hgs
parents:
diff changeset
  2797
#ifndef GST_DISABLE_GST_DEBUG
hgs
parents:
diff changeset
  2798
      num_per_stream[entry->stream_nr]++;
hgs
parents:
diff changeset
  2799
#endif
hgs
parents:
diff changeset
  2800
hgs
parents:
diff changeset
  2801
      GST_LOG_OBJECT (avi, "Sorted index entry %3d for stream %d of size %6u"
hgs
parents:
diff changeset
  2802
          " at offset %7" G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT
hgs
parents:
diff changeset
  2803
          " dur %" GST_TIME_FORMAT,
hgs
parents:
diff changeset
  2804
          avi->index_entries[i].index_nr, entry->stream_nr, entry->size,
hgs
parents:
diff changeset
  2805
          entry->offset, GST_TIME_ARGS (entry->ts), GST_TIME_ARGS (entry->dur));
hgs
parents:
diff changeset
  2806
    }
hgs
parents:
diff changeset
  2807
    if (delay) {
hgs
parents:
diff changeset
  2808
      for (i = 0; i < avi->num_streams; i++) {
hgs
parents:
diff changeset
  2809
        stream = &avi->stream[i];
hgs
parents:
diff changeset
  2810
        stream->idx_duration -= delay;
hgs
parents:
diff changeset
  2811
      }
hgs
parents:
diff changeset
  2812
    }
hgs
parents:
diff changeset
  2813
#ifndef GST_DISABLE_GST_DEBUG
hgs
parents:
diff changeset
  2814
    {
hgs
parents:
diff changeset
  2815
      gchar str[GST_AVI_DEMUX_MAX_STREAMS * (1 + 6 + 2)];
hgs
parents:
diff changeset
  2816
      gchar *pad_name;
hgs
parents:
diff changeset
  2817
hgs
parents:
diff changeset
  2818
      for (i = 0; i < avi->num_streams; i++) {
hgs
parents:
diff changeset
  2819
        if (!avi->stream[i].pad)
hgs
parents:
diff changeset
  2820
          continue;
hgs
parents:
diff changeset
  2821
        pad_name = GST_OBJECT_NAME (avi->stream[i].pad);
hgs
parents:
diff changeset
  2822
        sprintf (&str[i * (1 + 6 + 2)], " %6u %c", num_per_stream[i],
hgs
parents:
diff changeset
  2823
            pad_name[0]);
hgs
parents:
diff changeset
  2824
      }
hgs
parents:
diff changeset
  2825
      GST_LOG_OBJECT (avi, "indizies per stream:%20s", str);
hgs
parents:
diff changeset
  2826
    }
hgs
parents:
diff changeset
  2827
#endif
hgs
parents:
diff changeset
  2828
hgs
parents:
diff changeset
  2829
    GST_LOG_OBJECT (avi, "Freeing original index list");
hgs
parents:
diff changeset
  2830
    /* all the node->data in list point to alloc_list chunks */
hgs
parents:
diff changeset
  2831
hgs
parents:
diff changeset
  2832
    g_list_free (list);
hgs
parents:
diff changeset
  2833
  }
hgs
parents:
diff changeset
  2834
  if (alloc_list) {
hgs
parents:
diff changeset
  2835
    g_list_foreach (alloc_list, (GFunc) g_free, NULL);
hgs
parents:
diff changeset
  2836
    g_list_free (alloc_list);
hgs
parents:
diff changeset
  2837
  }
hgs
parents:
diff changeset
  2838
#ifndef GST_DISABLE_GST_DEBUG
hgs
parents:
diff changeset
  2839
  for (i = 0; i < avi->num_streams; i++) {
hgs
parents:
diff changeset
  2840
    GST_LOG_OBJECT (avi, "Stream %d, %d frames, %8" G_GUINT64_FORMAT " bytes",
hgs
parents:
diff changeset
  2841
        i, avi->stream[i].total_frames, avi->stream[i].total_bytes);
hgs
parents:
diff changeset
  2842
  }
hgs
parents:
diff changeset
  2843
#endif
hgs
parents:
diff changeset
  2844
hgs
parents:
diff changeset
  2845
  GST_LOG_OBJECT (avi, "Index massaging done");
hgs
parents:
diff changeset
  2846
  return TRUE;
hgs
parents:
diff changeset
  2847
hgs
parents:
diff changeset
  2848
  /* ERRORS */
hgs
parents:
diff changeset
  2849
out_of_mem:
hgs
parents:
diff changeset
  2850
  GST_WARNING_OBJECT (avi, "Out of memory for %" G_GSIZE_FORMAT " bytes",
hgs
parents:
diff changeset
  2851
      sizeof (gst_avi_index_entry) * avi->index_size);
hgs
parents:
diff changeset
  2852
  return FALSE;
hgs
parents:
diff changeset
  2853
}
hgs
parents:
diff changeset
  2854
hgs
parents:
diff changeset
  2855
static void
hgs
parents:
diff changeset
  2856
gst_avi_demux_calculate_durations_from_index (GstAviDemux * avi)
hgs
parents:
diff changeset
  2857
{
hgs
parents:
diff changeset
  2858
  gint stream;
hgs
parents:
diff changeset
  2859
  GstClockTime total;
hgs
parents:
diff changeset
  2860
hgs
parents:
diff changeset
  2861
  total = GST_CLOCK_TIME_NONE;
hgs
parents:
diff changeset
  2862
hgs
parents:
diff changeset
  2863
  /* all streams start at a timestamp 0 */
hgs
parents:
diff changeset
  2864
  for (stream = 0; stream < avi->num_streams; stream++) {
hgs
parents:
diff changeset
  2865
    GstClockTime duration, hduration;
hgs
parents:
diff changeset
  2866
    avi_stream_context *streamc = &avi->stream[stream];
hgs
parents:
diff changeset
  2867
    gst_riff_strh *strh = streamc->strh;
hgs
parents:
diff changeset
  2868
hgs
parents:
diff changeset
  2869
    if (!strh)
hgs
parents:
diff changeset
  2870
      continue;
hgs
parents:
diff changeset
  2871
hgs
parents:
diff changeset
  2872
    /* get header duration for the stream */
hgs
parents:
diff changeset
  2873
    hduration = streamc->hdr_duration;
hgs
parents:
diff changeset
  2874
hgs
parents:
diff changeset
  2875
    /* index duration calculated during parsing, invariant under massage */
hgs
parents:
diff changeset
  2876
    duration = streamc->idx_duration;
hgs
parents:
diff changeset
  2877
hgs
parents:
diff changeset
  2878
    /* now pick a good duration */
hgs
parents:
diff changeset
  2879
    if (GST_CLOCK_TIME_IS_VALID (duration)) {
hgs
parents:
diff changeset
  2880
      /* index gave valid duration, use that */
hgs
parents:
diff changeset
  2881
      GST_INFO ("Stream %d duration according to index: %" GST_TIME_FORMAT,
hgs
parents:
diff changeset
  2882
          stream, GST_TIME_ARGS (duration));
hgs
parents:
diff changeset
  2883
    } else {
hgs
parents:
diff changeset
  2884
      /* fall back to header info to calculate a duration */
hgs
parents:
diff changeset
  2885
      duration = hduration;
hgs
parents:
diff changeset
  2886
    }
hgs
parents:
diff changeset
  2887
    /* set duration for the stream */
hgs
parents:
diff changeset
  2888
    streamc->duration = duration;
hgs
parents:
diff changeset
  2889
hgs
parents:
diff changeset
  2890
    /* find total duration */
hgs
parents:
diff changeset
  2891
    if (total == GST_CLOCK_TIME_NONE || duration > total)
hgs
parents:
diff changeset
  2892
      total = duration;
hgs
parents:
diff changeset
  2893
  }
hgs
parents:
diff changeset
  2894
hgs
parents:
diff changeset
  2895
  if (GST_CLOCK_TIME_IS_VALID (total) && (total > 0)) {
hgs
parents:
diff changeset
  2896
    /* now update the duration for those streams where we had none */
hgs
parents:
diff changeset
  2897
    for (stream = 0; stream < avi->num_streams; stream++) {
hgs
parents:
diff changeset
  2898
      avi_stream_context *streamc = &avi->stream[stream];
hgs
parents:
diff changeset
  2899
hgs
parents:
diff changeset
  2900
      if (!GST_CLOCK_TIME_IS_VALID (streamc->duration)
hgs
parents:
diff changeset
  2901
          || streamc->duration == 0) {
hgs
parents:
diff changeset
  2902
        streamc->duration = total;
hgs
parents:
diff changeset
  2903
hgs
parents:
diff changeset
  2904
        GST_INFO ("Stream %d duration according to total: %" GST_TIME_FORMAT,
hgs
parents:
diff changeset
  2905
            stream, GST_TIME_ARGS (total));
hgs
parents:
diff changeset
  2906
      }
hgs
parents:
diff changeset
  2907
    }
hgs
parents:
diff changeset
  2908
  }
hgs
parents:
diff changeset
  2909
hgs
parents:
diff changeset
  2910
  /* and set the total duration in the segment. */
hgs
parents:
diff changeset
  2911
  GST_INFO ("Setting total duration to: %" GST_TIME_FORMAT,
hgs
parents:
diff changeset
  2912
      GST_TIME_ARGS (total));
hgs
parents:
diff changeset
  2913
hgs
parents:
diff changeset
  2914
  gst_segment_set_duration (&avi->segment, GST_FORMAT_TIME, total);
hgs
parents:
diff changeset
  2915
}
hgs
parents:
diff changeset
  2916
hgs
parents:
diff changeset
  2917
/* returns FALSE if there are no pads to deliver event to,
hgs
parents:
diff changeset
  2918
 * otherwise TRUE (whatever the outcome of event sending) */
hgs
parents:
diff changeset
  2919
static gboolean
hgs
parents:
diff changeset
  2920
gst_avi_demux_push_event (GstAviDemux * avi, GstEvent * event)
hgs
parents:
diff changeset
  2921
{
hgs
parents:
diff changeset
  2922
  gboolean result = FALSE;
hgs
parents:
diff changeset
  2923
  gint i;
hgs
parents:
diff changeset
  2924
hgs
parents:
diff changeset
  2925
  GST_DEBUG_OBJECT (avi, "sending %s event to %d streams",
hgs
parents:
diff changeset
  2926
      GST_EVENT_TYPE_NAME (event), avi->num_streams);
hgs
parents:
diff changeset
  2927
hgs
parents:
diff changeset
  2928
  if (avi->num_streams) {
hgs
parents:
diff changeset
  2929
    for (i = 0; i < avi->num_streams; i++) {
hgs
parents:
diff changeset
  2930
      avi_stream_context *stream = &avi->stream[i];
hgs
parents:
diff changeset
  2931
hgs
parents:
diff changeset
  2932
      if (stream->pad) {
hgs
parents:
diff changeset
  2933
        result = TRUE;
hgs
parents:
diff changeset
  2934
        gst_pad_push_event (stream->pad, gst_event_ref (event));
hgs
parents:
diff changeset
  2935
      }
hgs
parents:
diff changeset
  2936
    }
hgs
parents:
diff changeset
  2937
  }
hgs
parents:
diff changeset
  2938
  gst_event_unref (event);
hgs
parents:
diff changeset
  2939
  return result;
hgs
parents:
diff changeset
  2940
}
hgs
parents:
diff changeset
  2941
hgs
parents:
diff changeset
  2942
/*
hgs
parents:
diff changeset
  2943
 * Read AVI headers when streaming
hgs
parents:
diff changeset
  2944
 */
hgs
parents:
diff changeset
  2945
static GstFlowReturn
hgs
parents:
diff changeset
  2946
gst_avi_demux_stream_header_push (GstAviDemux * avi)
hgs
parents:
diff changeset
  2947
{
hgs
parents:
diff changeset
  2948
  GstFlowReturn ret = GST_FLOW_OK;
hgs
parents:
diff changeset
  2949
  guint32 tag = 0;
hgs
parents:
diff changeset
  2950
  guint32 ltag = 0;
hgs
parents:
diff changeset
  2951
  guint32 size = 0;
hgs
parents:
diff changeset
  2952
  const guint8 *data;
hgs
parents:
diff changeset
  2953
  GstBuffer *buf = NULL, *sub = NULL;
hgs
parents:
diff changeset
  2954
  guint offset = 4;
hgs
parents:
diff changeset
  2955
  gint64 stop;
hgs
parents:
diff changeset
  2956
hgs
parents:
diff changeset
  2957
  GST_DEBUG ("Reading and parsing avi headers: %d", avi->header_state);
hgs
parents:
diff changeset
  2958
hgs
parents:
diff changeset
  2959
  switch (avi->header_state) {
hgs
parents:
diff changeset
  2960
    case GST_AVI_DEMUX_HEADER_TAG_LIST:
hgs
parents:
diff changeset
  2961
      if (gst_avi_demux_peek_chunk (avi, &tag, &size)) {
hgs
parents:
diff changeset
  2962
        avi->offset += 8 + ((size + 1) & ~1);
hgs
parents:
diff changeset
  2963
        if (tag != GST_RIFF_TAG_LIST)
hgs
parents:
diff changeset
  2964
          goto header_no_list;
hgs
parents:
diff changeset
  2965
hgs
parents:
diff changeset
  2966
        gst_adapter_flush (avi->adapter, 8);
hgs
parents:
diff changeset
  2967
        /* Find the 'hdrl' LIST tag */
hgs
parents:
diff changeset
  2968
        GST_DEBUG ("Reading %d bytes", size);
hgs
parents:
diff changeset
  2969
        buf = gst_adapter_take_buffer (avi->adapter, size);
hgs
parents:
diff changeset
  2970
hgs
parents:
diff changeset
  2971
        if (GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)) != GST_RIFF_LIST_hdrl)
hgs
parents:
diff changeset
  2972
          goto header_no_hdrl;
hgs
parents:
diff changeset
  2973
hgs
parents:
diff changeset
  2974
        /* mind padding */
hgs
parents:
diff changeset
  2975
        if (size & 1)
hgs
parents:
diff changeset
  2976
          gst_adapter_flush (avi->adapter, 1);
hgs
parents:
diff changeset
  2977
hgs
parents:
diff changeset
  2978
        GST_DEBUG ("'hdrl' LIST tag found. Parsing next chunk");
hgs
parents:
diff changeset
  2979
hgs
parents:
diff changeset
  2980
        /* the hdrl starts with a 'avih' header */
hgs
parents:
diff changeset
  2981
        if (!gst_riff_parse_chunk (GST_ELEMENT (avi), buf, &offset, &tag, &sub))
hgs
parents:
diff changeset
  2982
          goto header_no_avih;
hgs
parents:
diff changeset
  2983
hgs
parents:
diff changeset
  2984
        if (tag != GST_RIFF_TAG_avih)
hgs
parents:
diff changeset
  2985
          goto header_no_avih;
hgs
parents:
diff changeset
  2986
hgs
parents:
diff changeset
  2987
        if (!gst_avi_demux_parse_avih (GST_ELEMENT (avi), sub, &avi->avih))
hgs
parents:
diff changeset
  2988
          goto header_wrong_avih;
hgs
parents:
diff changeset
  2989
hgs
parents:
diff changeset
  2990
        GST_DEBUG_OBJECT (avi, "AVI header ok, reading elemnts from header");
hgs
parents:
diff changeset
  2991
hgs
parents:
diff changeset
  2992
        /* now, read the elements from the header until the end */
hgs
parents:
diff changeset
  2993
        while (gst_riff_parse_chunk (GST_ELEMENT (avi), buf, &offset, &tag,
hgs
parents:
diff changeset
  2994
                &sub)) {
hgs
parents:
diff changeset
  2995
          /* sub can be NULL on empty tags */
hgs
parents:
diff changeset
  2996
          if (!sub)
hgs
parents:
diff changeset
  2997
            continue;
hgs
parents:
diff changeset
  2998
hgs
parents:
diff changeset
  2999
          switch (tag) {
hgs
parents:
diff changeset
  3000
            case GST_RIFF_TAG_LIST:
hgs
parents:
diff changeset
  3001
              if (GST_BUFFER_SIZE (sub) < 4)
hgs
parents:
diff changeset
  3002
                goto next;
hgs
parents:
diff changeset
  3003
hgs
parents:
diff changeset
  3004
              switch (GST_READ_UINT32_LE (GST_BUFFER_DATA (sub))) {
hgs
parents:
diff changeset
  3005
                case GST_RIFF_LIST_strl:
hgs
parents:
diff changeset
  3006
                  if (!(gst_avi_demux_parse_stream (avi, sub))) {
hgs
parents:
diff changeset
  3007
                    sub = NULL;
hgs
parents:
diff changeset
  3008
                    GST_ELEMENT_WARNING (avi, STREAM, DEMUX, (NULL),
hgs
parents:
diff changeset
  3009
                        ("failed to parse stream, ignoring"));
hgs
parents:
diff changeset
  3010
                    goto next;
hgs
parents:
diff changeset
  3011
                  }
hgs
parents:
diff changeset
  3012
                  sub = NULL;
hgs
parents:
diff changeset
  3013
                  goto next;
hgs
parents:
diff changeset
  3014
                case GST_RIFF_LIST_odml:
hgs
parents:
diff changeset
  3015
                  gst_avi_demux_parse_odml (avi, sub);
hgs
parents:
diff changeset
  3016
                  sub = NULL;
hgs
parents:
diff changeset
  3017
                  break;
hgs
parents:
diff changeset
  3018
                default:
hgs
parents:
diff changeset
  3019
                  GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  3020
                      "Unknown list %" GST_FOURCC_FORMAT " in AVI header",
hgs
parents:
diff changeset
  3021
                      GST_FOURCC_ARGS (GST_READ_UINT32_LE (GST_BUFFER_DATA
hgs
parents:
diff changeset
  3022
                              (sub))));
hgs
parents:
diff changeset
  3023
                  /* fall-through */
hgs
parents:
diff changeset
  3024
                case GST_RIFF_TAG_JUNK:
hgs
parents:
diff changeset
  3025
                  goto next;
hgs
parents:
diff changeset
  3026
              }
hgs
parents:
diff changeset
  3027
              break;
hgs
parents:
diff changeset
  3028
            default:
hgs
parents:
diff changeset
  3029
              GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  3030
                  "Unknown off %d tag %" GST_FOURCC_FORMAT " in AVI header",
hgs
parents:
diff changeset
  3031
                  offset, GST_FOURCC_ARGS (tag));
hgs
parents:
diff changeset
  3032
              /* fall-through */
hgs
parents:
diff changeset
  3033
            case GST_RIFF_TAG_JUNK:
hgs
parents:
diff changeset
  3034
            next:
hgs
parents:
diff changeset
  3035
              /* move to next chunk */
hgs
parents:
diff changeset
  3036
              if (sub)
hgs
parents:
diff changeset
  3037
                gst_buffer_unref (sub);
hgs
parents:
diff changeset
  3038
              sub = NULL;
hgs
parents:
diff changeset
  3039
              break;
hgs
parents:
diff changeset
  3040
          }
hgs
parents:
diff changeset
  3041
        }
hgs
parents:
diff changeset
  3042
        gst_buffer_unref (buf);
hgs
parents:
diff changeset
  3043
        GST_DEBUG ("elements parsed");
hgs
parents:
diff changeset
  3044
hgs
parents:
diff changeset
  3045
        /* check parsed streams */
hgs
parents:
diff changeset
  3046
        if (avi->num_streams == 0) {
hgs
parents:
diff changeset
  3047
          goto no_streams;
hgs
parents:
diff changeset
  3048
        } else if (avi->num_streams != avi->avih->streams) {
hgs
parents:
diff changeset
  3049
          GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  3050
              "Stream header mentioned %d streams, but %d available",
hgs
parents:
diff changeset
  3051
              avi->avih->streams, avi->num_streams);
hgs
parents:
diff changeset
  3052
        }
hgs
parents:
diff changeset
  3053
        GST_DEBUG ("Get junk and info next");
hgs
parents:
diff changeset
  3054
        avi->header_state = GST_AVI_DEMUX_HEADER_INFO;
hgs
parents:
diff changeset
  3055
      } else {
hgs
parents:
diff changeset
  3056
        /* Need more data */
hgs
parents:
diff changeset
  3057
        return ret;
hgs
parents:
diff changeset
  3058
      }
hgs
parents:
diff changeset
  3059
      /* fall-though */
hgs
parents:
diff changeset
  3060
    case GST_AVI_DEMUX_HEADER_INFO:
hgs
parents:
diff changeset
  3061
      GST_DEBUG_OBJECT (avi, "skipping junk between header and data ...");
hgs
parents:
diff changeset
  3062
      while (TRUE) {
hgs
parents:
diff changeset
  3063
        if (gst_adapter_available (avi->adapter) < 12)
hgs
parents:
diff changeset
  3064
          return GST_FLOW_OK;
hgs
parents:
diff changeset
  3065
hgs
parents:
diff changeset
  3066
        data = gst_adapter_peek (avi->adapter, 12);
hgs
parents:
diff changeset
  3067
        tag = GST_READ_UINT32_LE (data);
hgs
parents:
diff changeset
  3068
        size = GST_READ_UINT32_LE (data + 4);
hgs
parents:
diff changeset
  3069
        ltag = GST_READ_UINT32_LE (data + 8);
hgs
parents:
diff changeset
  3070
hgs
parents:
diff changeset
  3071
        if (tag == GST_RIFF_TAG_LIST) {
hgs
parents:
diff changeset
  3072
          switch (ltag) {
hgs
parents:
diff changeset
  3073
            case GST_RIFF_LIST_movi:
hgs
parents:
diff changeset
  3074
              gst_adapter_flush (avi->adapter, 12);
hgs
parents:
diff changeset
  3075
              avi->offset += 12;
hgs
parents:
diff changeset
  3076
              goto skipping_done;
hgs
parents:
diff changeset
  3077
            case GST_RIFF_LIST_INFO:
hgs
parents:
diff changeset
  3078
              GST_DEBUG ("Found INFO chunk");
hgs
parents:
diff changeset
  3079
              if (gst_avi_demux_peek_chunk (avi, &tag, &size)) {
hgs
parents:
diff changeset
  3080
                GST_DEBUG ("got size %d", size);
hgs
parents:
diff changeset
  3081
                avi->offset += 12;
hgs
parents:
diff changeset
  3082
                gst_adapter_flush (avi->adapter, 12);
hgs
parents:
diff changeset
  3083
                if (size > 4) {
hgs
parents:
diff changeset
  3084
                  buf = gst_adapter_take_buffer (avi->adapter, size - 4);
hgs
parents:
diff changeset
  3085
                  /* mind padding */
hgs
parents:
diff changeset
  3086
                  if (size & 1)
hgs
parents:
diff changeset
  3087
                    gst_adapter_flush (avi->adapter, 1);
hgs
parents:
diff changeset
  3088
                  gst_riff_parse_info (GST_ELEMENT (avi), buf,
hgs
parents:
diff changeset
  3089
                      &avi->globaltags);
hgs
parents:
diff changeset
  3090
                  gst_buffer_unref (buf);
hgs
parents:
diff changeset
  3091
hgs
parents:
diff changeset
  3092
                  avi->offset += ((size + 1) & ~1) - 4;
hgs
parents:
diff changeset
  3093
                } else {
hgs
parents:
diff changeset
  3094
                  GST_DEBUG ("skipping INFO LIST prefix");
hgs
parents:
diff changeset
  3095
                }
hgs
parents:
diff changeset
  3096
              } else {
hgs
parents:
diff changeset
  3097
                /* Need more data */
hgs
parents:
diff changeset
  3098
                return GST_FLOW_OK;
hgs
parents:
diff changeset
  3099
              }
hgs
parents:
diff changeset
  3100
              break;
hgs
parents:
diff changeset
  3101
            default:
hgs
parents:
diff changeset
  3102
              if (gst_avi_demux_peek_chunk (avi, &tag, &size)) {
hgs
parents:
diff changeset
  3103
                avi->offset += 8 + ((size + 1) & ~1);
hgs
parents:
diff changeset
  3104
                gst_adapter_flush (avi->adapter, 8 + ((size + 1) & ~1));
hgs
parents:
diff changeset
  3105
                // ??? goto iterate; ???
hgs
parents:
diff changeset
  3106
              } else {
hgs
parents:
diff changeset
  3107
                /* Need more data */
hgs
parents:
diff changeset
  3108
                return GST_FLOW_OK;
hgs
parents:
diff changeset
  3109
              }
hgs
parents:
diff changeset
  3110
              break;
hgs
parents:
diff changeset
  3111
          }
hgs
parents:
diff changeset
  3112
        } else {
hgs
parents:
diff changeset
  3113
          if (gst_avi_demux_peek_chunk (avi, &tag, &size)) {
hgs
parents:
diff changeset
  3114
            avi->offset += 8 + ((size + 1) & ~1);
hgs
parents:
diff changeset
  3115
            gst_adapter_flush (avi->adapter, 8 + ((size + 1) & ~1));
hgs
parents:
diff changeset
  3116
            //goto iterate;
hgs
parents:
diff changeset
  3117
          } else {
hgs
parents:
diff changeset
  3118
            /* Need more data */
hgs
parents:
diff changeset
  3119
            return GST_FLOW_OK;
hgs
parents:
diff changeset
  3120
          }
hgs
parents:
diff changeset
  3121
        }
hgs
parents:
diff changeset
  3122
      }
hgs
parents:
diff changeset
  3123
      break;
hgs
parents:
diff changeset
  3124
    default:
hgs
parents:
diff changeset
  3125
      GST_WARNING ("unhandled header state: %d", avi->header_state);
hgs
parents:
diff changeset
  3126
      break;
hgs
parents:
diff changeset
  3127
  }
hgs
parents:
diff changeset
  3128
skipping_done:
hgs
parents:
diff changeset
  3129
hgs
parents:
diff changeset
  3130
  GST_DEBUG_OBJECT (avi, "skipping done ... (streams=%u, stream[0].indexes=%p)",
hgs
parents:
diff changeset
  3131
      avi->num_streams, avi->stream[0].indexes);
hgs
parents:
diff changeset
  3132
hgs
parents:
diff changeset
  3133
  GST_DEBUG ("Found movi chunk. Starting to stream data");
hgs
parents:
diff changeset
  3134
  avi->state = GST_AVI_DEMUX_MOVI;
hgs
parents:
diff changeset
  3135
hgs
parents:
diff changeset
  3136
#if 0
hgs
parents:
diff changeset
  3137
  /*GList *index = NULL, *alloc = NULL; */
hgs
parents:
diff changeset
  3138
hgs
parents:
diff changeset
  3139
  /* ######################## this need to be integrated with the state */
hgs
parents:
diff changeset
  3140
  /* create or read stream index (for seeking) */
hgs
parents:
diff changeset
  3141
  if (avi->stream[0].indexes != NULL) {
hgs
parents:
diff changeset
  3142
    gst_avi_demux_read_subindexes_push (avi, &index, &alloc);
hgs
parents:
diff changeset
  3143
  }
hgs
parents:
diff changeset
  3144
  if (!index) {
hgs
parents:
diff changeset
  3145
    if (avi->avih->flags & GST_RIFF_AVIH_HASINDEX) {
hgs
parents:
diff changeset
  3146
      gst_avi_demux_stream_index (avi, &index, &alloc);
hgs
parents:
diff changeset
  3147
    }
hgs
parents:
diff changeset
  3148
    /* some indexes are incomplete, continue streaming from there */
hgs
parents:
diff changeset
  3149
    if (!index)
hgs
parents:
diff changeset
  3150
      gst_avi_demux_stream_scan (avi, &index, &alloc);
hgs
parents:
diff changeset
  3151
  }
hgs
parents:
diff changeset
  3152
hgs
parents:
diff changeset
  3153
  /* this is a fatal error */
hgs
parents:
diff changeset
  3154
  if (!index)
hgs
parents:
diff changeset
  3155
    goto no_index;
hgs
parents:
diff changeset
  3156
hgs
parents:
diff changeset
  3157
  if (!gst_avi_demux_massage_index (avi, index, alloc))
hgs
parents:
diff changeset
  3158
    goto no_index;
hgs
parents:
diff changeset
  3159
hgs
parents:
diff changeset
  3160
  gst_avi_demux_calculate_durations_from_index (avi);
hgs
parents:
diff changeset
  3161
  /* ######################## */
hgs
parents:
diff changeset
  3162
#endif
hgs
parents:
diff changeset
  3163
hgs
parents:
diff changeset
  3164
  /* create initial NEWSEGMENT event */
hgs
parents:
diff changeset
  3165
  if ((stop = avi->segment.stop) == GST_CLOCK_TIME_NONE)
hgs
parents:
diff changeset
  3166
    stop = avi->segment.duration;
hgs
parents:
diff changeset
  3167
hgs
parents:
diff changeset
  3168
  GST_DEBUG_OBJECT (avi, "segment stop %" G_GINT64_FORMAT, stop);
hgs
parents:
diff changeset
  3169
hgs
parents:
diff changeset
  3170
  if (avi->seek_event)
hgs
parents:
diff changeset
  3171
    gst_event_unref (avi->seek_event);
hgs
parents:
diff changeset
  3172
  avi->seek_event = gst_event_new_new_segment
hgs
parents:
diff changeset
  3173
      (FALSE, avi->segment.rate, GST_FORMAT_TIME,
hgs
parents:
diff changeset
  3174
      avi->segment.start, stop, avi->segment.start);
hgs
parents:
diff changeset
  3175
hgs
parents:
diff changeset
  3176
  /* at this point we know all the streams and we can signal the no more
hgs
parents:
diff changeset
  3177
   * pads signal */
hgs
parents:
diff changeset
  3178
  GST_DEBUG_OBJECT (avi, "signaling no more pads");
hgs
parents:
diff changeset
  3179
  gst_element_no_more_pads (GST_ELEMENT (avi));
hgs
parents:
diff changeset
  3180
hgs
parents:
diff changeset
  3181
  return GST_FLOW_OK;
hgs
parents:
diff changeset
  3182
hgs
parents:
diff changeset
  3183
  /* ERRORS */
hgs
parents:
diff changeset
  3184
no_streams:
hgs
parents:
diff changeset
  3185
  {
hgs
parents:
diff changeset
  3186
    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("No streams found"));
hgs
parents:
diff changeset
  3187
    return GST_FLOW_ERROR;
hgs
parents:
diff changeset
  3188
  }
hgs
parents:
diff changeset
  3189
header_no_list:
hgs
parents:
diff changeset
  3190
  {
hgs
parents:
diff changeset
  3191
    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
hgs
parents:
diff changeset
  3192
        ("Invalid AVI header (no LIST at start): %"
hgs
parents:
diff changeset
  3193
            GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
hgs
parents:
diff changeset
  3194
    return GST_FLOW_ERROR;
hgs
parents:
diff changeset
  3195
  }
hgs
parents:
diff changeset
  3196
header_no_hdrl:
hgs
parents:
diff changeset
  3197
  {
hgs
parents:
diff changeset
  3198
    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
hgs
parents:
diff changeset
  3199
        ("Invalid AVI header (no hdrl at start): %"
hgs
parents:
diff changeset
  3200
            GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
hgs
parents:
diff changeset
  3201
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  3202
    return GST_FLOW_ERROR;
hgs
parents:
diff changeset
  3203
  }
hgs
parents:
diff changeset
  3204
header_no_avih:
hgs
parents:
diff changeset
  3205
  {
hgs
parents:
diff changeset
  3206
    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
hgs
parents:
diff changeset
  3207
        ("Invalid AVI header (no avih at start): %"
hgs
parents:
diff changeset
  3208
            GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
hgs
parents:
diff changeset
  3209
    if (sub)
hgs
parents:
diff changeset
  3210
      gst_buffer_unref (sub);
hgs
parents:
diff changeset
  3211
hgs
parents:
diff changeset
  3212
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  3213
    return GST_FLOW_ERROR;
hgs
parents:
diff changeset
  3214
  }
hgs
parents:
diff changeset
  3215
header_wrong_avih:
hgs
parents:
diff changeset
  3216
  {
hgs
parents:
diff changeset
  3217
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  3218
    return GST_FLOW_ERROR;
hgs
parents:
diff changeset
  3219
  }
hgs
parents:
diff changeset
  3220
}
hgs
parents:
diff changeset
  3221
hgs
parents:
diff changeset
  3222
/*
hgs
parents:
diff changeset
  3223
 * Read full AVI headers.
hgs
parents:
diff changeset
  3224
 */
hgs
parents:
diff changeset
  3225
static GstFlowReturn
hgs
parents:
diff changeset
  3226
gst_avi_demux_stream_header_pull (GstAviDemux * avi)
hgs
parents:
diff changeset
  3227
{
hgs
parents:
diff changeset
  3228
  GstFlowReturn res;
hgs
parents:
diff changeset
  3229
  GstBuffer *buf, *sub = NULL;
hgs
parents:
diff changeset
  3230
  guint32 tag;
hgs
parents:
diff changeset
  3231
  GList *index = NULL, *alloc = NULL;
hgs
parents:
diff changeset
  3232
  guint offset = 4;
hgs
parents:
diff changeset
  3233
  gint64 stop;
hgs
parents:
diff changeset
  3234
  GstElement *element = GST_ELEMENT_CAST (avi);
hgs
parents:
diff changeset
  3235
hgs
parents:
diff changeset
  3236
  /* the header consists of a 'hdrl' LIST tag */
hgs
parents:
diff changeset
  3237
  res = gst_riff_read_chunk (element, avi->sinkpad, &avi->offset, &tag, &buf);
hgs
parents:
diff changeset
  3238
  if (res != GST_FLOW_OK)
hgs
parents:
diff changeset
  3239
    goto pull_range_failed;
hgs
parents:
diff changeset
  3240
  else if (tag != GST_RIFF_TAG_LIST)
hgs
parents:
diff changeset
  3241
    goto no_list;
hgs
parents:
diff changeset
  3242
  else if (GST_BUFFER_SIZE (buf) < 4)
hgs
parents:
diff changeset
  3243
    goto no_header;
hgs
parents:
diff changeset
  3244
hgs
parents:
diff changeset
  3245
  GST_DEBUG_OBJECT (avi, "parsing headers");
hgs
parents:
diff changeset
  3246
hgs
parents:
diff changeset
  3247
  /* Find the 'hdrl' LIST tag */
hgs
parents:
diff changeset
  3248
  while (GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)) != GST_RIFF_LIST_hdrl) {
hgs
parents:
diff changeset
  3249
    GST_LOG_OBJECT (avi, "buffer contains %" GST_FOURCC_FORMAT,
hgs
parents:
diff changeset
  3250
        GST_FOURCC_ARGS (GST_READ_UINT32_LE (GST_BUFFER_DATA (buf))));
hgs
parents:
diff changeset
  3251
hgs
parents:
diff changeset
  3252
    /* Eat up */
hgs
parents:
diff changeset
  3253
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  3254
hgs
parents:
diff changeset
  3255
    /* read new chunk */
hgs
parents:
diff changeset
  3256
    res = gst_riff_read_chunk (element, avi->sinkpad, &avi->offset, &tag, &buf);
hgs
parents:
diff changeset
  3257
    if (res != GST_FLOW_OK)
hgs
parents:
diff changeset
  3258
      goto pull_range_failed;
hgs
parents:
diff changeset
  3259
    else if (tag != GST_RIFF_TAG_LIST)
hgs
parents:
diff changeset
  3260
      goto no_list;
hgs
parents:
diff changeset
  3261
    else if (GST_BUFFER_SIZE (buf) < 4)
hgs
parents:
diff changeset
  3262
      goto no_header;
hgs
parents:
diff changeset
  3263
  }
hgs
parents:
diff changeset
  3264
hgs
parents:
diff changeset
  3265
  GST_DEBUG_OBJECT (avi, "hdrl LIST tag found");
hgs
parents:
diff changeset
  3266
hgs
parents:
diff changeset
  3267
  /* the hdrl starts with a 'avih' header */
hgs
parents:
diff changeset
  3268
  if (!gst_riff_parse_chunk (element, buf, &offset, &tag, &sub))
hgs
parents:
diff changeset
  3269
    goto no_avih;
hgs
parents:
diff changeset
  3270
  else if (tag != GST_RIFF_TAG_avih)
hgs
parents:
diff changeset
  3271
    goto no_avih;
hgs
parents:
diff changeset
  3272
  else if (!gst_avi_demux_parse_avih (element, sub, &avi->avih))
hgs
parents:
diff changeset
  3273
    goto invalid_avih;
hgs
parents:
diff changeset
  3274
hgs
parents:
diff changeset
  3275
  GST_DEBUG_OBJECT (avi, "AVI header ok, reading elements from header");
hgs
parents:
diff changeset
  3276
hgs
parents:
diff changeset
  3277
  /* now, read the elements from the header until the end */
hgs
parents:
diff changeset
  3278
  while (gst_riff_parse_chunk (element, buf, &offset, &tag, &sub)) {
hgs
parents:
diff changeset
  3279
    /* sub can be NULL on empty tags */
hgs
parents:
diff changeset
  3280
    if (!sub)
hgs
parents:
diff changeset
  3281
      continue;
hgs
parents:
diff changeset
  3282
hgs
parents:
diff changeset
  3283
    switch (tag) {
hgs
parents:
diff changeset
  3284
      case GST_RIFF_TAG_LIST:
hgs
parents:
diff changeset
  3285
      {
hgs
parents:
diff changeset
  3286
        guint8 *data;
hgs
parents:
diff changeset
  3287
        guint32 fourcc;
hgs
parents:
diff changeset
  3288
hgs
parents:
diff changeset
  3289
        if (GST_BUFFER_SIZE (sub) < 4)
hgs
parents:
diff changeset
  3290
          goto next;
hgs
parents:
diff changeset
  3291
hgs
parents:
diff changeset
  3292
        data = GST_BUFFER_DATA (sub);
hgs
parents:
diff changeset
  3293
        fourcc = GST_READ_UINT32_LE (data);
hgs
parents:
diff changeset
  3294
hgs
parents:
diff changeset
  3295
        switch (fourcc) {
hgs
parents:
diff changeset
  3296
          case GST_RIFF_LIST_strl:
hgs
parents:
diff changeset
  3297
            if (!(gst_avi_demux_parse_stream (avi, sub))) {
hgs
parents:
diff changeset
  3298
              GST_ELEMENT_WARNING (avi, STREAM, DEMUX, (NULL),
hgs
parents:
diff changeset
  3299
                  ("failed to parse stream, ignoring"));
hgs
parents:
diff changeset
  3300
              sub = NULL;
hgs
parents:
diff changeset
  3301
            }
hgs
parents:
diff changeset
  3302
            sub = NULL;
hgs
parents:
diff changeset
  3303
            goto next;
hgs
parents:
diff changeset
  3304
          case GST_RIFF_LIST_odml:
hgs
parents:
diff changeset
  3305
            gst_avi_demux_parse_odml (avi, sub);
hgs
parents:
diff changeset
  3306
            sub = NULL;
hgs
parents:
diff changeset
  3307
            break;
hgs
parents:
diff changeset
  3308
          default:
hgs
parents:
diff changeset
  3309
            GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  3310
                "Unknown list %" GST_FOURCC_FORMAT " in AVI header",
hgs
parents:
diff changeset
  3311
                GST_FOURCC_ARGS (fourcc));
hgs
parents:
diff changeset
  3312
            GST_MEMDUMP_OBJECT (avi, "Unknown list", GST_BUFFER_DATA (sub),
hgs
parents:
diff changeset
  3313
                GST_BUFFER_SIZE (sub));
hgs
parents:
diff changeset
  3314
            /* fall-through */
hgs
parents:
diff changeset
  3315
          case GST_RIFF_TAG_JUNK:
hgs
parents:
diff changeset
  3316
            goto next;
hgs
parents:
diff changeset
  3317
        }
hgs
parents:
diff changeset
  3318
        break;
hgs
parents:
diff changeset
  3319
      }
hgs
parents:
diff changeset
  3320
      default:
hgs
parents:
diff changeset
  3321
        GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  3322
            "Unknown tag %" GST_FOURCC_FORMAT " in AVI header at off %d",
hgs
parents:
diff changeset
  3323
            GST_FOURCC_ARGS (tag), offset);
hgs
parents:
diff changeset
  3324
        GST_MEMDUMP_OBJECT (avi, "Unknown tag", GST_BUFFER_DATA (sub),
hgs
parents:
diff changeset
  3325
            GST_BUFFER_SIZE (sub));
hgs
parents:
diff changeset
  3326
        /* fall-through */
hgs
parents:
diff changeset
  3327
      case GST_RIFF_TAG_JUNK:
hgs
parents:
diff changeset
  3328
      next:
hgs
parents:
diff changeset
  3329
        if (sub)
hgs
parents:
diff changeset
  3330
          gst_buffer_unref (sub);
hgs
parents:
diff changeset
  3331
        sub = NULL;
hgs
parents:
diff changeset
  3332
        break;
hgs
parents:
diff changeset
  3333
    }
hgs
parents:
diff changeset
  3334
  }
hgs
parents:
diff changeset
  3335
  gst_buffer_unref (buf);
hgs
parents:
diff changeset
  3336
  GST_DEBUG ("elements parsed");
hgs
parents:
diff changeset
  3337
hgs
parents:
diff changeset
  3338
  /* check parsed streams */
hgs
parents:
diff changeset
  3339
  if (avi->num_streams == 0)
hgs
parents:
diff changeset
  3340
    goto no_streams;
hgs
parents:
diff changeset
  3341
  else if (avi->num_streams != avi->avih->streams) {
hgs
parents:
diff changeset
  3342
    GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  3343
        "Stream header mentioned %d streams, but %d available",
hgs
parents:
diff changeset
  3344
        avi->avih->streams, avi->num_streams);
hgs
parents:
diff changeset
  3345
  }
hgs
parents:
diff changeset
  3346
hgs
parents:
diff changeset
  3347
  GST_DEBUG_OBJECT (avi, "skipping junk between header and data, offset=%"
hgs
parents:
diff changeset
  3348
      G_GUINT64_FORMAT, avi->offset);
hgs
parents:
diff changeset
  3349
hgs
parents:
diff changeset
  3350
  /* Now, find the data (i.e. skip all junk between header and data) */
hgs
parents:
diff changeset
  3351
  do {
hgs
parents:
diff changeset
  3352
    guint size;
hgs
parents:
diff changeset
  3353
    guint32 tag, ltag;
hgs
parents:
diff changeset
  3354
hgs
parents:
diff changeset
  3355
    res = gst_pad_pull_range (avi->sinkpad, avi->offset, 12, &buf);
hgs
parents:
diff changeset
  3356
    if (res != GST_FLOW_OK) {
hgs
parents:
diff changeset
  3357
      GST_DEBUG_OBJECT (avi, "pull_range failure while looking for tags");
hgs
parents:
diff changeset
  3358
      goto pull_range_failed;
hgs
parents:
diff changeset
  3359
    } else if (GST_BUFFER_SIZE (buf) < 12) {
hgs
parents:
diff changeset
  3360
      GST_DEBUG_OBJECT (avi, "got %d bytes which is less than 12 bytes",
hgs
parents:
diff changeset
  3361
          GST_BUFFER_SIZE (buf));
hgs
parents:
diff changeset
  3362
      gst_buffer_unref (buf);
hgs
parents:
diff changeset
  3363
      return GST_FLOW_ERROR;
hgs
parents:
diff changeset
  3364
    }
hgs
parents:
diff changeset
  3365
hgs
parents:
diff changeset
  3366
    tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
hgs
parents:
diff changeset
  3367
    size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4);
hgs
parents:
diff changeset
  3368
    ltag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 8);
hgs
parents:
diff changeset
  3369
hgs
parents:
diff changeset
  3370
    GST_DEBUG ("tag %" GST_FOURCC_FORMAT ", size %u",
hgs
parents:
diff changeset
  3371
        GST_FOURCC_ARGS (tag), size);
hgs
parents:
diff changeset
  3372
    GST_MEMDUMP ("Tag content", GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
hgs
parents:
diff changeset
  3373
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  3374
hgs
parents:
diff changeset
  3375
    switch (tag) {
hgs
parents:
diff changeset
  3376
      case GST_RIFF_TAG_LIST:{
hgs
parents:
diff changeset
  3377
        switch (ltag) {
hgs
parents:
diff changeset
  3378
          case GST_RIFF_LIST_movi:
hgs
parents:
diff changeset
  3379
            GST_DEBUG_OBJECT (avi,
hgs
parents:
diff changeset
  3380
                "Reached the 'movi' tag, we're done with skipping");
hgs
parents:
diff changeset
  3381
            goto skipping_done;
hgs
parents:
diff changeset
  3382
          case GST_RIFF_LIST_INFO:
hgs
parents:
diff changeset
  3383
            res =
hgs
parents:
diff changeset
  3384
                gst_riff_read_chunk (element, avi->sinkpad, &avi->offset, &tag,
hgs
parents:
diff changeset
  3385
                &buf);
hgs
parents:
diff changeset
  3386
            if (res != GST_FLOW_OK) {
hgs
parents:
diff changeset
  3387
              GST_DEBUG_OBJECT (avi, "couldn't read INFO chunk");
hgs
parents:
diff changeset
  3388
              goto pull_range_failed;
hgs
parents:
diff changeset
  3389
            }
hgs
parents:
diff changeset
  3390
            GST_DEBUG ("got size %u", GST_BUFFER_SIZE (buf));
hgs
parents:
diff changeset
  3391
            if (size < 4) {
hgs
parents:
diff changeset
  3392
              GST_DEBUG ("skipping INFO LIST prefix");
hgs
parents:
diff changeset
  3393
              avi->offset += (4 - GST_ROUND_UP_2 (size));
hgs
parents:
diff changeset
  3394
              gst_buffer_unref (buf);
hgs
parents:
diff changeset
  3395
              continue;
hgs
parents:
diff changeset
  3396
            }
hgs
parents:
diff changeset
  3397
hgs
parents:
diff changeset
  3398
            sub = gst_buffer_create_sub (buf, 4, GST_BUFFER_SIZE (buf) - 4);
hgs
parents:
diff changeset
  3399
            gst_riff_parse_info (element, sub, &avi->globaltags);
hgs
parents:
diff changeset
  3400
            if (sub) {
hgs
parents:
diff changeset
  3401
              gst_buffer_unref (sub);
hgs
parents:
diff changeset
  3402
              sub = NULL;
hgs
parents:
diff changeset
  3403
            }
hgs
parents:
diff changeset
  3404
            gst_buffer_unref (buf);
hgs
parents:
diff changeset
  3405
            /* gst_riff_read_chunk() has already advanced avi->offset */
hgs
parents:
diff changeset
  3406
            break;
hgs
parents:
diff changeset
  3407
          default:
hgs
parents:
diff changeset
  3408
            GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  3409
                "Skipping unknown list tag %" GST_FOURCC_FORMAT,
hgs
parents:
diff changeset
  3410
                GST_FOURCC_ARGS (ltag));
hgs
parents:
diff changeset
  3411
            avi->offset += 8 + ((size + 1) & ~1);
hgs
parents:
diff changeset
  3412
            break;
hgs
parents:
diff changeset
  3413
        }
hgs
parents:
diff changeset
  3414
      }
hgs
parents:
diff changeset
  3415
        break;
hgs
parents:
diff changeset
  3416
      default:
hgs
parents:
diff changeset
  3417
        GST_WARNING_OBJECT (avi, "Skipping unknown tag %" GST_FOURCC_FORMAT,
hgs
parents:
diff changeset
  3418
            GST_FOURCC_ARGS (tag));
hgs
parents:
diff changeset
  3419
        /* Fall-through */
hgs
parents:
diff changeset
  3420
      case GST_MAKE_FOURCC ('J', 'U', 'N', 'Q'):
hgs
parents:
diff changeset
  3421
      case GST_MAKE_FOURCC ('J', 'U', 'N', 'K'):
hgs
parents:
diff changeset
  3422
        avi->offset += 8 + ((size + 1) & ~1);
hgs
parents:
diff changeset
  3423
        break;
hgs
parents:
diff changeset
  3424
    }
hgs
parents:
diff changeset
  3425
  } while (1);
hgs
parents:
diff changeset
  3426
skipping_done:
hgs
parents:
diff changeset
  3427
hgs
parents:
diff changeset
  3428
  GST_DEBUG_OBJECT (avi, "skipping done ... (streams=%u, stream[0].indexes=%p)",
hgs
parents:
diff changeset
  3429
      avi->num_streams, avi->stream[0].indexes);
hgs
parents:
diff changeset
  3430
hgs
parents:
diff changeset
  3431
  /* create or read stream index (for seeking) */
hgs
parents:
diff changeset
  3432
  if (avi->stream[0].indexes != NULL) {
hgs
parents:
diff changeset
  3433
    /* we read a super index already (gst_avi_demux_parse_superindex() ) */
hgs
parents:
diff changeset
  3434
    gst_avi_demux_read_subindexes_pull (avi, &index, &alloc);
hgs
parents:
diff changeset
  3435
  }
hgs
parents:
diff changeset
  3436
  if (!index) {
hgs
parents:
diff changeset
  3437
    if (avi->avih->flags & GST_RIFF_AVIH_HASINDEX) {
hgs
parents:
diff changeset
  3438
      gst_avi_demux_stream_index (avi, &index, &alloc);
hgs
parents:
diff changeset
  3439
    }
hgs
parents:
diff changeset
  3440
    /* some indexes are incomplete, continue streaming from there */
hgs
parents:
diff changeset
  3441
    if (!index)
hgs
parents:
diff changeset
  3442
      gst_avi_demux_stream_scan (avi, &index, &alloc);
hgs
parents:
diff changeset
  3443
  }
hgs
parents:
diff changeset
  3444
hgs
parents:
diff changeset
  3445
  /* this is a fatal error */
hgs
parents:
diff changeset
  3446
  if (!index)
hgs
parents:
diff changeset
  3447
    goto no_index;
hgs
parents:
diff changeset
  3448
hgs
parents:
diff changeset
  3449
  if (!gst_avi_demux_massage_index (avi, index, alloc))
hgs
parents:
diff changeset
  3450
    goto no_index;
hgs
parents:
diff changeset
  3451
hgs
parents:
diff changeset
  3452
  gst_avi_demux_calculate_durations_from_index (avi);
hgs
parents:
diff changeset
  3453
hgs
parents:
diff changeset
  3454
  /* create initial NEWSEGMENT event */
hgs
parents:
diff changeset
  3455
  if ((stop = avi->segment.stop) == GST_CLOCK_TIME_NONE)
hgs
parents:
diff changeset
  3456
    stop = avi->segment.duration;
hgs
parents:
diff changeset
  3457
hgs
parents:
diff changeset
  3458
  GST_DEBUG_OBJECT (avi, "segment stop %" G_GINT64_FORMAT, stop);
hgs
parents:
diff changeset
  3459
hgs
parents:
diff changeset
  3460
  if (avi->seek_event)
hgs
parents:
diff changeset
  3461
    gst_event_unref (avi->seek_event);
hgs
parents:
diff changeset
  3462
  avi->seek_event = gst_event_new_new_segment
hgs
parents:
diff changeset
  3463
      (FALSE, avi->segment.rate, GST_FORMAT_TIME,
hgs
parents:
diff changeset
  3464
      avi->segment.start, stop, avi->segment.start);
hgs
parents:
diff changeset
  3465
hgs
parents:
diff changeset
  3466
  /* at this point we know all the streams and we can signal the no more
hgs
parents:
diff changeset
  3467
   * pads signal */
hgs
parents:
diff changeset
  3468
  GST_DEBUG_OBJECT (avi, "signaling no more pads");
hgs
parents:
diff changeset
  3469
  gst_element_no_more_pads (GST_ELEMENT_CAST (avi));
hgs
parents:
diff changeset
  3470
hgs
parents:
diff changeset
  3471
  return GST_FLOW_OK;
hgs
parents:
diff changeset
  3472
hgs
parents:
diff changeset
  3473
  /* ERRORS */
hgs
parents:
diff changeset
  3474
no_list:
hgs
parents:
diff changeset
  3475
  {
hgs
parents:
diff changeset
  3476
    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
hgs
parents:
diff changeset
  3477
        ("Invalid AVI header (no LIST at start): %"
hgs
parents:
diff changeset
  3478
            GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
hgs
parents:
diff changeset
  3479
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  3480
    return GST_FLOW_ERROR;
hgs
parents:
diff changeset
  3481
  }
hgs
parents:
diff changeset
  3482
no_header:
hgs
parents:
diff changeset
  3483
  {
hgs
parents:
diff changeset
  3484
    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
hgs
parents:
diff changeset
  3485
        ("Invalid AVI header (no hdrl at start): %"
hgs
parents:
diff changeset
  3486
            GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
hgs
parents:
diff changeset
  3487
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  3488
    return GST_FLOW_ERROR;
hgs
parents:
diff changeset
  3489
  }
hgs
parents:
diff changeset
  3490
no_avih:
hgs
parents:
diff changeset
  3491
  {
hgs
parents:
diff changeset
  3492
    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
hgs
parents:
diff changeset
  3493
        ("Invalid AVI header (no avih at start): %"
hgs
parents:
diff changeset
  3494
            GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
hgs
parents:
diff changeset
  3495
    if (sub)
hgs
parents:
diff changeset
  3496
      gst_buffer_unref (sub);
hgs
parents:
diff changeset
  3497
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  3498
    return GST_FLOW_ERROR;
hgs
parents:
diff changeset
  3499
  }
hgs
parents:
diff changeset
  3500
invalid_avih:
hgs
parents:
diff changeset
  3501
  {
hgs
parents:
diff changeset
  3502
    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
hgs
parents:
diff changeset
  3503
        ("Invalid AVI header (cannot parse avih at start)"));
hgs
parents:
diff changeset
  3504
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  3505
    return GST_FLOW_ERROR;
hgs
parents:
diff changeset
  3506
  }
hgs
parents:
diff changeset
  3507
no_streams:
hgs
parents:
diff changeset
  3508
  {
hgs
parents:
diff changeset
  3509
    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("No streams found"));
hgs
parents:
diff changeset
  3510
    return GST_FLOW_ERROR;
hgs
parents:
diff changeset
  3511
  }
hgs
parents:
diff changeset
  3512
no_index:
hgs
parents:
diff changeset
  3513
  {
hgs
parents:
diff changeset
  3514
    GST_WARNING ("file without or too big index");
hgs
parents:
diff changeset
  3515
    g_list_free (index);
hgs
parents:
diff changeset
  3516
    g_list_foreach (alloc, (GFunc) g_free, NULL);
hgs
parents:
diff changeset
  3517
    g_list_free (alloc);
hgs
parents:
diff changeset
  3518
hgs
parents:
diff changeset
  3519
    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
hgs
parents:
diff changeset
  3520
        ("Could not get/create index"));
hgs
parents:
diff changeset
  3521
    return GST_FLOW_ERROR;
hgs
parents:
diff changeset
  3522
  }
hgs
parents:
diff changeset
  3523
pull_range_failed:
hgs
parents:
diff changeset
  3524
  {
hgs
parents:
diff changeset
  3525
    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
hgs
parents:
diff changeset
  3526
        ("pull_range flow reading header: %s", gst_flow_get_name (res)));
hgs
parents:
diff changeset
  3527
    return GST_FLOW_ERROR;
hgs
parents:
diff changeset
  3528
  }
hgs
parents:
diff changeset
  3529
}
hgs
parents:
diff changeset
  3530
hgs
parents:
diff changeset
  3531
/*
hgs
parents:
diff changeset
  3532
 * Do the actual seeking.
hgs
parents:
diff changeset
  3533
 */
hgs
parents:
diff changeset
  3534
static gboolean
hgs
parents:
diff changeset
  3535
gst_avi_demux_do_seek (GstAviDemux * avi, GstSegment * segment)
hgs
parents:
diff changeset
  3536
{
hgs
parents:
diff changeset
  3537
  GstClockTime seek_time;
hgs
parents:
diff changeset
  3538
  gboolean keyframe;
hgs
parents:
diff changeset
  3539
  gst_avi_index_entry *entry, *kentry;
hgs
parents:
diff changeset
  3540
  gint old_entry;
hgs
parents:
diff changeset
  3541
hgs
parents:
diff changeset
  3542
  seek_time = segment->last_stop;
hgs
parents:
diff changeset
  3543
  keyframe = !!(segment->flags & GST_SEEK_FLAG_KEY_UNIT);
hgs
parents:
diff changeset
  3544
hgs
parents:
diff changeset
  3545
  /* FIXME: if we seek in an openDML file, we will have multiple
hgs
parents:
diff changeset
  3546
   * primary levels. Seeking in between those will cause havoc. */
hgs
parents:
diff changeset
  3547
hgs
parents:
diff changeset
  3548
  /* save old position so we can see if we must mark a discont. */
hgs
parents:
diff changeset
  3549
  old_entry = avi->current_entry;
hgs
parents:
diff changeset
  3550
hgs
parents:
diff changeset
  3551
  /* get the entry for the requested position, which is always in last_stop.
hgs
parents:
diff changeset
  3552
   * we search the index entry for stream 0, since all entries are sorted by
hgs
parents:
diff changeset
  3553
   * time and stream we automagically are positioned for the other streams as
hgs
parents:
diff changeset
  3554
   * well. FIXME, this code assumes the main stream with keyframes is stream 0,
hgs
parents:
diff changeset
  3555
   * which is mostly correct... */
hgs
parents:
diff changeset
  3556
  if (!(entry = gst_avi_demux_index_entry_for_time (avi, 0, seek_time)))
hgs
parents:
diff changeset
  3557
    goto no_entry;
hgs
parents:
diff changeset
  3558
hgs
parents:
diff changeset
  3559
  GST_DEBUG_OBJECT (avi,
hgs
parents:
diff changeset
  3560
      "Got requested entry %d [stream:%d / ts:%" GST_TIME_FORMAT
hgs
parents:
diff changeset
  3561
      " / duration:%" GST_TIME_FORMAT "]", entry->index_nr,
hgs
parents:
diff changeset
  3562
      entry->stream_nr, GST_TIME_ARGS (entry->ts), GST_TIME_ARGS (entry->dur));
hgs
parents:
diff changeset
  3563
hgs
parents:
diff changeset
  3564
  /* check if we are already on a keyframe */
hgs
parents:
diff changeset
  3565
  if (!(entry->flags & GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME)) {
hgs
parents:
diff changeset
  3566
    /* now go to the previous keyframe, this is where we should start
hgs
parents:
diff changeset
  3567
     * decoding from. */
hgs
parents:
diff changeset
  3568
    if (!(kentry = gst_avi_demux_index_prev (avi, 0, entry->index_nr,
hgs
parents:
diff changeset
  3569
                GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME))) {
hgs
parents:
diff changeset
  3570
      goto no_entry;
hgs
parents:
diff changeset
  3571
    }
hgs
parents:
diff changeset
  3572
  } else {
hgs
parents:
diff changeset
  3573
    /* we were on a keyframe */
hgs
parents:
diff changeset
  3574
    kentry = entry;
hgs
parents:
diff changeset
  3575
  }
hgs
parents:
diff changeset
  3576
hgs
parents:
diff changeset
  3577
  GST_DEBUG_OBJECT (avi,
hgs
parents:
diff changeset
  3578
      "Got keyframe entry %d [stream:%d / ts:%" GST_TIME_FORMAT
hgs
parents:
diff changeset
  3579
      " / duration:%" GST_TIME_FORMAT "]", kentry->index_nr,
hgs
parents:
diff changeset
  3580
      entry->stream_nr, GST_TIME_ARGS (kentry->ts),
hgs
parents:
diff changeset
  3581
      GST_TIME_ARGS (kentry->dur));
hgs
parents:
diff changeset
  3582
hgs
parents:
diff changeset
  3583
  /* we must start decoding at the keyframe */
hgs
parents:
diff changeset
  3584
  avi->current_entry = kentry->index_nr;
hgs
parents:
diff changeset
  3585
hgs
parents:
diff changeset
  3586
  if (segment->rate < 0.0) {
hgs
parents:
diff changeset
  3587
    gst_avi_index_entry *next_keyframe;
hgs
parents:
diff changeset
  3588
hgs
parents:
diff changeset
  3589
    /* Because we don't know the frame order we need to push from the prev keyframe
hgs
parents:
diff changeset
  3590
     * to the next keyframe. If there is a smart decoder downstream he will notice
hgs
parents:
diff changeset
  3591
     * that there are too many encoded frames send and return UNEXPECTED when there
hgs
parents:
diff changeset
  3592
     * are enough decoded frames to fill the segment.
hgs
parents:
diff changeset
  3593
     */
hgs
parents:
diff changeset
  3594
    next_keyframe =
hgs
parents:
diff changeset
  3595
        gst_avi_demux_index_next (avi, 0, kentry->index_nr,
hgs
parents:
diff changeset
  3596
        GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME);
hgs
parents:
diff changeset
  3597
    if (!next_keyframe)
hgs
parents:
diff changeset
  3598
      next_keyframe = gst_avi_demux_index_last (avi, 0);
hgs
parents:
diff changeset
  3599
hgs
parents:
diff changeset
  3600
    avi->reverse_start_index = kentry->index_nr;
hgs
parents:
diff changeset
  3601
    avi->reverse_stop_index = next_keyframe->index_nr;
hgs
parents:
diff changeset
  3602
hgs
parents:
diff changeset
  3603
    GST_DEBUG_OBJECT (avi, "reverse seek: start idx (%d) and stop idx (%d)",
hgs
parents:
diff changeset
  3604
        avi->reverse_start_index, avi->reverse_stop_index);
hgs
parents:
diff changeset
  3605
  }
hgs
parents:
diff changeset
  3606
hgs
parents:
diff changeset
  3607
  if (keyframe) {
hgs
parents:
diff changeset
  3608
    /* when seeking to a keyframe, we update the result seek time
hgs
parents:
diff changeset
  3609
     * to the time of the keyframe. */
hgs
parents:
diff changeset
  3610
    seek_time = avi->index_entries[avi->current_entry].ts;
hgs
parents:
diff changeset
  3611
  }
hgs
parents:
diff changeset
  3612
hgs
parents:
diff changeset
  3613
next:
hgs
parents:
diff changeset
  3614
  /* if we changed position, mark a DISCONT on all streams */
hgs
parents:
diff changeset
  3615
  if (avi->current_entry != old_entry) {
hgs
parents:
diff changeset
  3616
    gint i;
hgs
parents:
diff changeset
  3617
hgs
parents:
diff changeset
  3618
    for (i = 0; i < avi->num_streams; i++) {
hgs
parents:
diff changeset
  3619
      avi->stream[i].discont = TRUE;
hgs
parents:
diff changeset
  3620
    }
hgs
parents:
diff changeset
  3621
  }
hgs
parents:
diff changeset
  3622
hgs
parents:
diff changeset
  3623
  GST_DEBUG_OBJECT (avi, "seek: %" GST_TIME_FORMAT
hgs
parents:
diff changeset
  3624
      " keyframe seeking:%d", GST_TIME_ARGS (seek_time), keyframe);
hgs
parents:
diff changeset
  3625
hgs
parents:
diff changeset
  3626
  /* the seek time is also the last_stop and stream time */
hgs
parents:
diff changeset
  3627
  segment->last_stop = seek_time;
hgs
parents:
diff changeset
  3628
  segment->time = seek_time;
hgs
parents:
diff changeset
  3629
hgs
parents:
diff changeset
  3630
  return TRUE;
hgs
parents:
diff changeset
  3631
hgs
parents:
diff changeset
  3632
no_entry:
hgs
parents:
diff changeset
  3633
  {
hgs
parents:
diff changeset
  3634
    /* we could not find an entry for the given time */
hgs
parents:
diff changeset
  3635
    GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  3636
        "Couldn't find AviIndexEntry for time:%" GST_TIME_FORMAT,
hgs
parents:
diff changeset
  3637
        GST_TIME_ARGS (seek_time));
hgs
parents:
diff changeset
  3638
    if (avi->current_entry >= avi->index_size && avi->index_size > 0)
hgs
parents:
diff changeset
  3639
      avi->current_entry = avi->index_size - 1;
hgs
parents:
diff changeset
  3640
hgs
parents:
diff changeset
  3641
    goto next;
hgs
parents:
diff changeset
  3642
  }
hgs
parents:
diff changeset
  3643
}
hgs
parents:
diff changeset
  3644
hgs
parents:
diff changeset
  3645
/*
hgs
parents:
diff changeset
  3646
 * Handle seek event.
hgs
parents:
diff changeset
  3647
 */
hgs
parents:
diff changeset
  3648
static gboolean
hgs
parents:
diff changeset
  3649
gst_avi_demux_handle_seek (GstAviDemux * avi, GstPad * pad, GstEvent * event)
hgs
parents:
diff changeset
  3650
{
hgs
parents:
diff changeset
  3651
  gdouble rate;
hgs
parents:
diff changeset
  3652
  GstFormat format;
hgs
parents:
diff changeset
  3653
  GstSeekFlags flags;
hgs
parents:
diff changeset
  3654
  GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type;
hgs
parents:
diff changeset
  3655
  gint64 cur, stop;
hgs
parents:
diff changeset
  3656
  gboolean flush;
hgs
parents:
diff changeset
  3657
  gboolean update;
hgs
parents:
diff changeset
  3658
  GstSegment seeksegment = { 0, };
hgs
parents:
diff changeset
  3659
hgs
parents:
diff changeset
  3660
  if (event) {
hgs
parents:
diff changeset
  3661
    GST_DEBUG_OBJECT (avi, "doing seek with event");
hgs
parents:
diff changeset
  3662
hgs
parents:
diff changeset
  3663
    gst_event_parse_seek (event, &rate, &format, &flags,
hgs
parents:
diff changeset
  3664
        &cur_type, &cur, &stop_type, &stop);
hgs
parents:
diff changeset
  3665
hgs
parents:
diff changeset
  3666
    /* we have to have a format as the segment format. Try to convert
hgs
parents:
diff changeset
  3667
     * if not. */
hgs
parents:
diff changeset
  3668
    if (format != GST_FORMAT_TIME) {
hgs
parents:
diff changeset
  3669
      GstFormat fmt = GST_FORMAT_TIME;
hgs
parents:
diff changeset
  3670
      gboolean res = TRUE;
hgs
parents:
diff changeset
  3671
hgs
parents:
diff changeset
  3672
      if (cur_type != GST_SEEK_TYPE_NONE)
hgs
parents:
diff changeset
  3673
        res = gst_pad_query_convert (pad, format, cur, &fmt, &cur);
hgs
parents:
diff changeset
  3674
      if (res && stop_type != GST_SEEK_TYPE_NONE)
hgs
parents:
diff changeset
  3675
        res = gst_pad_query_convert (pad, format, stop, &fmt, &stop);
hgs
parents:
diff changeset
  3676
      if (!res)
hgs
parents:
diff changeset
  3677
        goto no_format;
hgs
parents:
diff changeset
  3678
hgs
parents:
diff changeset
  3679
      format = fmt;
hgs
parents:
diff changeset
  3680
    }
hgs
parents:
diff changeset
  3681
    GST_DEBUG_OBJECT (avi,
hgs
parents:
diff changeset
  3682
        "seek requested: rate %g cur %" GST_TIME_FORMAT " stop %"
hgs
parents:
diff changeset
  3683
        GST_TIME_FORMAT, rate, GST_TIME_ARGS (cur), GST_TIME_ARGS (stop));
hgs
parents:
diff changeset
  3684
    /* FIXME: can we do anything with rate!=1.0 */
hgs
parents:
diff changeset
  3685
  } else {
hgs
parents:
diff changeset
  3686
    GST_DEBUG_OBJECT (avi, "doing seek without event");
hgs
parents:
diff changeset
  3687
    flags = 0;
hgs
parents:
diff changeset
  3688
    rate = 1.0;
hgs
parents:
diff changeset
  3689
  }
hgs
parents:
diff changeset
  3690
hgs
parents:
diff changeset
  3691
  /* save flush flag */
hgs
parents:
diff changeset
  3692
  flush = flags & GST_SEEK_FLAG_FLUSH;
hgs
parents:
diff changeset
  3693
hgs
parents:
diff changeset
  3694
  if (flush) {
hgs
parents:
diff changeset
  3695
    GstEvent *event = gst_event_new_flush_start ();
hgs
parents:
diff changeset
  3696
hgs
parents:
diff changeset
  3697
    /* for a flushing seek, we send a flush_start on all pads. This will
hgs
parents:
diff changeset
  3698
     * eventually stop streaming with a WRONG_STATE. We can thus eventually
hgs
parents:
diff changeset
  3699
     * take the STREAM_LOCK. */
hgs
parents:
diff changeset
  3700
    GST_DEBUG_OBJECT (avi, "sending flush start");
hgs
parents:
diff changeset
  3701
    gst_avi_demux_push_event (avi, gst_event_ref (event));
hgs
parents:
diff changeset
  3702
    gst_pad_push_event (avi->sinkpad, event);
hgs
parents:
diff changeset
  3703
  } else {
hgs
parents:
diff changeset
  3704
    /* a non-flushing seek, we PAUSE the task so that we can take the
hgs
parents:
diff changeset
  3705
     * STREAM_LOCK */
hgs
parents:
diff changeset
  3706
    GST_DEBUG_OBJECT (avi, "non flushing seek, pausing task");
hgs
parents:
diff changeset
  3707
    gst_pad_pause_task (avi->sinkpad);
hgs
parents:
diff changeset
  3708
  }
hgs
parents:
diff changeset
  3709
hgs
parents:
diff changeset
  3710
  /* wait for streaming to stop */
hgs
parents:
diff changeset
  3711
  GST_DEBUG_OBJECT (avi, "wait for streaming to stop");
hgs
parents:
diff changeset
  3712
  GST_PAD_STREAM_LOCK (avi->sinkpad);
hgs
parents:
diff changeset
  3713
hgs
parents:
diff changeset
  3714
  /* copy segment, we need this because we still need the old
hgs
parents:
diff changeset
  3715
   * segment when we close the current segment. */
hgs
parents:
diff changeset
  3716
  memcpy (&seeksegment, &avi->segment, sizeof (GstSegment));
hgs
parents:
diff changeset
  3717
hgs
parents:
diff changeset
  3718
  if (event) {
hgs
parents:
diff changeset
  3719
    GST_DEBUG_OBJECT (avi, "configuring seek");
hgs
parents:
diff changeset
  3720
    gst_segment_set_seek (&seeksegment, rate, format, flags,
hgs
parents:
diff changeset
  3721
        cur_type, cur, stop_type, stop, &update);
hgs
parents:
diff changeset
  3722
  }
hgs
parents:
diff changeset
  3723
hgs
parents:
diff changeset
  3724
  /* do the seek, seeksegment.last_stop contains the new position, this
hgs
parents:
diff changeset
  3725
   * actually never fails. */
hgs
parents:
diff changeset
  3726
  gst_avi_demux_do_seek (avi, &seeksegment);
hgs
parents:
diff changeset
  3727
hgs
parents:
diff changeset
  3728
  if (flush) {
hgs
parents:
diff changeset
  3729
    gint i;
hgs
parents:
diff changeset
  3730
hgs
parents:
diff changeset
  3731
    GST_DEBUG_OBJECT (avi, "sending flush stop");
hgs
parents:
diff changeset
  3732
    gst_avi_demux_push_event (avi, gst_event_new_flush_stop ());
hgs
parents:
diff changeset
  3733
    gst_pad_push_event (avi->sinkpad, gst_event_new_flush_stop ());
hgs
parents:
diff changeset
  3734
    /* reset the last flow and mark discont, FLUSH is always DISCONT */
hgs
parents:
diff changeset
  3735
    for (i = 0; i < avi->num_streams; i++) {
hgs
parents:
diff changeset
  3736
      avi->stream[i].last_flow = GST_FLOW_OK;
hgs
parents:
diff changeset
  3737
      avi->stream[i].discont = TRUE;
hgs
parents:
diff changeset
  3738
    }
hgs
parents:
diff changeset
  3739
  } else if (avi->segment_running) {
hgs
parents:
diff changeset
  3740
    GstEvent *seg;
hgs
parents:
diff changeset
  3741
hgs
parents:
diff changeset
  3742
    /* we are running the current segment and doing a non-flushing seek,
hgs
parents:
diff changeset
  3743
     * close the segment first based on the last_stop. */
hgs
parents:
diff changeset
  3744
    GST_DEBUG_OBJECT (avi, "closing running segment %" G_GINT64_FORMAT
hgs
parents:
diff changeset
  3745
        " to %" G_GINT64_FORMAT, avi->segment.start, avi->segment.last_stop);
hgs
parents:
diff changeset
  3746
    seg = gst_event_new_new_segment (TRUE,
hgs
parents:
diff changeset
  3747
        avi->segment.rate, avi->segment.format,
hgs
parents:
diff changeset
  3748
        avi->segment.start, avi->segment.last_stop, avi->segment.time);
hgs
parents:
diff changeset
  3749
    gst_avi_demux_push_event (avi, seg);
hgs
parents:
diff changeset
  3750
  }
hgs
parents:
diff changeset
  3751
hgs
parents:
diff changeset
  3752
  /* now update the real segment info */
hgs
parents:
diff changeset
  3753
  memcpy (&avi->segment, &seeksegment, sizeof (GstSegment));
hgs
parents:
diff changeset
  3754
hgs
parents:
diff changeset
  3755
  /* post the SEGMENT_START message when we do segmented playback */
hgs
parents:
diff changeset
  3756
  if (avi->segment.flags & GST_SEEK_FLAG_SEGMENT) {
hgs
parents:
diff changeset
  3757
    gst_element_post_message (GST_ELEMENT (avi),
hgs
parents:
diff changeset
  3758
        gst_message_new_segment_start (GST_OBJECT (avi),
hgs
parents:
diff changeset
  3759
            avi->segment.format, avi->segment.last_stop));
hgs
parents:
diff changeset
  3760
  }
hgs
parents:
diff changeset
  3761
hgs
parents:
diff changeset
  3762
  /* prepare for streaming again */
hgs
parents:
diff changeset
  3763
  if ((stop = avi->segment.stop) == GST_CLOCK_TIME_NONE)
hgs
parents:
diff changeset
  3764
    stop = avi->segment.duration;
hgs
parents:
diff changeset
  3765
hgs
parents:
diff changeset
  3766
  /* queue the segment event for the streaming thread. */
hgs
parents:
diff changeset
  3767
  if (avi->seek_event)
hgs
parents:
diff changeset
  3768
    gst_event_unref (avi->seek_event);
hgs
parents:
diff changeset
  3769
  if (avi->segment.rate > 0.0) {
hgs
parents:
diff changeset
  3770
    avi->seek_event = gst_event_new_new_segment (FALSE,
hgs
parents:
diff changeset
  3771
        avi->segment.rate, avi->segment.format,
hgs
parents:
diff changeset
  3772
        avi->segment.last_stop, stop, avi->segment.time);
hgs
parents:
diff changeset
  3773
  } else {
hgs
parents:
diff changeset
  3774
    avi->seek_event = gst_event_new_new_segment (FALSE,
hgs
parents:
diff changeset
  3775
        avi->segment.rate, avi->segment.format,
hgs
parents:
diff changeset
  3776
        avi->segment.start, avi->segment.last_stop, avi->segment.start);
hgs
parents:
diff changeset
  3777
  }
hgs
parents:
diff changeset
  3778
hgs
parents:
diff changeset
  3779
  if (!avi->streaming) {
hgs
parents:
diff changeset
  3780
    avi->segment_running = TRUE;
hgs
parents:
diff changeset
  3781
    gst_pad_start_task (avi->sinkpad, (GstTaskFunction) gst_avi_demux_loop,
hgs
parents:
diff changeset
  3782
        avi->sinkpad);
hgs
parents:
diff changeset
  3783
  }
hgs
parents:
diff changeset
  3784
  GST_PAD_STREAM_UNLOCK (avi->sinkpad);
hgs
parents:
diff changeset
  3785
hgs
parents:
diff changeset
  3786
  return TRUE;
hgs
parents:
diff changeset
  3787
hgs
parents:
diff changeset
  3788
  /* ERRORS */
hgs
parents:
diff changeset
  3789
no_format:
hgs
parents:
diff changeset
  3790
  {
hgs
parents:
diff changeset
  3791
    GST_DEBUG_OBJECT (avi, "unsupported format given, seek aborted.");
hgs
parents:
diff changeset
  3792
    return FALSE;
hgs
parents:
diff changeset
  3793
  }
hgs
parents:
diff changeset
  3794
}
hgs
parents:
diff changeset
  3795
hgs
parents:
diff changeset
  3796
/*
hgs
parents:
diff changeset
  3797
 * Helper for gst_avi_demux_invert()
hgs
parents:
diff changeset
  3798
 */
hgs
parents:
diff changeset
  3799
static inline void
hgs
parents:
diff changeset
  3800
swap_line (guint8 * d1, guint8 * d2, guint8 * tmp, gint bytes)
hgs
parents:
diff changeset
  3801
{
hgs
parents:
diff changeset
  3802
  memcpy (tmp, d1, bytes);
hgs
parents:
diff changeset
  3803
  memcpy (d1, d2, bytes);
hgs
parents:
diff changeset
  3804
  memcpy (d2, tmp, bytes);
hgs
parents:
diff changeset
  3805
}
hgs
parents:
diff changeset
  3806
hgs
parents:
diff changeset
  3807
hgs
parents:
diff changeset
  3808
#define gst_avi_demux_is_uncompressed(fourcc)		\
hgs
parents:
diff changeset
  3809
  (fourcc == GST_RIFF_DIB ||				\
hgs
parents:
diff changeset
  3810
   fourcc == GST_RIFF_rgb ||				\
hgs
parents:
diff changeset
  3811
   fourcc == GST_RIFF_RGB || fourcc == GST_RIFF_RAW)
hgs
parents:
diff changeset
  3812
hgs
parents:
diff changeset
  3813
/*
hgs
parents:
diff changeset
  3814
 * Invert DIB buffers... Takes existing buffer and
hgs
parents:
diff changeset
  3815
 * returns either the buffer or a new one (with old
hgs
parents:
diff changeset
  3816
 * one dereferenced).
hgs
parents:
diff changeset
  3817
 * FIXME: can't we preallocate tmp? and remember stride, bpp?
hgs
parents:
diff changeset
  3818
 */
hgs
parents:
diff changeset
  3819
static GstBuffer *
hgs
parents:
diff changeset
  3820
gst_avi_demux_invert (avi_stream_context * stream, GstBuffer * buf)
hgs
parents:
diff changeset
  3821
{
hgs
parents:
diff changeset
  3822
  GstStructure *s;
hgs
parents:
diff changeset
  3823
  gint y, w, h;
hgs
parents:
diff changeset
  3824
  gint bpp, stride;
hgs
parents:
diff changeset
  3825
  guint8 *tmp = NULL;
hgs
parents:
diff changeset
  3826
hgs
parents:
diff changeset
  3827
  if (stream->strh->type != GST_RIFF_FCC_vids)
hgs
parents:
diff changeset
  3828
    return buf;
hgs
parents:
diff changeset
  3829
hgs
parents:
diff changeset
  3830
  if (!gst_avi_demux_is_uncompressed (stream->strh->fcc_handler)) {
hgs
parents:
diff changeset
  3831
    return buf;                 /* Ignore non DIB buffers */
hgs
parents:
diff changeset
  3832
  }
hgs
parents:
diff changeset
  3833
hgs
parents:
diff changeset
  3834
  s = gst_caps_get_structure (GST_PAD_CAPS (stream->pad), 0);
hgs
parents:
diff changeset
  3835
  if (!gst_structure_get_int (s, "bpp", &bpp)) {
hgs
parents:
diff changeset
  3836
    GST_WARNING ("Failed to retrieve depth from caps");
hgs
parents:
diff changeset
  3837
    return buf;
hgs
parents:
diff changeset
  3838
  }
hgs
parents:
diff changeset
  3839
hgs
parents:
diff changeset
  3840
  if (stream->strf.vids == NULL) {
hgs
parents:
diff changeset
  3841
    GST_WARNING ("Failed to retrieve vids for stream");
hgs
parents:
diff changeset
  3842
    return buf;
hgs
parents:
diff changeset
  3843
  }
hgs
parents:
diff changeset
  3844
hgs
parents:
diff changeset
  3845
  h = stream->strf.vids->height;
hgs
parents:
diff changeset
  3846
  w = stream->strf.vids->width;
hgs
parents:
diff changeset
  3847
  stride = w * (bpp / 8);
hgs
parents:
diff changeset
  3848
hgs
parents:
diff changeset
  3849
  buf = gst_buffer_make_writable (buf);
hgs
parents:
diff changeset
  3850
  if (GST_BUFFER_SIZE (buf) < (stride * h)) {
hgs
parents:
diff changeset
  3851
    GST_WARNING ("Buffer is smaller than reported Width x Height x Depth");
hgs
parents:
diff changeset
  3852
    return buf;
hgs
parents:
diff changeset
  3853
  }
hgs
parents:
diff changeset
  3854
hgs
parents:
diff changeset
  3855
  tmp = g_malloc (stride);
hgs
parents:
diff changeset
  3856
hgs
parents:
diff changeset
  3857
  for (y = 0; y < h / 2; y++) {
hgs
parents:
diff changeset
  3858
    swap_line (GST_BUFFER_DATA (buf) + stride * y,
hgs
parents:
diff changeset
  3859
        GST_BUFFER_DATA (buf) + stride * (h - 1 - y), tmp, stride);
hgs
parents:
diff changeset
  3860
  }
hgs
parents:
diff changeset
  3861
hgs
parents:
diff changeset
  3862
  g_free (tmp);
hgs
parents:
diff changeset
  3863
hgs
parents:
diff changeset
  3864
  return buf;
hgs
parents:
diff changeset
  3865
}
hgs
parents:
diff changeset
  3866
hgs
parents:
diff changeset
  3867
/*
hgs
parents:
diff changeset
  3868
 * Returns the aggregated GstFlowReturn.
hgs
parents:
diff changeset
  3869
 */
hgs
parents:
diff changeset
  3870
static GstFlowReturn
hgs
parents:
diff changeset
  3871
gst_avi_demux_combine_flows (GstAviDemux * avi, avi_stream_context * stream,
hgs
parents:
diff changeset
  3872
    GstFlowReturn ret)
hgs
parents:
diff changeset
  3873
{
hgs
parents:
diff changeset
  3874
  guint i;
hgs
parents:
diff changeset
  3875
hgs
parents:
diff changeset
  3876
  /* store the value */
hgs
parents:
diff changeset
  3877
  stream->last_flow = ret;
hgs
parents:
diff changeset
  3878
hgs
parents:
diff changeset
  3879
  /* any other error that is not-linked can be returned right away */
hgs
parents:
diff changeset
  3880
  if (G_UNLIKELY (ret != GST_FLOW_NOT_LINKED))
hgs
parents:
diff changeset
  3881
    goto done;
hgs
parents:
diff changeset
  3882
hgs
parents:
diff changeset
  3883
  /* only return NOT_LINKED if all other pads returned NOT_LINKED */
hgs
parents:
diff changeset
  3884
  for (i = 0; i < avi->num_streams; i++) {
hgs
parents:
diff changeset
  3885
    avi_stream_context *ostream = &avi->stream[i];
hgs
parents:
diff changeset
  3886
hgs
parents:
diff changeset
  3887
    ret = ostream->last_flow;
hgs
parents:
diff changeset
  3888
    /* some other return value (must be SUCCESS but we can return
hgs
parents:
diff changeset
  3889
     * other values as well) */
hgs
parents:
diff changeset
  3890
    if (G_UNLIKELY (ret != GST_FLOW_NOT_LINKED))
hgs
parents:
diff changeset
  3891
      goto done;
hgs
parents:
diff changeset
  3892
  }
hgs
parents:
diff changeset
  3893
  /* if we get here, all other pads were unlinked and we return
hgs
parents:
diff changeset
  3894
   * NOT_LINKED then */
hgs
parents:
diff changeset
  3895
done:
hgs
parents:
diff changeset
  3896
  GST_LOG_OBJECT (avi, "combined return %s", gst_flow_get_name (ret));
hgs
parents:
diff changeset
  3897
  return ret;
hgs
parents:
diff changeset
  3898
}
hgs
parents:
diff changeset
  3899
hgs
parents:
diff changeset
  3900
/*
hgs
parents:
diff changeset
  3901
 * prepare the avi element for a reverse jump to a prev keyframe
hgs
parents:
diff changeset
  3902
 * this function will return the start entry. if the function returns
hgs
parents:
diff changeset
  3903
 * NULL there was no prev keyframe.
hgs
parents:
diff changeset
  3904
 */
hgs
parents:
diff changeset
  3905
static gst_avi_index_entry *
hgs
parents:
diff changeset
  3906
gst_avi_demux_step_reverse (GstAviDemux * avi)
hgs
parents:
diff changeset
  3907
{
hgs
parents:
diff changeset
  3908
  gst_avi_index_entry *entry;
hgs
parents:
diff changeset
  3909
  gint i;
hgs
parents:
diff changeset
  3910
hgs
parents:
diff changeset
  3911
  avi->reverse_stop_index = avi->reverse_start_index;
hgs
parents:
diff changeset
  3912
  entry =
hgs
parents:
diff changeset
  3913
      gst_avi_demux_index_prev (avi, 0, avi->reverse_stop_index,
hgs
parents:
diff changeset
  3914
      GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME);
hgs
parents:
diff changeset
  3915
  if (!entry) {
hgs
parents:
diff changeset
  3916
    GST_DEBUG_OBJECT (avi, "no valid index entry found index %d",
hgs
parents:
diff changeset
  3917
        avi->reverse_stop_index);
hgs
parents:
diff changeset
  3918
    return NULL;
hgs
parents:
diff changeset
  3919
  }
hgs
parents:
diff changeset
  3920
  avi->current_entry = avi->reverse_start_index = entry->index_nr;
hgs
parents:
diff changeset
  3921
  GST_DEBUG_OBJECT (avi,
hgs
parents:
diff changeset
  3922
      "reverse playback jump: start idx (%d) and stop idx (%d)",
hgs
parents:
diff changeset
  3923
      avi->reverse_start_index, avi->reverse_stop_index);
hgs
parents:
diff changeset
  3924
  gst_segment_set_last_stop (&avi->segment, GST_FORMAT_TIME, entry->ts);
hgs
parents:
diff changeset
  3925
  for (i = 0; i < avi->num_streams; i++) {
hgs
parents:
diff changeset
  3926
    avi->stream[i].last_flow = GST_FLOW_OK;
hgs
parents:
diff changeset
  3927
    avi->stream[i].discont = TRUE;
hgs
parents:
diff changeset
  3928
  }
hgs
parents:
diff changeset
  3929
  return entry;
hgs
parents:
diff changeset
  3930
}
hgs
parents:
diff changeset
  3931
hgs
parents:
diff changeset
  3932
/*
hgs
parents:
diff changeset
  3933
 * Read data from one index entry
hgs
parents:
diff changeset
  3934
 */
hgs
parents:
diff changeset
  3935
static GstFlowReturn
hgs
parents:
diff changeset
  3936
gst_avi_demux_process_next_entry (GstAviDemux * avi)
hgs
parents:
diff changeset
  3937
{
hgs
parents:
diff changeset
  3938
  GstFlowReturn res = GST_FLOW_OK;
hgs
parents:
diff changeset
  3939
  gboolean processed = FALSE;
hgs
parents:
diff changeset
  3940
  avi_stream_context *stream;
hgs
parents:
diff changeset
  3941
  gst_avi_index_entry *entry;
hgs
parents:
diff changeset
  3942
  GstBuffer *buf;
hgs
parents:
diff changeset
  3943
hgs
parents:
diff changeset
  3944
  do {
hgs
parents:
diff changeset
  3945
    /* see if we are at the end */
hgs
parents:
diff changeset
  3946
    if ((avi->segment.rate > 0 && avi->current_entry >= avi->index_size))
hgs
parents:
diff changeset
  3947
      goto eos;
hgs
parents:
diff changeset
  3948
hgs
parents:
diff changeset
  3949
    /* get next entry, this will work as we checked for the index size above */
hgs
parents:
diff changeset
  3950
    entry = &avi->index_entries[avi->current_entry++];
hgs
parents:
diff changeset
  3951
hgs
parents:
diff changeset
  3952
    /* check for reverse playback */
hgs
parents:
diff changeset
  3953
    if (avi->segment.rate < 0 && avi->current_entry > avi->reverse_stop_index) {
hgs
parents:
diff changeset
  3954
      GST_LOG_OBJECT (avi, "stop_index %d reached", avi->reverse_stop_index);
hgs
parents:
diff changeset
  3955
hgs
parents:
diff changeset
  3956
      /* check if we have pushed enough data for this segment */
hgs
parents:
diff changeset
  3957
      if (avi->reverse_start_index == 0)
hgs
parents:
diff changeset
  3958
        goto eos_reverse_zero;
hgs
parents:
diff changeset
  3959
      if (avi->index_entries[avi->reverse_start_index].ts < avi->segment.start)
hgs
parents:
diff changeset
  3960
        goto eos_reverse_segment;
hgs
parents:
diff changeset
  3961
hgs
parents:
diff changeset
  3962
      if (!(entry = gst_avi_demux_step_reverse (avi)))
hgs
parents:
diff changeset
  3963
        goto eos;
hgs
parents:
diff changeset
  3964
hgs
parents:
diff changeset
  3965
      avi->current_entry++;
hgs
parents:
diff changeset
  3966
    }
hgs
parents:
diff changeset
  3967
hgs
parents:
diff changeset
  3968
    /* see if we have a valid stream, ignore if not
hgs
parents:
diff changeset
  3969
     * FIXME: can't we check this when building the index?
hgs
parents:
diff changeset
  3970
     *   we check it in _parse_index(), _stream_scan()
hgs
parents:
diff changeset
  3971
     */
hgs
parents:
diff changeset
  3972
    if (entry->stream_nr >= avi->num_streams) {
hgs
parents:
diff changeset
  3973
      GST_WARNING_OBJECT (avi,
hgs
parents:
diff changeset
  3974
          "Entry %d has non-existing stream nr %d",
hgs
parents:
diff changeset
  3975
          avi->current_entry - 1, entry->stream_nr);
hgs
parents:
diff changeset
  3976
      continue;
hgs
parents:
diff changeset
  3977
    }
hgs
parents:
diff changeset
  3978
hgs
parents:
diff changeset
  3979
    /* get stream now */
hgs
parents:
diff changeset
  3980
    stream = &avi->stream[entry->stream_nr];
hgs
parents:
diff changeset
  3981
hgs
parents:
diff changeset
  3982
    if (avi->segment.rate > 0.0) {
hgs
parents:
diff changeset
  3983
      /* only check this for fowards playback for now */
hgs
parents:
diff changeset
  3984
      if ((entry->flags & GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME)
hgs
parents:
diff changeset
  3985
          && GST_CLOCK_TIME_IS_VALID (entry->ts)
hgs
parents:
diff changeset
  3986
          && GST_CLOCK_TIME_IS_VALID (avi->segment.stop)
hgs
parents:
diff changeset
  3987
          && (entry->ts > avi->segment.stop)) {
hgs
parents:
diff changeset
  3988
        goto eos_stop;
hgs
parents:
diff changeset
  3989
      }
hgs
parents:
diff changeset
  3990
    }
hgs
parents:
diff changeset
  3991
hgs
parents:
diff changeset
  3992
    /* skip empty entries */
hgs
parents:
diff changeset
  3993
    if (entry->size == 0 || !stream->pad) {
hgs
parents:
diff changeset
  3994
      GST_DEBUG_OBJECT (avi, "Skipping entry %d (%d, %p)",
hgs
parents:
diff changeset
  3995
          avi->current_entry - 1, entry->size, stream->pad);
hgs
parents:
diff changeset
  3996
      goto next;
hgs
parents:
diff changeset
  3997
    }
hgs
parents:
diff changeset
  3998
hgs
parents:
diff changeset
  3999
    GST_LOG ("reading buffer (size=%d) from stream %d at current pos %"
hgs
parents:
diff changeset
  4000
        G_GUINT64_FORMAT " (%llx)", entry->size, entry->stream_nr,
hgs
parents:
diff changeset
  4001
        avi->index_offset + entry->offset, avi->index_offset + entry->offset);
hgs
parents:
diff changeset
  4002
hgs
parents:
diff changeset
  4003
    /* pull in the data */
hgs
parents:
diff changeset
  4004
    res = gst_pad_pull_range (avi->sinkpad, entry->offset +
hgs
parents:
diff changeset
  4005
        avi->index_offset, entry->size, &buf);
hgs
parents:
diff changeset
  4006
    if (res != GST_FLOW_OK)
hgs
parents:
diff changeset
  4007
      goto pull_failed;
hgs
parents:
diff changeset
  4008
hgs
parents:
diff changeset
  4009
    /* check for short buffers, this is EOS as well */
hgs
parents:
diff changeset
  4010
    if (GST_BUFFER_SIZE (buf) < entry->size)
hgs
parents:
diff changeset
  4011
      goto short_buffer;
hgs
parents:
diff changeset
  4012
hgs
parents:
diff changeset
  4013
    /* invert the picture if needed */
hgs
parents:
diff changeset
  4014
    buf = gst_avi_demux_invert (stream, buf);
hgs
parents:
diff changeset
  4015
hgs
parents:
diff changeset
  4016
    /* mark non-keyframes */
hgs
parents:
diff changeset
  4017
    if (!(entry->flags & GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME))
hgs
parents:
diff changeset
  4018
      GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
hgs
parents:
diff changeset
  4019
hgs
parents:
diff changeset
  4020
    GST_BUFFER_TIMESTAMP (buf) = entry->ts;
hgs
parents:
diff changeset
  4021
    GST_BUFFER_DURATION (buf) = entry->dur;
hgs
parents:
diff changeset
  4022
    if (stream->strh->type == GST_RIFF_FCC_vids) {
hgs
parents:
diff changeset
  4023
      if (stream->current_frame >= 0)
hgs
parents:
diff changeset
  4024
        GST_BUFFER_OFFSET (buf) = stream->current_frame;
hgs
parents:
diff changeset
  4025
      else {
hgs
parents:
diff changeset
  4026
        gint64 framenum;
hgs
parents:
diff changeset
  4027
        GstFormat fmt = GST_FORMAT_DEFAULT;
hgs
parents:
diff changeset
  4028
hgs
parents:
diff changeset
  4029
        if (gst_pad_query_convert (stream->pad, GST_FORMAT_TIME, entry->ts,
hgs
parents:
diff changeset
  4030
                &fmt, &framenum))
hgs
parents:
diff changeset
  4031
          GST_BUFFER_OFFSET (buf) = framenum;
hgs
parents:
diff changeset
  4032
        else
hgs
parents:
diff changeset
  4033
          GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
hgs
parents:
diff changeset
  4034
      }
hgs
parents:
diff changeset
  4035
    } else
hgs
parents:
diff changeset
  4036
      GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
hgs
parents:
diff changeset
  4037
    GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
hgs
parents:
diff changeset
  4038
    gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad));
hgs
parents:
diff changeset
  4039
hgs
parents:
diff changeset
  4040
    GST_DEBUG_OBJECT (avi, "Pushing buffer of size %d, offset %"
hgs
parents:
diff changeset
  4041
        G_GUINT64_FORMAT " and time %"
hgs
parents:
diff changeset
  4042
        GST_TIME_FORMAT " on pad %s",
hgs
parents:
diff changeset
  4043
        GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf),
hgs
parents:
diff changeset
  4044
        GST_TIME_ARGS (entry->ts), GST_PAD_NAME (stream->pad));
hgs
parents:
diff changeset
  4045
hgs
parents:
diff changeset
  4046
    /* update current position in the segment */
hgs
parents:
diff changeset
  4047
    gst_segment_set_last_stop (&avi->segment, GST_FORMAT_TIME, entry->ts);
hgs
parents:
diff changeset
  4048
hgs
parents:
diff changeset
  4049
    /* mark discont when pending */
hgs
parents:
diff changeset
  4050
    if (stream->discont) {
hgs
parents:
diff changeset
  4051
      GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
hgs
parents:
diff changeset
  4052
      stream->discont = FALSE;
hgs
parents:
diff changeset
  4053
    }
hgs
parents:
diff changeset
  4054
hgs
parents:
diff changeset
  4055
    res = gst_pad_push (stream->pad, buf);
hgs
parents:
diff changeset
  4056
hgs
parents:
diff changeset
  4057
    /* mark as processed, we increment the frame and byte counters then
hgs
parents:
diff changeset
  4058
     * leave the while loop and return the GstFlowReturn */
hgs
parents:
diff changeset
  4059
    processed = TRUE;
hgs
parents:
diff changeset
  4060
    GST_DEBUG_OBJECT (avi, "Processed buffer %d: %s", entry->index_nr,
hgs
parents:
diff changeset
  4061
        gst_flow_get_name (res));
hgs
parents:
diff changeset
  4062
hgs
parents:
diff changeset
  4063
    if (avi->segment.rate < 0
hgs
parents:
diff changeset
  4064
        && entry->ts > avi->segment.stop && res == GST_FLOW_UNEXPECTED) {
hgs
parents:
diff changeset
  4065
      /* In reverse playback we can get a GST_FLOW_UNEXPECTED when
hgs
parents:
diff changeset
  4066
       * we are at the end of the segment, so we just need to jump
hgs
parents:
diff changeset
  4067
       * back to the previous section.
hgs
parents:
diff changeset
  4068
       */
hgs
parents:
diff changeset
  4069
      GST_DEBUG_OBJECT (avi, "downstream has reached end of segment");
hgs
parents:
diff changeset
  4070
hgs
parents:
diff changeset
  4071
      if (!(entry = gst_avi_demux_step_reverse (avi)))
hgs
parents:
diff changeset
  4072
        goto eos;
hgs
parents:
diff changeset
  4073
hgs
parents:
diff changeset
  4074
      res = GST_FLOW_OK;
hgs
parents:
diff changeset
  4075
hgs
parents:
diff changeset
  4076
      stream->current_frame = entry->frames_before;
hgs
parents:
diff changeset
  4077
      stream->current_byte = entry->bytes_before;
hgs
parents:
diff changeset
  4078
hgs
parents:
diff changeset
  4079
      continue;
hgs
parents:
diff changeset
  4080
    }
hgs
parents:
diff changeset
  4081
hgs
parents:
diff changeset
  4082
    /* combine flows */
hgs
parents:
diff changeset
  4083
    res = gst_avi_demux_combine_flows (avi, stream, res);
hgs
parents:
diff changeset
  4084
hgs
parents:
diff changeset
  4085
  next:
hgs
parents:
diff changeset
  4086
    stream->current_frame = entry->frames_before + 1;
hgs
parents:
diff changeset
  4087
    stream->current_byte = entry->bytes_before + entry->size;
hgs
parents:
diff changeset
  4088
  } while (!processed);
hgs
parents:
diff changeset
  4089
hgs
parents:
diff changeset
  4090
beach:
hgs
parents:
diff changeset
  4091
  GST_DEBUG_OBJECT (avi, "returning %s", gst_flow_get_name (res));
hgs
parents:
diff changeset
  4092
hgs
parents:
diff changeset
  4093
  return res;
hgs
parents:
diff changeset
  4094
hgs
parents:
diff changeset
  4095
  /* ERRORS */
hgs
parents:
diff changeset
  4096
eos:
hgs
parents:
diff changeset
  4097
  {
hgs
parents:
diff changeset
  4098
    GST_LOG_OBJECT (avi, "Handled last index entry, setting EOS (%d > %d)",
hgs
parents:
diff changeset
  4099
        avi->current_entry, avi->index_size);
hgs
parents:
diff changeset
  4100
    /* we mark the first stream as EOS */
hgs
parents:
diff changeset
  4101
    res = GST_FLOW_UNEXPECTED;
hgs
parents:
diff changeset
  4102
    goto beach;
hgs
parents:
diff changeset
  4103
  }
hgs
parents:
diff changeset
  4104
eos_stop:
hgs
parents:
diff changeset
  4105
  {
hgs
parents:
diff changeset
  4106
    GST_LOG_OBJECT (avi, "Found keyframe after segment,"
hgs
parents:
diff changeset
  4107
        " setting EOS (%" GST_TIME_FORMAT " > %" GST_TIME_FORMAT ")",
hgs
parents:
diff changeset
  4108
        GST_TIME_ARGS (entry->ts), GST_TIME_ARGS (avi->segment.stop));
hgs
parents:
diff changeset
  4109
    res = GST_FLOW_UNEXPECTED;
hgs
parents:
diff changeset
  4110
    goto beach;
hgs
parents:
diff changeset
  4111
  }
hgs
parents:
diff changeset
  4112
eos_reverse_zero:
hgs
parents:
diff changeset
  4113
  {
hgs
parents:
diff changeset
  4114
    GST_DEBUG_OBJECT (avi, "start_index was 0, setting EOS");
hgs
parents:
diff changeset
  4115
    res = GST_FLOW_UNEXPECTED;
hgs
parents:
diff changeset
  4116
    goto beach;
hgs
parents:
diff changeset
  4117
  }
hgs
parents:
diff changeset
  4118
eos_reverse_segment:
hgs
parents:
diff changeset
  4119
  {
hgs
parents:
diff changeset
  4120
    GST_DEBUG_OBJECT (avi, "full segment pushed, setting EOS");
hgs
parents:
diff changeset
  4121
    res = GST_FLOW_UNEXPECTED;
hgs
parents:
diff changeset
  4122
    goto beach;
hgs
parents:
diff changeset
  4123
  }
hgs
parents:
diff changeset
  4124
pull_failed:
hgs
parents:
diff changeset
  4125
  {
hgs
parents:
diff changeset
  4126
    GST_DEBUG_OBJECT (avi,
hgs
parents:
diff changeset
  4127
        "pull range failed: pos=%" G_GUINT64_FORMAT " size=%d",
hgs
parents:
diff changeset
  4128
        entry->offset + avi->index_offset, entry->size);
hgs
parents:
diff changeset
  4129
    goto beach;
hgs
parents:
diff changeset
  4130
  }
hgs
parents:
diff changeset
  4131
short_buffer:
hgs
parents:
diff changeset
  4132
  {
hgs
parents:
diff changeset
  4133
    GST_WARNING_OBJECT (avi, "Short read at offset %" G_GUINT64_FORMAT
hgs
parents:
diff changeset
  4134
        ", only got %d/%d bytes (truncated file?)", entry->offset +
hgs
parents:
diff changeset
  4135
        avi->index_offset, GST_BUFFER_SIZE (buf), entry->size);
hgs
parents:
diff changeset
  4136
    gst_buffer_unref (buf);
hgs
parents:
diff changeset
  4137
    res = GST_FLOW_UNEXPECTED;
hgs
parents:
diff changeset
  4138
    goto beach;
hgs
parents:
diff changeset
  4139
  }
hgs
parents:
diff changeset
  4140
}
hgs
parents:
diff changeset
  4141
hgs
parents:
diff changeset
  4142
/*
hgs
parents:
diff changeset
  4143
 * Read data. If we have an index it delegates to
hgs
parents:
diff changeset
  4144
 * gst_avi_demux_process_next_entry().
hgs
parents:
diff changeset
  4145
 */
hgs
parents:
diff changeset
  4146
static GstFlowReturn
hgs
parents:
diff changeset
  4147
gst_avi_demux_stream_data (GstAviDemux * avi)
hgs
parents:
diff changeset
  4148
{
hgs
parents:
diff changeset
  4149
  guint32 tag = 0;
hgs
parents:
diff changeset
  4150
  guint32 size = 0;
hgs
parents:
diff changeset
  4151
  gint stream_nr = 0;
hgs
parents:
diff changeset
  4152
  GstFlowReturn res = GST_FLOW_OK;
hgs
parents:
diff changeset
  4153
  GstFormat format = GST_FORMAT_TIME;
hgs
parents:
diff changeset
  4154
hgs
parents:
diff changeset
  4155
  /* if we have a avi->index_entries[], we don't want to read
hgs
parents:
diff changeset
  4156
   * the stream linearly, but seek to the next ts/index_entry. */
hgs
parents:
diff changeset
  4157
  if (G_LIKELY (avi->index_entries != NULL))
hgs
parents:
diff changeset
  4158
    return gst_avi_demux_process_next_entry (avi);
hgs
parents:
diff changeset
  4159
hgs
parents:
diff changeset
  4160
  if (G_UNLIKELY (avi->have_eos)) {
hgs
parents:
diff changeset
  4161
    /* Clean adapter, we're done */
hgs
parents:
diff changeset
  4162
    gst_adapter_clear (avi->adapter);
hgs
parents:
diff changeset
  4163
    return res;
hgs
parents:
diff changeset
  4164
  }
hgs
parents:
diff changeset
  4165
hgs
parents:
diff changeset
  4166
  /*
hgs
parents:
diff changeset
  4167
     if (!gst_avi_demux_sync (avi, &tag, FALSE))
hgs
parents:
diff changeset
  4168
     return FALSE;
hgs
parents:
diff changeset
  4169
   */
hgs
parents:
diff changeset
  4170
hgs
parents:
diff changeset
  4171
  /* Iterate until need more data, so adapter won't grow too much */
hgs
parents:
diff changeset
  4172
  while (1) {
hgs
parents:
diff changeset
  4173
    if (G_UNLIKELY (!gst_avi_demux_peek_chunk_info (avi, &tag, &size))) {
hgs
parents:
diff changeset
  4174
      return GST_FLOW_OK;
hgs
parents:
diff changeset
  4175
    }
hgs
parents:
diff changeset
  4176
hgs
parents:
diff changeset
  4177
    GST_DEBUG ("Trying chunk (%" GST_FOURCC_FORMAT "), size %d",
hgs
parents:
diff changeset
  4178
        GST_FOURCC_ARGS (tag), size);
hgs
parents:
diff changeset
  4179
hgs
parents:
diff changeset
  4180
    if (G_LIKELY ((tag & 0xff) >= '0' && (tag & 0xff) <= '9' &&
hgs
parents:
diff changeset
  4181
            ((tag >> 8) & 0xff) >= '0' && ((tag >> 8) & 0xff) <= '9')) {
hgs
parents:
diff changeset
  4182
      GST_LOG ("Chunk ok");
hgs
parents:
diff changeset
  4183
    } else if ((tag & 0xffff) == (('x' << 8) | 'i')) {
hgs
parents:
diff changeset
  4184
      GST_DEBUG ("Found sub-index tag");
hgs
parents:
diff changeset
  4185
      if (gst_avi_demux_peek_chunk (avi, &tag, &size)) {
hgs
parents:
diff changeset
  4186
        if ((size > 0) && (size != -1)) {
hgs
parents:
diff changeset
  4187
          GST_DEBUG ("  skipping %d bytes for now", size);
hgs
parents:
diff changeset
  4188
          gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
hgs
parents:
diff changeset
  4189
        }
hgs
parents:
diff changeset
  4190
      }
hgs
parents:
diff changeset
  4191
      return GST_FLOW_OK;
hgs
parents:
diff changeset
  4192
    } else if (tag == GST_RIFF_TAG_JUNK) {
hgs
parents:
diff changeset
  4193
      GST_DEBUG ("JUNK chunk, skipping");
hgs
parents:
diff changeset
  4194
    } else if (tag == GST_RIFF_TAG_idx1) {
hgs
parents:
diff changeset
  4195
      GST_DEBUG ("Found index tag, stream done");
hgs
parents:
diff changeset
  4196
      avi->have_eos = TRUE;
hgs
parents:
diff changeset
  4197
      return GST_FLOW_UNEXPECTED;
hgs
parents:
diff changeset
  4198
    } else if (tag == GST_RIFF_TAG_LIST) {
hgs
parents:
diff changeset
  4199
      /* movi chunks might be grouped in rec list */
hgs
parents:
diff changeset
  4200
      if (gst_adapter_available (avi->adapter) >= 12) {
hgs
parents:
diff changeset
  4201
        GST_DEBUG ("Found LIST tag, skipping LIST header");
hgs
parents:
diff changeset
  4202
        gst_adapter_flush (avi->adapter, 12);
hgs
parents:
diff changeset
  4203
        continue;
hgs
parents:
diff changeset
  4204
      }
hgs
parents:
diff changeset
  4205
      return GST_FLOW_OK;
hgs
parents:
diff changeset
  4206
    } else if (tag == GST_RIFF_TAG_JUNK) {
hgs
parents:
diff changeset
  4207
      /* rec list might contain JUNK chunks */
hgs
parents:
diff changeset
  4208
      GST_DEBUG ("Found JUNK tag");
hgs
parents:
diff changeset
  4209
      if (gst_avi_demux_peek_chunk (avi, &tag, &size)) {
hgs
parents:
diff changeset
  4210
        if ((size > 0) && (size != -1)) {
hgs
parents:
diff changeset
  4211
          GST_DEBUG ("  skipping %d bytes for now", size);
hgs
parents:
diff changeset
  4212
          gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
hgs
parents:
diff changeset
  4213
          continue;
hgs
parents:
diff changeset
  4214
        }
hgs
parents:
diff changeset
  4215
      }
hgs
parents:
diff changeset
  4216
      return GST_FLOW_OK;
hgs
parents:
diff changeset
  4217
    } else {
hgs
parents:
diff changeset
  4218
      GST_DEBUG ("No more stream chunks, send EOS");
hgs
parents:
diff changeset
  4219
      avi->have_eos = TRUE;
hgs
parents:
diff changeset
  4220
      return GST_FLOW_UNEXPECTED;
hgs
parents:
diff changeset
  4221
    }
hgs
parents:
diff changeset
  4222
hgs
parents:
diff changeset
  4223
    if (G_UNLIKELY (!gst_avi_demux_peek_chunk (avi, &tag, &size))) {
hgs
parents:
diff changeset
  4224
      if ((size == 0) || (size == -1))
hgs
parents:
diff changeset
  4225
        gst_adapter_flush (avi->adapter, 8);
hgs
parents:
diff changeset
  4226
      return GST_FLOW_OK;
hgs
parents:
diff changeset
  4227
    }
hgs
parents:
diff changeset
  4228
    GST_DEBUG ("chunk ID %" GST_FOURCC_FORMAT ", size %u",
hgs
parents:
diff changeset
  4229
        GST_FOURCC_ARGS (tag), size);
hgs
parents:
diff changeset
  4230
hgs
parents:
diff changeset
  4231
    stream_nr = CHUNKID_TO_STREAMNR (tag);
hgs
parents:
diff changeset
  4232
hgs
parents:
diff changeset
  4233
    if (G_UNLIKELY (stream_nr < 0 || stream_nr >= avi->num_streams)) {
hgs
parents:
diff changeset
  4234
      /* recoverable */
hgs
parents:
diff changeset
  4235
      GST_WARNING ("Invalid stream ID %d (%" GST_FOURCC_FORMAT ")",
hgs
parents:
diff changeset
  4236
          stream_nr, GST_FOURCC_ARGS (tag));
hgs
parents:
diff changeset
  4237
      avi->offset += 8 + ((size + 1) & ~1);
hgs
parents:
diff changeset
  4238
      gst_adapter_flush (avi->adapter, 8 + ((size + 1) & ~1));
hgs
parents:
diff changeset
  4239
    } else {
hgs
parents:
diff changeset
  4240
      avi_stream_context *stream;
hgs
parents:
diff changeset
  4241
      GstClockTime next_ts = 0;
hgs
parents:
diff changeset
  4242
      GstBuffer *buf;
hgs
parents:
diff changeset
  4243
hgs
parents:
diff changeset
  4244
      gst_adapter_flush (avi->adapter, 8);
hgs
parents:
diff changeset
  4245
hgs
parents:
diff changeset
  4246
      /* get buffer */
hgs
parents:
diff changeset
  4247
      buf = gst_adapter_take_buffer (avi->adapter, ((size + 1) & ~1));
hgs
parents:
diff changeset
  4248
      /* patch the size */
hgs
parents:
diff changeset
  4249
      GST_BUFFER_SIZE (buf) = size;
hgs
parents:
diff changeset
  4250
      avi->offset += 8 + ((size + 1) & ~1);
hgs
parents:
diff changeset
  4251
hgs
parents:
diff changeset
  4252
      stream = &avi->stream[stream_nr];
hgs
parents:
diff changeset
  4253
hgs
parents:
diff changeset
  4254
      /* set delay (if any)
hgs
parents:
diff changeset
  4255
         if (stream->strh->init_frames == stream->current_frame &&
hgs
parents:
diff changeset
  4256
         stream->delay == 0)
hgs
parents:
diff changeset
  4257
         stream->delay = next_ts;
hgs
parents:
diff changeset
  4258
       */
hgs
parents:
diff changeset
  4259
hgs
parents:
diff changeset
  4260
      stream->current_frame++;
hgs
parents:
diff changeset
  4261
      stream->current_byte += size;
hgs
parents:
diff changeset
  4262
hgs
parents:
diff changeset
  4263
      /* parsing of corresponding header may have failed */
hgs
parents:
diff changeset
  4264
      if (G_UNLIKELY (!stream->pad)) {
hgs
parents:
diff changeset
  4265
        GST_WARNING_OBJECT (avi, "no pad for stream ID %" GST_FOURCC_FORMAT,
hgs
parents:
diff changeset
  4266
            GST_FOURCC_ARGS (tag));
hgs
parents:
diff changeset
  4267
        gst_buffer_unref (buf);
hgs
parents:
diff changeset
  4268
      } else {
hgs
parents:
diff changeset
  4269
        GstClockTime dur_ts = 0;
hgs
parents:
diff changeset
  4270
hgs
parents:
diff changeset
  4271
        /* get time of this buffer */
hgs
parents:
diff changeset
  4272
        gst_pad_query_position (stream->pad, &format, (gint64 *) & next_ts);
hgs
parents:
diff changeset
  4273
        if (G_UNLIKELY (format != GST_FORMAT_TIME))
hgs
parents:
diff changeset
  4274
          goto wrong_format;
hgs
parents:
diff changeset
  4275
hgs
parents:
diff changeset
  4276
        /* invert the picture if needed */
hgs
parents:
diff changeset
  4277
        buf = gst_avi_demux_invert (stream, buf);
hgs
parents:
diff changeset
  4278
hgs
parents:
diff changeset
  4279
        gst_pad_query_position (stream->pad, &format, (gint64 *) & dur_ts);
hgs
parents:
diff changeset
  4280
        if (G_UNLIKELY (format != GST_FORMAT_TIME))
hgs
parents:
diff changeset
  4281
          goto wrong_format;
hgs
parents:
diff changeset
  4282
hgs
parents:
diff changeset
  4283
        GST_BUFFER_TIMESTAMP (buf) = next_ts;
hgs
parents:
diff changeset
  4284
        GST_BUFFER_DURATION (buf) = dur_ts - next_ts;
hgs
parents:
diff changeset
  4285
        if (stream->strh->type == GST_RIFF_FCC_vids)
hgs
parents:
diff changeset
  4286
          GST_BUFFER_OFFSET (buf) = stream->current_frame - 1;
hgs
parents:
diff changeset
  4287
        else
hgs
parents:
diff changeset
  4288
          GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
hgs
parents:
diff changeset
  4289
hgs
parents:
diff changeset
  4290
        gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad));
hgs
parents:
diff changeset
  4291
        GST_DEBUG_OBJECT (avi,
hgs
parents:
diff changeset
  4292
            "Pushing buffer with time=%" GST_TIME_FORMAT
hgs
parents:
diff changeset
  4293
            ", offset %" G_GUINT64_FORMAT " and size %d over pad %s",
hgs
parents:
diff changeset
  4294
            GST_TIME_ARGS (next_ts), GST_BUFFER_OFFSET (buf), size,
hgs
parents:
diff changeset
  4295
            GST_PAD_NAME (stream->pad));
hgs
parents:
diff changeset
  4296
hgs
parents:
diff changeset
  4297
        /* update current position in the segment */
hgs
parents:
diff changeset
  4298
        gst_segment_set_last_stop (&avi->segment, GST_FORMAT_TIME, next_ts);
hgs
parents:
diff changeset
  4299
hgs
parents:
diff changeset
  4300
        /* mark discont when pending */
hgs
parents:
diff changeset
  4301
        if (G_UNLIKELY (stream->discont)) {
hgs
parents:
diff changeset
  4302
          GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
hgs
parents:
diff changeset
  4303
          stream->discont = FALSE;
hgs
parents:
diff changeset
  4304
        }
hgs
parents:
diff changeset
  4305
        res = gst_pad_push (stream->pad, buf);
hgs
parents:
diff changeset
  4306
hgs
parents:
diff changeset
  4307
        /* combine flows */
hgs
parents:
diff changeset
  4308
        res = gst_avi_demux_combine_flows (avi, stream, res);
hgs
parents:
diff changeset
  4309
        if (G_UNLIKELY (res != GST_FLOW_OK)) {
hgs
parents:
diff changeset
  4310
          GST_DEBUG ("Push failed; %s", gst_flow_get_name (res));
hgs
parents:
diff changeset
  4311
          return res;
hgs
parents:
diff changeset
  4312
        }
hgs
parents:
diff changeset
  4313
      }
hgs
parents:
diff changeset
  4314
    }
hgs
parents:
diff changeset
  4315
  }
hgs
parents:
diff changeset
  4316
hgs
parents:
diff changeset
  4317
done:
hgs
parents:
diff changeset
  4318
  return res;
hgs
parents:
diff changeset
  4319
hgs
parents:
diff changeset
  4320
  /* ERRORS */
hgs
parents:
diff changeset
  4321
wrong_format:
hgs
parents:
diff changeset
  4322
  {
hgs
parents:
diff changeset
  4323
    GST_DEBUG_OBJECT (avi, "format %s != GST_FORMAT_TIME",
hgs
parents:
diff changeset
  4324
        gst_format_get_name (format));
hgs
parents:
diff changeset
  4325
    res = GST_FLOW_ERROR;
hgs
parents:
diff changeset
  4326
    goto done;
hgs
parents:
diff changeset
  4327
  }
hgs
parents:
diff changeset
  4328
}
hgs
parents:
diff changeset
  4329
hgs
parents:
diff changeset
  4330
/*
hgs
parents:
diff changeset
  4331
 * Send pending tags.
hgs
parents:
diff changeset
  4332
 */
hgs
parents:
diff changeset
  4333
static void
hgs
parents:
diff changeset
  4334
push_tag_lists (GstAviDemux * avi)
hgs
parents:
diff changeset
  4335
{
hgs
parents:
diff changeset
  4336
  guint i;
hgs
parents:
diff changeset
  4337
hgs
parents:
diff changeset
  4338
  if (!avi->got_tags)
hgs
parents:
diff changeset
  4339
    return;
hgs
parents:
diff changeset
  4340
hgs
parents:
diff changeset
  4341
  GST_DEBUG_OBJECT (avi, "Pushing pending tag lists");
hgs
parents:
diff changeset
  4342
hgs
parents:
diff changeset
  4343
  for (i = 0; i < avi->num_streams; i++)
hgs
parents:
diff changeset
  4344
    if (avi->stream[i].pad && avi->stream[i].taglist) {
hgs
parents:
diff changeset
  4345
      GST_DEBUG_OBJECT (avi->stream[i].pad, "Tags: %" GST_PTR_FORMAT,
hgs
parents:
diff changeset
  4346
          avi->stream[i].taglist);
hgs
parents:
diff changeset
  4347
      gst_element_found_tags_for_pad (GST_ELEMENT (avi), avi->stream[i].pad,
hgs
parents:
diff changeset
  4348
          avi->stream[i].taglist);
hgs
parents:
diff changeset
  4349
      avi->stream[i].taglist = NULL;
hgs
parents:
diff changeset
  4350
    }
hgs
parents:
diff changeset
  4351
hgs
parents:
diff changeset
  4352
  if (avi->globaltags == NULL)
hgs
parents:
diff changeset
  4353
    avi->globaltags = gst_tag_list_new ();
hgs
parents:
diff changeset
  4354
hgs
parents:
diff changeset
  4355
  gst_tag_list_add (avi->globaltags, GST_TAG_MERGE_REPLACE,
hgs
parents:
diff changeset
  4356
      GST_TAG_CONTAINER_FORMAT, "AVI", NULL);
hgs
parents:
diff changeset
  4357
hgs
parents:
diff changeset
  4358
  GST_DEBUG_OBJECT (avi, "Global tags: %" GST_PTR_FORMAT, avi->globaltags);
hgs
parents:
diff changeset
  4359
  gst_element_found_tags (GST_ELEMENT (avi), avi->globaltags);
hgs
parents:
diff changeset
  4360
  avi->globaltags = NULL;
hgs
parents:
diff changeset
  4361
  avi->got_tags = FALSE;
hgs
parents:
diff changeset
  4362
}
hgs
parents:
diff changeset
  4363
hgs
parents:
diff changeset
  4364
static void
hgs
parents:
diff changeset
  4365
gst_avi_demux_loop (GstPad * pad)
hgs
parents:
diff changeset
  4366
{
hgs
parents:
diff changeset
  4367
  GstFlowReturn res;
hgs
parents:
diff changeset
  4368
  GstAviDemux *avi = GST_AVI_DEMUX (GST_PAD_PARENT (pad));
hgs
parents:
diff changeset
  4369
hgs
parents:
diff changeset
  4370
  switch (avi->state) {
hgs
parents:
diff changeset
  4371
    case GST_AVI_DEMUX_START:
hgs
parents:
diff changeset
  4372
      if (G_UNLIKELY ((res =
hgs
parents:
diff changeset
  4373
                  gst_avi_demux_stream_init_pull (avi)) != GST_FLOW_OK)) {
hgs
parents:
diff changeset
  4374
        GST_WARNING ("stream_init flow: %s", gst_flow_get_name (res));
hgs
parents:
diff changeset
  4375
        goto pause;
hgs
parents:
diff changeset
  4376
      }
hgs
parents:
diff changeset
  4377
      avi->state = GST_AVI_DEMUX_HEADER;
hgs
parents:
diff changeset
  4378
      /* fall-through */
hgs
parents:
diff changeset
  4379
    case GST_AVI_DEMUX_HEADER:
hgs
parents:
diff changeset
  4380
      if (G_UNLIKELY ((res =
hgs
parents:
diff changeset
  4381
                  gst_avi_demux_stream_header_pull (avi)) != GST_FLOW_OK)) {
hgs
parents:
diff changeset
  4382
        GST_WARNING ("stream_header flow: %s", gst_flow_get_name (res));
hgs
parents:
diff changeset
  4383
        goto pause;
hgs
parents:
diff changeset
  4384
      }
hgs
parents:
diff changeset
  4385
      avi->state = GST_AVI_DEMUX_MOVI;
hgs
parents:
diff changeset
  4386
      break;
hgs
parents:
diff changeset
  4387
    case GST_AVI_DEMUX_MOVI:
hgs
parents:
diff changeset
  4388
      if (G_UNLIKELY (avi->seek_event)) {
hgs
parents:
diff changeset
  4389
        gst_avi_demux_push_event (avi, avi->seek_event);
hgs
parents:
diff changeset
  4390
        avi->seek_event = NULL;
hgs
parents:
diff changeset
  4391
      }
hgs
parents:
diff changeset
  4392
      if (G_UNLIKELY (avi->got_tags)) {
hgs
parents:
diff changeset
  4393
        push_tag_lists (avi);
hgs
parents:
diff changeset
  4394
      }
hgs
parents:
diff changeset
  4395
      /* process each index entry in turn */
hgs
parents:
diff changeset
  4396
      res = gst_avi_demux_stream_data (avi);
hgs
parents:
diff changeset
  4397
hgs
parents:
diff changeset
  4398
      /* pause when error */
hgs
parents:
diff changeset
  4399
      if (G_UNLIKELY (res != GST_FLOW_OK)) {
hgs
parents:
diff changeset
  4400
        GST_INFO ("stream_movi flow: %s", gst_flow_get_name (res));
hgs
parents:
diff changeset
  4401
        goto pause;
hgs
parents:
diff changeset
  4402
      }
hgs
parents:
diff changeset
  4403
      break;
hgs
parents:
diff changeset
  4404
    default:
hgs
parents:
diff changeset
  4405
      GST_ERROR_OBJECT (avi, "unknown state %d", avi->state);
hgs
parents:
diff changeset
  4406
      res = GST_FLOW_ERROR;
hgs
parents:
diff changeset
  4407
      goto pause;
hgs
parents:
diff changeset
  4408
  }
hgs
parents:
diff changeset
  4409
hgs
parents:
diff changeset
  4410
  GST_LOG_OBJECT (avi, "state: %d res:%s", avi->state, gst_flow_get_name (res));
hgs
parents:
diff changeset
  4411
hgs
parents:
diff changeset
  4412
  return;
hgs
parents:
diff changeset
  4413
hgs
parents:
diff changeset
  4414
  /* ERRORS */
hgs
parents:
diff changeset
  4415
pause:
hgs
parents:
diff changeset
  4416
  GST_LOG_OBJECT (avi, "pausing task, reason %s", gst_flow_get_name (res));
hgs
parents:
diff changeset
  4417
  avi->segment_running = FALSE;
hgs
parents:
diff changeset
  4418
  gst_pad_pause_task (avi->sinkpad);
hgs
parents:
diff changeset
  4419
hgs
parents:
diff changeset
  4420
  if (GST_FLOW_IS_FATAL (res) || (res == GST_FLOW_NOT_LINKED)) {
hgs
parents:
diff changeset
  4421
    gboolean push_eos = TRUE;
hgs
parents:
diff changeset
  4422
hgs
parents:
diff changeset
  4423
    if (res == GST_FLOW_UNEXPECTED) {
hgs
parents:
diff changeset
  4424
      /* handle end-of-stream/segment */
hgs
parents:
diff changeset
  4425
      if (avi->segment.flags & GST_SEEK_FLAG_SEGMENT) {
hgs
parents:
diff changeset
  4426
        gint64 stop;
hgs
parents:
diff changeset
  4427
hgs
parents:
diff changeset
  4428
        if ((stop = avi->segment.stop) == -1)
hgs
parents:
diff changeset
  4429
          stop = avi->segment.duration;
hgs
parents:
diff changeset
  4430
hgs
parents:
diff changeset
  4431
        GST_INFO_OBJECT (avi, "sending segment_done");
hgs
parents:
diff changeset
  4432
hgs
parents:
diff changeset
  4433
        gst_element_post_message
hgs
parents:
diff changeset
  4434
            (GST_ELEMENT (avi),
hgs
parents:
diff changeset
  4435
            gst_message_new_segment_done (GST_OBJECT (avi), GST_FORMAT_TIME,
hgs
parents:
diff changeset
  4436
                stop));
hgs
parents:
diff changeset
  4437
        push_eos = FALSE;
hgs
parents:
diff changeset
  4438
      }
hgs
parents:
diff changeset
  4439
    } else {
hgs
parents:
diff changeset
  4440
      /* for fatal errors we post an error message */
hgs
parents:
diff changeset
  4441
      GST_ELEMENT_ERROR (avi, STREAM, FAILED,
hgs
parents:
diff changeset
  4442
          (_("Internal data stream error.")),
hgs
parents:
diff changeset
  4443
          ("streaming stopped, reason %s", gst_flow_get_name (res)));
hgs
parents:
diff changeset
  4444
    }
hgs
parents:
diff changeset
  4445
    if (push_eos) {
hgs
parents:
diff changeset
  4446
      GST_INFO_OBJECT (avi, "sending eos");
hgs
parents:
diff changeset
  4447
      if (!gst_avi_demux_push_event (avi, gst_event_new_eos ()) &&
hgs
parents:
diff changeset
  4448
          (res == GST_FLOW_UNEXPECTED)) {
hgs
parents:
diff changeset
  4449
        GST_ELEMENT_ERROR (avi, STREAM, DEMUX,
hgs
parents:
diff changeset
  4450
            (NULL), ("got eos but no streams (yet)"));
hgs
parents:
diff changeset
  4451
      }
hgs
parents:
diff changeset
  4452
    }
hgs
parents:
diff changeset
  4453
  }
hgs
parents:
diff changeset
  4454
}
hgs
parents:
diff changeset
  4455
hgs
parents:
diff changeset
  4456
hgs
parents:
diff changeset
  4457
static GstFlowReturn
hgs
parents:
diff changeset
  4458
gst_avi_demux_chain (GstPad * pad, GstBuffer * buf)
hgs
parents:
diff changeset
  4459
{
hgs
parents:
diff changeset
  4460
  GstFlowReturn res;
hgs
parents:
diff changeset
  4461
  GstAviDemux *avi = GST_AVI_DEMUX (GST_PAD_PARENT (pad));
hgs
parents:
diff changeset
  4462
hgs
parents:
diff changeset
  4463
  GST_DEBUG ("Store %d bytes in adapter", GST_BUFFER_SIZE (buf));
hgs
parents:
diff changeset
  4464
  gst_adapter_push (avi->adapter, buf);
hgs
parents:
diff changeset
  4465
hgs
parents:
diff changeset
  4466
  switch (avi->state) {
hgs
parents:
diff changeset
  4467
    case GST_AVI_DEMUX_START:
hgs
parents:
diff changeset
  4468
      if ((res = gst_avi_demux_stream_init_push (avi)) != GST_FLOW_OK) {
hgs
parents:
diff changeset
  4469
        GST_WARNING ("stream_init flow: %s", gst_flow_get_name (res));
hgs
parents:
diff changeset
  4470
        break;
hgs
parents:
diff changeset
  4471
      }
hgs
parents:
diff changeset
  4472
      break;
hgs
parents:
diff changeset
  4473
    case GST_AVI_DEMUX_HEADER:
hgs
parents:
diff changeset
  4474
      if ((res = gst_avi_demux_stream_header_push (avi)) != GST_FLOW_OK) {
hgs
parents:
diff changeset
  4475
        GST_WARNING ("stream_header flow: %s", gst_flow_get_name (res));
hgs
parents:
diff changeset
  4476
        break;
hgs
parents:
diff changeset
  4477
      }
hgs
parents:
diff changeset
  4478
      break;
hgs
parents:
diff changeset
  4479
    case GST_AVI_DEMUX_MOVI:
hgs
parents:
diff changeset
  4480
      if (G_UNLIKELY (avi->seek_event)) {
hgs
parents:
diff changeset
  4481
        gst_avi_demux_push_event (avi, avi->seek_event);
hgs
parents:
diff changeset
  4482
        avi->seek_event = NULL;
hgs
parents:
diff changeset
  4483
      }
hgs
parents:
diff changeset
  4484
      if (G_UNLIKELY (avi->got_tags)) {
hgs
parents:
diff changeset
  4485
        push_tag_lists (avi);
hgs
parents:
diff changeset
  4486
      }
hgs
parents:
diff changeset
  4487
      res = gst_avi_demux_stream_data (avi);
hgs
parents:
diff changeset
  4488
      break;
hgs
parents:
diff changeset
  4489
    default:
hgs
parents:
diff changeset
  4490
      GST_ELEMENT_ERROR (avi, STREAM, FAILED, (NULL),
hgs
parents:
diff changeset
  4491
          ("Illegal internal state"));
hgs
parents:
diff changeset
  4492
      res = GST_FLOW_ERROR;
hgs
parents:
diff changeset
  4493
      break;
hgs
parents:
diff changeset
  4494
  }
hgs
parents:
diff changeset
  4495
hgs
parents:
diff changeset
  4496
  GST_DEBUG_OBJECT (avi, "state: %d res:%s", avi->state,
hgs
parents:
diff changeset
  4497
      gst_flow_get_name (res));
hgs
parents:
diff changeset
  4498
hgs
parents:
diff changeset
  4499
  return res;
hgs
parents:
diff changeset
  4500
}
hgs
parents:
diff changeset
  4501
hgs
parents:
diff changeset
  4502
static gboolean
hgs
parents:
diff changeset
  4503
gst_avi_demux_sink_activate (GstPad * sinkpad)
hgs
parents:
diff changeset
  4504
{
hgs
parents:
diff changeset
  4505
  if (gst_pad_check_pull_range (sinkpad)) {
hgs
parents:
diff changeset
  4506
    GST_DEBUG ("going to pull mode");
hgs
parents:
diff changeset
  4507
    return gst_pad_activate_pull (sinkpad, TRUE);
hgs
parents:
diff changeset
  4508
  } else {
hgs
parents:
diff changeset
  4509
    GST_DEBUG ("going to push (streaming) mode");
hgs
parents:
diff changeset
  4510
    return gst_pad_activate_push (sinkpad, TRUE);
hgs
parents:
diff changeset
  4511
  }
hgs
parents:
diff changeset
  4512
}
hgs
parents:
diff changeset
  4513
hgs
parents:
diff changeset
  4514
static gboolean
hgs
parents:
diff changeset
  4515
gst_avi_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
hgs
parents:
diff changeset
  4516
{
hgs
parents:
diff changeset
  4517
  GstAviDemux *avi = GST_AVI_DEMUX (GST_OBJECT_PARENT (sinkpad));
hgs
parents:
diff changeset
  4518
hgs
parents:
diff changeset
  4519
  if (active) {
hgs
parents:
diff changeset
  4520
    avi->segment_running = TRUE;
hgs
parents:
diff changeset
  4521
    avi->streaming = FALSE;
hgs
parents:
diff changeset
  4522
    return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_avi_demux_loop,
hgs
parents:
diff changeset
  4523
        sinkpad);
hgs
parents:
diff changeset
  4524
  } else {
hgs
parents:
diff changeset
  4525
    avi->segment_running = FALSE;
hgs
parents:
diff changeset
  4526
    return gst_pad_stop_task (sinkpad);
hgs
parents:
diff changeset
  4527
  }
hgs
parents:
diff changeset
  4528
}
hgs
parents:
diff changeset
  4529
hgs
parents:
diff changeset
  4530
static gboolean
hgs
parents:
diff changeset
  4531
gst_avi_demux_activate_push (GstPad * pad, gboolean active)
hgs
parents:
diff changeset
  4532
{
hgs
parents:
diff changeset
  4533
  GstAviDemux *avi = GST_AVI_DEMUX (GST_OBJECT_PARENT (pad));
hgs
parents:
diff changeset
  4534
hgs
parents:
diff changeset
  4535
  if (active) {
hgs
parents:
diff changeset
  4536
    GST_DEBUG ("avi: activating push/chain function");
hgs
parents:
diff changeset
  4537
    avi->streaming = TRUE;
hgs
parents:
diff changeset
  4538
  } else {
hgs
parents:
diff changeset
  4539
    GST_DEBUG ("avi: deactivating push/chain function");
hgs
parents:
diff changeset
  4540
  }
hgs
parents:
diff changeset
  4541
hgs
parents:
diff changeset
  4542
  return TRUE;
hgs
parents:
diff changeset
  4543
}
hgs
parents:
diff changeset
  4544
hgs
parents:
diff changeset
  4545
static GstStateChangeReturn
hgs
parents:
diff changeset
  4546
gst_avi_demux_change_state (GstElement * element, GstStateChange transition)
hgs
parents:
diff changeset
  4547
{
hgs
parents:
diff changeset
  4548
  GstStateChangeReturn ret;
hgs
parents:
diff changeset
  4549
  GstAviDemux *avi = GST_AVI_DEMUX (element);
hgs
parents:
diff changeset
  4550
hgs
parents:
diff changeset
  4551
  switch (transition) {
hgs
parents:
diff changeset
  4552
    case GST_STATE_CHANGE_READY_TO_PAUSED:
hgs
parents:
diff changeset
  4553
      avi->streaming = FALSE;
hgs
parents:
diff changeset
  4554
      gst_segment_init (&avi->segment, GST_FORMAT_TIME);
hgs
parents:
diff changeset
  4555
      break;
hgs
parents:
diff changeset
  4556
    default:
hgs
parents:
diff changeset
  4557
      break;
hgs
parents:
diff changeset
  4558
  }
hgs
parents:
diff changeset
  4559
hgs
parents:
diff changeset
  4560
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
hgs
parents:
diff changeset
  4561
  if (ret == GST_STATE_CHANGE_FAILURE)
hgs
parents:
diff changeset
  4562
    goto done;
hgs
parents:
diff changeset
  4563
hgs
parents:
diff changeset
  4564
  switch (transition) {
hgs
parents:
diff changeset
  4565
    case GST_STATE_CHANGE_PAUSED_TO_READY:
hgs
parents:
diff changeset
  4566
      gst_avi_demux_reset (avi);
hgs
parents:
diff changeset
  4567
      break;
hgs
parents:
diff changeset
  4568
    default:
hgs
parents:
diff changeset
  4569
      break;
hgs
parents:
diff changeset
  4570
  }
hgs
parents:
diff changeset
  4571
hgs
parents:
diff changeset
  4572
done:
hgs
parents:
diff changeset
  4573
  return ret;
hgs
parents:
diff changeset
  4574
}