qtdemux.c 53.6 KB
Newer Older
Artyom Baginski's avatar
Artyom Baginski committed
1 2
/* GStreamer
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3
 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
Artyom Baginski's avatar
Artyom Baginski committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

21 22 23
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
24
#include "qtdemux.h"
25

Artyom Baginski's avatar
Artyom Baginski committed
26
#include <string.h>
27 28
#include <zlib.h>

29 30
GST_DEBUG_CATEGORY_EXTERN (qtdemux_debug);
#define GST_CAT_DEFAULT qtdemux_debug
31

32 33 34 35 36 37 38 39
#define QTDEMUX_GUINT32_GET(a) GUINT32_FROM_BE(*(guint32 *)(a))
#define QTDEMUX_GUINT16_GET(a) GUINT16_FROM_BE(*(guint16 *)(a))
#define QTDEMUX_GUINT8_GET(a) (*(guint8 *)(a))
#define QTDEMUX_FP32_GET(a) (GUINT32_FROM_BE(*(guint16 *)(a))/65536.0)
#define QTDEMUX_FP16_GET(a) (GUINT16_FROM_BE(*(guint16 *)(a))/256.0)
#define QTDEMUX_FOURCC_GET(a) GUINT32_FROM_LE(*(guint32 *)(a))

#define QTDEMUX_GUINT64_GET(a) ((((guint64)QTDEMUX_GUINT32_GET(a))<<32)|QTDEMUX_GUINT32_GET(((void *)a)+4))
Artyom Baginski's avatar
Artyom Baginski committed
40

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
typedef struct _QtNode QtNode;
typedef struct _QtNodeType QtNodeType;
typedef struct _QtDemuxSample QtDemuxSample;
//typedef struct _QtDemuxStream QtDemuxStream;

struct _QtNode {
  guint32 type;
  gpointer data;
  int len;
};

struct _QtNodeType {
  guint32 fourcc;
  char *name;
  int flags;
  void (*dump)(GstQTDemux *qtdemux, void *buffer, int depth);
};

struct _QtDemuxSample {
  int sample_index;
  int chunk;
  int size;
  guint32 offset;
  guint64 timestamp;
65
  guint64 duration;
66 67 68 69 70 71 72 73 74 75 76
};

struct _QtDemuxStream {
  guint32 subtype;
  GstCaps *caps;
  GstPad *pad;
  int n_samples;
  QtDemuxSample *samples;
  int timescale;

  int sample_index;
77 78 79

  int width;
  int height;
80
  float fps;
81
  
82 83
  double rate;
  int n_channels;
84 85
  guint bytes_per_frame;
  guint samples_per_packet;
86 87 88 89 90
};

enum QtDemuxState {
  QTDEMUX_STATE_NULL,
  QTDEMUX_STATE_HEADER,
91
  QTDEMUX_STATE_HEADER_SEEKING,
92 93 94 95 96 97
  QTDEMUX_STATE_SEEKING,
  QTDEMUX_STATE_MOVIE,
  QTDEMUX_STATE_SEEKING_EOS,
  QTDEMUX_STATE_EOS,
};

98 99 100
static GNode *qtdemux_tree_get_child_by_type(GNode *node, guint32 fourcc);
static GNode *qtdemux_tree_get_sibling_by_type(GNode *node, guint32 fourcc);

Artyom Baginski's avatar
Artyom Baginski committed
101 102 103
static GstElementDetails 
gst_qtdemux_details = 
{
104 105 106
  "QuickTime Demuxer",
  "Codec/Demuxer",
  "Demultiplex a QuickTime file into audio and video streams",
107
  "David Schleef <ds@schleef.org>"
Artyom Baginski's avatar
Artyom Baginski committed
108 109 110 111 112 113 114 115 116 117
};

enum {
  LAST_SIGNAL
};

enum {
  ARG_0
};

David Schleef's avatar
David Schleef committed
118 119
static GstStaticPadTemplate gst_qtdemux_sink_template =
GST_STATIC_PAD_TEMPLATE (
Artyom Baginski's avatar
Artyom Baginski committed
120 121
  "sink",
  GST_PAD_SINK,
David Schleef's avatar
David Schleef committed
122
  GST_PAD_SOMETIMES,
123
  GST_STATIC_CAPS ("video/quicktime")
David Schleef's avatar
David Schleef committed
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
);

static GstStaticPadTemplate gst_qtdemux_videosrc_template =
GST_STATIC_PAD_TEMPLATE (
  "audio_%02d",
  GST_PAD_SRC,
  GST_PAD_SOMETIMES,
  GST_STATIC_CAPS_ANY
);

static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
GST_STATIC_PAD_TEMPLATE (
  "video_%02d",
  GST_PAD_SRC,
  GST_PAD_SOMETIMES,
  GST_STATIC_CAPS_ANY
);
Artyom Baginski's avatar
Artyom Baginski committed
141

142
static GstElementClass *parent_class = NULL;
Artyom Baginski's avatar
Artyom Baginski committed
143 144

static void gst_qtdemux_class_init (GstQTDemuxClass *klass);
145
static void gst_qtdemux_base_init (GstQTDemuxClass *klass);
Artyom Baginski's avatar
Artyom Baginski committed
146
static void gst_qtdemux_init (GstQTDemux *quicktime_demux);
147 148 149 150 151 152 153 154 155
static GstElementStateReturn gst_qtdemux_change_state(GstElement *element);
static void gst_qtdemux_loop_header (GstElement *element);
static gboolean gst_qtdemux_handle_sink_event (GstQTDemux *qtdemux);

static void qtdemux_parse_moov(GstQTDemux *qtdemux, void *buffer, int length);
static void qtdemux_parse(GstQTDemux *qtdemux, GNode *node, void *buffer, int length);
static QtNodeType *qtdemux_type_get(guint32 fourcc);
static void qtdemux_node_dump(GstQTDemux *qtdemux, GNode *node);
static void qtdemux_parse_tree(GstQTDemux *qtdemux);
156
static GstCaps *qtdemux_video_caps(GstQTDemux *qtdemux, guint32 fourcc, const guint8 *stsd_data);
157
static GstCaps *qtdemux_audio_caps(GstQTDemux *qtdemux, guint32 fourcc, const guint8 *data);
158 159

static GType gst_qtdemux_get_type (void) 
Artyom Baginski's avatar
Artyom Baginski committed
160 161 162 163 164
{
  static GType qtdemux_type = 0;

  if (!qtdemux_type) {
    static const GTypeInfo qtdemux_info = {
165 166
      sizeof(GstQTDemuxClass),
      (GBaseInitFunc)gst_qtdemux_base_init, NULL,
Artyom Baginski's avatar
Artyom Baginski committed
167 168 169 170 171 172 173 174 175
      (GClassInitFunc)gst_qtdemux_class_init,
      NULL, NULL, sizeof(GstQTDemux), 0,
      (GInstanceInitFunc)gst_qtdemux_init,
    };
    qtdemux_type = g_type_register_static (GST_TYPE_ELEMENT, "GstQTDemux", &qtdemux_info, 0);
  }
  return qtdemux_type;
}

176 177 178 179 180
static void gst_qtdemux_base_init (GstQTDemuxClass *klass)
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);

  gst_element_class_add_pad_template (element_class,
David Schleef's avatar
David Schleef committed
181 182 183 184 185
      gst_static_pad_template_get (&gst_qtdemux_sink_template));
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
186
  gst_element_class_set_details (element_class, &gst_qtdemux_details);
David Schleef's avatar
David Schleef committed
187

188 189
}

190
static void gst_qtdemux_class_init (GstQTDemuxClass *klass) 
Artyom Baginski's avatar
Artyom Baginski committed
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

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

  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);

  gstelement_class->change_state = gst_qtdemux_change_state;
}

static void 
gst_qtdemux_init (GstQTDemux *qtdemux) 
{
David Schleef's avatar
David Schleef committed
206 207 208 209
  qtdemux->sinkpad = gst_pad_new_from_template (
      gst_static_pad_template_get (&gst_qtdemux_sink_template), "sink");
  gst_element_set_loop_function (GST_ELEMENT (qtdemux),
      gst_qtdemux_loop_header);
Artyom Baginski's avatar
Artyom Baginski committed
210 211 212
  gst_element_add_pad (GST_ELEMENT (qtdemux), qtdemux->sinkpad);
}

213 214
GST_DEBUG_CATEGORY (qtdemux_debug);

Artyom Baginski's avatar
Artyom Baginski committed
215
static gboolean
216
plugin_init (GstPlugin *plugin)
Artyom Baginski's avatar
Artyom Baginski committed
217
{
218
  GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
219

220 221 222
  if (!gst_library_load ("gstbytestream"))
    return FALSE;

223 224 225
  if (!gst_library_load ("gstgetbits"))
    return FALSE;

226
  return gst_element_register (plugin, "qtdemux",
227
			       GST_RANK_PRIMARY, GST_TYPE_QTDEMUX);
Artyom Baginski's avatar
Artyom Baginski committed
228 229
}

230
GST_PLUGIN_DEFINE (
Artyom Baginski's avatar
Artyom Baginski committed
231 232 233
  GST_VERSION_MAJOR,
  GST_VERSION_MINOR,
  "qtdemux",
234 235 236 237 238 239 240
  "Quicktime stream demuxer",
  plugin_init,
  VERSION,
  "LGPL",
  GST_PACKAGE,
  GST_ORIGIN
)
Artyom Baginski's avatar
Artyom Baginski committed
241

242
static gboolean gst_qtdemux_handle_sink_event (GstQTDemux *qtdemux)
Artyom Baginski's avatar
Artyom Baginski committed
243 244
{
  guint32 remaining;
245
  GstEvent *event;
Artyom Baginski's avatar
Artyom Baginski committed
246 247
  GstEventType type;

248 249 250
  gst_bytestream_get_status(qtdemux->bs, &remaining, &event);

  type = event ? GST_EVENT_TYPE(event) : GST_EVENT_UNKNOWN;
251
  GST_DEBUG ("qtdemux: event %p %d", event, type);
Artyom Baginski's avatar
Artyom Baginski committed
252

253
  switch(type){
Artyom Baginski's avatar
Artyom Baginski committed
254
    case GST_EVENT_EOS:
255 256 257 258
      gst_bytestream_flush(qtdemux->bs, remaining);
      gst_pad_event_default(qtdemux->sinkpad, event);
      return FALSE;
    case GST_EVENT_FLUSH:
259
      //g_warning("flush event");
Artyom Baginski's avatar
Artyom Baginski committed
260 261
      break;
    case GST_EVENT_DISCONTINUOUS:
262
      GST_DEBUG ("discontinuous event\n");
263 264
      //gst_bytestream_flush_fast(qtdemux->bs, remaining);
      break;
Artyom Baginski's avatar
Artyom Baginski committed
265
    default:
266
      g_warning("unhandled event %d",type);
Artyom Baginski's avatar
Artyom Baginski committed
267 268
      break;
  }
269 270

  gst_event_unref(event);
Artyom Baginski's avatar
Artyom Baginski committed
271 272 273
  return TRUE;
}

274 275 276
static GstElementStateReturn gst_qtdemux_change_state(GstElement *element)
{
  GstQTDemux *qtdemux = GST_QTDEMUX(element);
Artyom Baginski's avatar
Artyom Baginski committed
277

278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
  switch(GST_STATE_TRANSITION(element)){
    case GST_STATE_NULL_TO_READY:
      break;
    case GST_STATE_READY_TO_PAUSED:
      qtdemux->bs = gst_bytestream_new(qtdemux->sinkpad);
      qtdemux->state = QTDEMUX_STATE_HEADER;
      /* FIXME */
      break;
    case GST_STATE_PAUSED_TO_PLAYING:
      break;
    case GST_STATE_PLAYING_TO_PAUSED:
      break;
    case GST_STATE_PAUSED_TO_READY:
      gst_bytestream_destroy(qtdemux->bs);
      break;
    case GST_STATE_READY_TO_NULL:
      break;
    default:
      break;
  }
Artyom Baginski's avatar
Artyom Baginski committed
298

299 300
  return GST_ELEMENT_CLASS(parent_class)->change_state(element);
}
Artyom Baginski's avatar
Artyom Baginski committed
301

302 303 304 305 306 307 308 309 310 311 312 313
static void gst_qtdemux_loop_header (GstElement *element)
{
  GstQTDemux *qtdemux = GST_QTDEMUX(element);
  guint8 *data;
  guint32 length;
  guint32 fourcc;
  GstBuffer *buf;
  int offset;
  int cur_offset;
  int size;
  int ret;

314 315 316 317
  /* FIXME _tell gets the offset wrong */
  //cur_offset = gst_bytestream_tell(qtdemux->bs);
  
  cur_offset = qtdemux->offset;
318
  GST_DEBUG ("loop at position %d",cur_offset);
319 320 321 322

  switch(qtdemux->state){
  case QTDEMUX_STATE_HEADER:
  {
323 324 325 326 327 328 329 330 331 332
    do{
      ret = gst_bytestream_peek_bytes(qtdemux->bs, &data, 16);
      if(ret<16){
        if(!gst_qtdemux_handle_sink_event(qtdemux)){
          return;
	}
      }else{
	break;
      }
    }while(1);
Artyom Baginski's avatar
Artyom Baginski committed
333

334
    length = GUINT32_FROM_BE(*(guint32 *)data);
335
    GST_DEBUG ("length %08x",length);
336
    fourcc = GUINT32_FROM_LE(*(guint32 *)(data+4));
337
    GST_DEBUG ("fourcc " GST_FOURCC_FORMAT, GST_FOURCC_ARGS(fourcc));
Jeremy Simon's avatar
Jeremy Simon committed
338

339
    if(length==0){
340
      length = gst_bytestream_length(qtdemux->bs) - cur_offset;
341 342 343 344 345
    }
    if(length==1){
      guint32 length1, length2;
  
      length1 = GUINT32_FROM_BE(*(guint32 *)(data+8));
346
      GST_DEBUG ("length1 %08x",length1);
347
      length2 = GUINT32_FROM_BE(*(guint32 *)(data+12));
348
      GST_DEBUG ("length2 %08x",length2);
349 350 351 352 353 354
  
      length=length2;
    }
  
    switch(fourcc){
      case GST_MAKE_FOURCC('m','d','a','t'):
355 356
      case GST_MAKE_FOURCC('f','r','e','e'):
      case GST_MAKE_FOURCC('w','i','d','e'):
357 358
      case GST_MAKE_FOURCC('P','I','C','T'):
      case GST_MAKE_FOURCC('p','n','o','t'):
359
        break;
360 361 362 363
      case GST_MAKE_FOURCC('m','o','o','v'):
      {
        GstBuffer *moov;
  
364 365 366
	do{
          ret = gst_bytestream_read(qtdemux->bs, &moov, length);
          if(ret < length){
367
            GST_DEBUG ("read failed (%d < %d)",ret,length);
368 369 370 371 372 373 374 375
            if(!gst_qtdemux_handle_sink_event(qtdemux)){
	      return;
	    }
          }else{
	    break;
	  }
	}while(1);

376
        qtdemux_parse_moov(qtdemux, GST_BUFFER_DATA(moov), length);
377
        if(1)qtdemux_node_dump(qtdemux, qtdemux->moov_node);
378 379 380 381 382 383
        qtdemux_parse_tree(qtdemux);
        qtdemux->state = QTDEMUX_STATE_MOVIE;
        break;
      }
      default:
      {
384
        GST_LOG("unknown %08x '" GST_FOURCC_FORMAT "' at %d\n",
385
	    fourcc, GST_FOURCC_ARGS(fourcc), cur_offset);
386 387 388
        break;
      }
    }
389 390 391
    ret = gst_bytestream_seek(qtdemux->bs, cur_offset + length,
        GST_SEEK_METHOD_SET);
    qtdemux->offset = cur_offset + length;
392
    GST_DEBUG ("seek returned %d\n",ret);
393
    break;
Artyom Baginski's avatar
Artyom Baginski committed
394
  }
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
  case QTDEMUX_STATE_SEEKING_EOS:
  {
    guint8 *data;

    do{
      ret = gst_bytestream_peek_bytes(qtdemux->bs, &data, 1);
      if(ret<1){
        if(!gst_qtdemux_handle_sink_event(qtdemux)){
	  return;
        }
      }else{
	break;
      }
    }while(TRUE);
    gst_element_set_eos(element);
Artyom Baginski's avatar
Artyom Baginski committed
410

411
    qtdemux->state = QTDEMUX_STATE_EOS;
Artyom Baginski's avatar
Artyom Baginski committed
412 413
    return;
  }
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
  case QTDEMUX_STATE_EOS:
    g_warning("spinning in EOS\n");
    return;
  case QTDEMUX_STATE_MOVIE:
  {
    QtDemuxStream *stream;
    guint64 min_time;
    int index = -1;
    int i;

    min_time = G_MAXUINT64;
    for(i=0;i<qtdemux->n_streams;i++){
      stream = qtdemux->streams[i];

      if(stream->sample_index < stream->n_samples &&
	  stream->samples[stream->sample_index].timestamp < min_time){
	min_time = stream->samples[stream->sample_index].timestamp;
	index = i;
      }
    }
Artyom Baginski's avatar
Artyom Baginski committed
434

435 436 437
    if(index==-1){
      for(i=0;i<qtdemux->n_streams;i++){
        gst_pad_push(qtdemux->streams[i]->pad,
438
	    GST_DATA(gst_event_new (GST_EVENT_EOS)));
439 440
      }
      ret = gst_bytestream_seek(qtdemux->bs, 0, GST_SEEK_METHOD_END);
441
      GST_DEBUG ("seek returned %d",ret);
442 443 444 445 446 447 448 449 450 451

      qtdemux->state = QTDEMUX_STATE_SEEKING_EOS;
      return;
    }

    stream = qtdemux->streams[index];

    offset = stream->samples[stream->sample_index].offset;
    size = stream->samples[stream->sample_index].size;

452 453 454
    GST_INFO ("pushing from stream %d, sample_index=%d offset=%d size=%d timestamp=%lld",
	index, stream->sample_index, offset, size,
        stream->samples[stream->sample_index].timestamp);
455

456 457
    cur_offset = gst_bytestream_tell(qtdemux->bs);
    if(offset != cur_offset){
458
      GST_DEBUG ("seeking to offset %d",offset);
459
      GST_LOG ("seeking to offset %d\n",offset);
460
      ret = gst_bytestream_seek(qtdemux->bs, offset, GST_SEEK_METHOD_SET);
461
      GST_DEBUG ("seek returned %d",ret);
462
      return;
Artyom Baginski's avatar
Artyom Baginski committed
463
    }
464

465
    GST_DEBUG ("reading %d bytes\n",size);
466 467 468 469
    buf = NULL;
    do{
      ret = gst_bytestream_read(qtdemux->bs, &buf, size);
      if(ret < size){
470
        GST_DEBUG ("read failed (%d < %d)",ret,size);
471 472
        if(!gst_qtdemux_handle_sink_event(qtdemux)){
	  return;
Artyom Baginski's avatar
Artyom Baginski committed
473
	}
474 475
      }else{
	break;
Artyom Baginski's avatar
Artyom Baginski committed
476
      }
477 478 479
    }while(TRUE);

    if(buf){
480 481 482 483
      /* hum... */
      if(stream->subtype == GST_MAKE_FOURCC('v','i','d','e')){
        float fps = 1. * GST_SECOND / stream->samples[stream->sample_index].duration;
        if (fps != stream->fps) {
David Schleef's avatar
David Schleef committed
484 485
	  gst_caps_set_simple (stream->caps, "framerate", G_TYPE_DOUBLE, fps,
	      NULL);
486
          stream->fps = fps;
487
          gst_pad_set_explicit_caps(stream->pad, stream->caps);
488 489 490
        }
      }

491
      GST_BUFFER_TIMESTAMP(buf) = stream->samples[stream->sample_index].timestamp;
492
      GST_BUFFER_DURATION(buf) = stream->samples[stream->sample_index].duration;
493
      gst_pad_push(stream->pad, GST_DATA (buf));
494 495

      GST_DEBUG ("pushing buffer on %" GST_PTR_FORMAT, stream->pad);
Artyom Baginski's avatar
Artyom Baginski committed
496
    }
497 498 499 500 501 502 503 504
    stream->sample_index++;
    break;
  }
  default:
    /* unreached */
    g_assert(0);
  }

Artyom Baginski's avatar
Artyom Baginski committed
505 506
}

507
void gst_qtdemux_add_stream(GstQTDemux *qtdemux, QtDemuxStream *stream)
Artyom Baginski's avatar
Artyom Baginski committed
508
{
509
  if(stream->subtype == GST_MAKE_FOURCC('v','i','d','e')){
David Schleef's avatar
David Schleef committed
510 511
    stream->pad = gst_pad_new_from_template (
	gst_static_pad_template_get(&gst_qtdemux_videosrc_template),
512 513
        g_strdup_printf ("video_%02d", qtdemux->n_video_streams));
    stream->fps = 1. * GST_SECOND / stream->samples[0].duration;
514
    if(stream->caps){
David Schleef's avatar
David Schleef committed
515 516 517 518
      gst_caps_set_simple(stream->caps,
	  "width", G_TYPE_INT, stream->width,
	  "height", G_TYPE_INT, stream->height,
	  "framerate", G_TYPE_DOUBLE, stream->fps, NULL);
519 520 521
    }
    qtdemux->n_video_streams++;
  }else{
David Schleef's avatar
David Schleef committed
522 523
    stream->pad = gst_pad_new_from_template (
	gst_static_pad_template_get(&gst_qtdemux_audiosrc_template),
524
        g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams));
525
    if(stream->caps){
David Schleef's avatar
David Schleef committed
526 527 528
      gst_caps_set_simple(stream->caps,
	  "rate", G_TYPE_INT, (int)stream->rate,
	  "channels", G_TYPE_INT, stream->n_channels, NULL);
Artyom Baginski's avatar
Artyom Baginski committed
529
    }
530 531
    qtdemux->n_audio_streams++;
  }
532

533
  gst_pad_use_explicit_caps (stream->pad);
534

David Schleef's avatar
David Schleef committed
535
  GST_PAD_ELEMENT_PRIVATE(stream->pad) = stream;
536 537
  qtdemux->streams[qtdemux->n_streams] = stream;
  qtdemux->n_streams++;
538
  GST_DEBUG ("n_streams is now %d", qtdemux->n_streams);
539

540 541
  gst_pad_set_explicit_caps(stream->pad, stream->caps);

542
  GST_DEBUG ("adding pad %p to qtdemux %p", stream->pad, qtdemux);
543
  gst_element_add_pad(GST_ELEMENT (qtdemux), stream->pad);
Artyom Baginski's avatar
Artyom Baginski committed
544 545
}

546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585

#define QT_CONTAINER 1

#define FOURCC_moov	GST_MAKE_FOURCC('m','o','o','v')
#define FOURCC_mvhd	GST_MAKE_FOURCC('m','v','h','d')
#define FOURCC_clip	GST_MAKE_FOURCC('c','l','i','p')
#define FOURCC_trak	GST_MAKE_FOURCC('t','r','a','k')
#define FOURCC_udta	GST_MAKE_FOURCC('u','d','t','a')
#define FOURCC_ctab	GST_MAKE_FOURCC('c','t','a','b')
#define FOURCC_tkhd	GST_MAKE_FOURCC('t','k','h','d')
#define FOURCC_crgn	GST_MAKE_FOURCC('c','r','g','n')
#define FOURCC_matt	GST_MAKE_FOURCC('m','a','t','t')
#define FOURCC_kmat	GST_MAKE_FOURCC('k','m','a','t')
#define FOURCC_edts	GST_MAKE_FOURCC('e','d','t','s')
#define FOURCC_elst	GST_MAKE_FOURCC('e','l','s','t')
#define FOURCC_load	GST_MAKE_FOURCC('l','o','a','d')
#define FOURCC_tref	GST_MAKE_FOURCC('t','r','e','f')
#define FOURCC_imap	GST_MAKE_FOURCC('i','m','a','p')
#define FOURCC___in	GST_MAKE_FOURCC(' ',' ','i','n')
#define FOURCC___ty	GST_MAKE_FOURCC(' ',' ','t','y')
#define FOURCC_mdia	GST_MAKE_FOURCC('m','d','i','a')
#define FOURCC_mdhd	GST_MAKE_FOURCC('m','d','h','d')
#define FOURCC_hdlr	GST_MAKE_FOURCC('h','d','l','r')
#define FOURCC_minf	GST_MAKE_FOURCC('m','i','n','f')
#define FOURCC_vmhd	GST_MAKE_FOURCC('v','m','h','d')
#define FOURCC_smhd	GST_MAKE_FOURCC('s','m','h','d')
#define FOURCC_gmhd	GST_MAKE_FOURCC('g','m','h','d')
#define FOURCC_gmin	GST_MAKE_FOURCC('g','m','i','n')
#define FOURCC_dinf	GST_MAKE_FOURCC('d','i','n','f')
#define FOURCC_dref	GST_MAKE_FOURCC('d','r','e','f')
#define FOURCC_stbl	GST_MAKE_FOURCC('s','t','b','l')
#define FOURCC_stsd	GST_MAKE_FOURCC('s','t','s','d')
#define FOURCC_stts	GST_MAKE_FOURCC('s','t','t','s')
#define FOURCC_stss	GST_MAKE_FOURCC('s','t','s','s')
#define FOURCC_stsc	GST_MAKE_FOURCC('s','t','s','c')
#define FOURCC_stsz	GST_MAKE_FOURCC('s','t','s','z')
#define FOURCC_stco	GST_MAKE_FOURCC('s','t','c','o')
#define FOURCC_vide	GST_MAKE_FOURCC('v','i','d','e')
#define FOURCC_soun	GST_MAKE_FOURCC('s','o','u','n')
#define FOURCC_co64	GST_MAKE_FOURCC('c','o','6','4')
586 587 588
#define FOURCC_cmov	GST_MAKE_FOURCC('c','m','o','v')
#define FOURCC_dcom	GST_MAKE_FOURCC('d','c','o','m')
#define FOURCC_cmvd	GST_MAKE_FOURCC('c','m','v','d')
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604


static void qtdemux_dump_mvhd(GstQTDemux *qtdemux, void *buffer, int depth);
static void qtdemux_dump_tkhd(GstQTDemux *qtdemux, void *buffer, int depth);
static void qtdemux_dump_elst(GstQTDemux *qtdemux, void *buffer, int depth);
static void qtdemux_dump_mdhd(GstQTDemux *qtdemux, void *buffer, int depth);
static void qtdemux_dump_hdlr(GstQTDemux *qtdemux, void *buffer, int depth);
static void qtdemux_dump_vmhd(GstQTDemux *qtdemux, void *buffer, int depth);
static void qtdemux_dump_dref(GstQTDemux *qtdemux, void *buffer, int depth);
static void qtdemux_dump_stsd(GstQTDemux *qtdemux, void *buffer, int depth);
static void qtdemux_dump_stts(GstQTDemux *qtdemux, void *buffer, int depth);
static void qtdemux_dump_stss(GstQTDemux *qtdemux, void *buffer, int depth);
static void qtdemux_dump_stsc(GstQTDemux *qtdemux, void *buffer, int depth);
static void qtdemux_dump_stsz(GstQTDemux *qtdemux, void *buffer, int depth);
static void qtdemux_dump_stco(GstQTDemux *qtdemux, void *buffer, int depth);
static void qtdemux_dump_co64(GstQTDemux *qtdemux, void *buffer, int depth);
605 606
static void qtdemux_dump_dcom(GstQTDemux *qtdemux, void *buffer, int depth);
static void qtdemux_dump_cmvd(GstQTDemux *qtdemux, void *buffer, int depth);
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658

QtNodeType qt_node_types[] = {
  { FOURCC_moov, "movie",		QT_CONTAINER, },
  { FOURCC_mvhd, "movie header",	0,
  	qtdemux_dump_mvhd },
  { FOURCC_clip, "clipping",		QT_CONTAINER, },
  { FOURCC_trak, "track",		QT_CONTAINER, },
  { FOURCC_udta, "user data",		0, }, /* special container */
  { FOURCC_ctab, "color table",		0, },
  { FOURCC_tkhd, "track header",	0,
  	qtdemux_dump_tkhd },
  { FOURCC_crgn, "clipping region",	0, },
  { FOURCC_matt, "track matte",		QT_CONTAINER, },
  { FOURCC_kmat, "compressed matte",	0, },
  { FOURCC_edts, "edit",		QT_CONTAINER, },
  { FOURCC_elst, "edit list",		0,
  	qtdemux_dump_elst },
  { FOURCC_load, "track load settings",	0, },
  { FOURCC_tref, "track reference",	QT_CONTAINER, },
  { FOURCC_imap, "track input map",	QT_CONTAINER, },
  { FOURCC___in, "track input",		0, }, /* special container */
  { FOURCC___ty, "input type",		0, },
  { FOURCC_mdia, "media",		QT_CONTAINER },
  { FOURCC_mdhd, "media header",	0,
  	qtdemux_dump_mdhd },
  { FOURCC_hdlr, "handler reference",	0,
  	qtdemux_dump_hdlr },
  { FOURCC_minf, "media information",	QT_CONTAINER },
  { FOURCC_vmhd, "video media information", 0,
  	qtdemux_dump_vmhd },
  { FOURCC_smhd, "sound media information", 0 },
  { FOURCC_gmhd, "base media information header", 0 },
  { FOURCC_gmin, "base media info",	0 },
  { FOURCC_dinf, "data information",	QT_CONTAINER },
  { FOURCC_dref, "data reference",	0,
  	qtdemux_dump_dref },
  { FOURCC_stbl, "sample table",	QT_CONTAINER },
  { FOURCC_stsd, "sample description",	0,
  	qtdemux_dump_stsd },
  { FOURCC_stts, "time-to-sample",	0,
  	qtdemux_dump_stts },
  { FOURCC_stss, "sync sample",		0,
  	qtdemux_dump_stss },
  { FOURCC_stsc, "sample-to-chunk",	0,
  	qtdemux_dump_stsc },
  { FOURCC_stsz, "sample size",		0,
  	qtdemux_dump_stsz },
  { FOURCC_stco, "chunk offset",	0,
  	qtdemux_dump_stco },
  { FOURCC_co64, "64-bit chunk offset",	0,
  	qtdemux_dump_co64 },
  { FOURCC_vide, "video media",		0 },
659 660 661 662 663
  { FOURCC_cmov, "compressed movie",	QT_CONTAINER },
  { FOURCC_dcom, "compressed data",	0,
  	qtdemux_dump_dcom },
  { FOURCC_cmvd, "compressed movie data", 0,
  	qtdemux_dump_cmvd },
664 665 666 667 668
  { 0, "unknown", 0 },
};
static int n_qt_node_types = sizeof(qt_node_types)/sizeof(qt_node_types[0]);


669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711
static void *qtdemux_zalloc(void *opaque, unsigned int items, unsigned int size)
{
  return g_malloc(items*size);
}

static void qtdemux_zfree(void *opaque, void *addr)
{
  g_free(addr);
}

static void *qtdemux_inflate(void *z_buffer, int z_length, int length)
{
  void *buffer;
  z_stream *z;
  int ret;

  z = g_new0(z_stream, 1);
  z->zalloc = qtdemux_zalloc;
  z->zfree = qtdemux_zfree;
  z->opaque = NULL;

  z->next_in = z_buffer;
  z->avail_in = z_length;

  buffer = g_malloc(length);
  ret = inflateInit(z);
  while(z->avail_in > 0){
    if(z->avail_out == 0){
      length += 1024;
      buffer = realloc(buffer, length);
      z->next_out = buffer + z->total_out;
      z->avail_out = 1024;
    }
    ret = inflate(z,Z_SYNC_FLUSH);
    if(ret != Z_OK)break;
  }
  if(ret != Z_STREAM_END){
    g_warning("inflate() returned %d\n",ret);
  }

  g_free(z);
  return buffer;
}
712 713

static void qtdemux_parse_moov(GstQTDemux *qtdemux, void *buffer, int length)
Artyom Baginski's avatar
Artyom Baginski committed
714
{
715
  GNode *cmov;
716 717 718 719 720

  qtdemux->moov_node = g_node_new(buffer);

  qtdemux_parse(qtdemux, qtdemux->moov_node, buffer, length);

721 722 723 724 725 726 727 728 729 730 731 732 733 734 735
  cmov = qtdemux_tree_get_child_by_type(qtdemux->moov_node, FOURCC_cmov);
  if(cmov){
    GNode *dcom;
    GNode *cmvd;

    dcom = qtdemux_tree_get_child_by_type(cmov, FOURCC_dcom);
    cmvd = qtdemux_tree_get_child_by_type(cmov, FOURCC_cmvd);

    if(QTDEMUX_FOURCC_GET(dcom->data+8) == GST_MAKE_FOURCC('z','l','i','b')){
      int uncompressed_length;
      int compressed_length;
      void *buf;
      
      uncompressed_length = QTDEMUX_GUINT32_GET(cmvd->data+8);
      compressed_length = QTDEMUX_GUINT32_GET(cmvd->data+4) - 12;
736
      GST_LOG("length = %d\n",uncompressed_length);
737 738 739 740 741 742 743 744 745

      buf = qtdemux_inflate(cmvd->data + 12, compressed_length,
	  uncompressed_length);

      qtdemux->moov_node_compressed = qtdemux->moov_node;
      qtdemux->moov_node = g_node_new(buf);

      qtdemux_parse(qtdemux, qtdemux->moov_node, buf, uncompressed_length);
    }else{
746
      GST_LOG("unknown header compression type\n");
747 748
    }
  }
Artyom Baginski's avatar
Artyom Baginski committed
749 750
}

751
static void qtdemux_parse(GstQTDemux *qtdemux, GNode *node, void *buffer, int length)
Artyom Baginski's avatar
Artyom Baginski committed
752
{
753 754 755 756 757
  guint32 fourcc;
  guint32 node_length;
  QtNodeType *type;
  void *end;

758
  GST_LOG("qtdemux_parse %p %d\n",buffer, length);
759

760 761
  node_length = QTDEMUX_GUINT32_GET(buffer);
  fourcc = QTDEMUX_FOURCC_GET(buffer+4);
762 763

  type = qtdemux_type_get(fourcc);
Artyom Baginski's avatar
Artyom Baginski committed
764
  
765
  GST_LOG("parsing '" GST_FOURCC_FORMAT "', length=%d\n",
766
      GST_FOURCC_ARGS(fourcc), node_length);
767 768 769 770 771 772 773 774 775 776 777 778

  if(type->flags & QT_CONTAINER){
    void *buf;
    guint32 len;

    buf = buffer + 8;
    end = buffer + length;
    while(buf < end){
      GNode *child;

      if(buf + 8 >= end){
	/* FIXME: get annoyed */
779
	GST_LOG("buffer overrun\n");
780
      }
781
      len = QTDEMUX_GUINT32_GET(buf);
782 783 784 785 786 787 788 789

      child = g_node_new(buf);
      g_node_append(node, child);
      qtdemux_parse(qtdemux, child, buf, len);

      buf += len;
    }
  }else{
790 791 792 793 794 795
#if 0
    if(fourcc == FOURCC_cmvd){
      int uncompressed_length;
      void *buf;
      
      uncompressed_length = QTDEMUX_GUINT32_GET(buffer+8);
796
      GST_LOG("length = %d\n",uncompressed_length);
797 798 799 800 801 802 803 804 805 806

      buf = qtdemux_inflate(buffer + 12, node_length-12, uncompressed_length);

      end = buf + uncompressed_length;
      while(buf < end){
        GNode *child;
	guint32 len;

        if(buf + 8 >= end){
	  /* FIXME: get annoyed */
807
	  GST_LOG("buffer overrun\n");
808 809
        }
        len = QTDEMUX_GUINT32_GET(buf);
810

811 812 813 814 815 816 817 818
        child = g_node_new(buf);
        g_node_append(node, child);
        qtdemux_parse(qtdemux, child, buf, len);

        buf += len;
      }
    }
#endif
Artyom Baginski's avatar
Artyom Baginski committed
819 820 821
  }
}

822
static QtNodeType *qtdemux_type_get(guint32 fourcc)
Artyom Baginski's avatar
Artyom Baginski committed
823
{
824 825 826 827 828 829 830
  int i;

  for(i=0;i<n_qt_node_types;i++){
    if(qt_node_types[i].fourcc == fourcc)
      return qt_node_types+i;
  }
  return qt_node_types+n_qt_node_types-1;
Artyom Baginski's avatar
Artyom Baginski committed
831 832
}

833
static gboolean qtdemux_node_dump_foreach(GNode *node, gpointer data)
Artyom Baginski's avatar
Artyom Baginski committed
834
{
835 836 837 838 839
  void *buffer = node->data;
  guint32 node_length;
  guint32 fourcc;
  QtNodeType *type;
  int depth;
Artyom Baginski's avatar
Artyom Baginski committed
840

841 842
  node_length = GUINT32_FROM_BE(*(guint32 *)buffer);
  fourcc = GUINT32_FROM_LE(*(guint32 *)(buffer+4));
Artyom Baginski's avatar
Artyom Baginski committed
843

844 845 846
  type = qtdemux_type_get(fourcc);

  depth = (g_node_depth(node)-1)*2;
847
  GST_LOG("%*s'" GST_FOURCC_FORMAT "', [%d], %s\n",
848 849 850 851 852 853 854 855
      depth, "",
      GST_FOURCC_ARGS(fourcc),
      node_length,
      type->name);

  if(type->dump)type->dump(data, buffer, depth);

  return FALSE;
Artyom Baginski's avatar
Artyom Baginski committed
856 857
}

858
static void qtdemux_node_dump(GstQTDemux *qtdemux, GNode *node)
Artyom Baginski's avatar
Artyom Baginski committed
859
{
860 861
  g_node_traverse(qtdemux->moov_node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
      qtdemux_node_dump_foreach, qtdemux);
Artyom Baginski's avatar
Artyom Baginski committed
862 863
}

864 865
static void qtdemux_dump_mvhd(GstQTDemux *qtdemux, void *buffer, int depth)
{
866 867 868 869 870 871 872 873 874 875 876 877 878 879
  GST_LOG("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
  GST_LOG("%*s  creation time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
  GST_LOG("%*s  modify time:   %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16));
  GST_LOG("%*s  time scale:    1/%u sec\n", depth, "", QTDEMUX_GUINT32_GET(buffer+20));
  GST_LOG("%*s  duration:      %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+24));
  GST_LOG("%*s  pref. rate:    %g\n", depth, "", QTDEMUX_FP32_GET(buffer+28));
  GST_LOG("%*s  pref. volume:  %g\n", depth, "", QTDEMUX_FP16_GET(buffer+32));
  GST_LOG("%*s  preview time:  %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+80));
  GST_LOG("%*s  preview dur.:  %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+84));
  GST_LOG("%*s  poster time:   %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+88));
  GST_LOG("%*s  select time:   %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+92));
  GST_LOG("%*s  select dur.:   %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+96));
  GST_LOG("%*s  current time:  %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+100));
  GST_LOG("%*s  next track ID: %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+104));
880
}
Artyom Baginski's avatar
Artyom Baginski committed
881

882 883
static void qtdemux_dump_tkhd(GstQTDemux *qtdemux, void *buffer, int depth)
{
884 885 886 887 888 889 890 891 892 893
  GST_LOG("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
  GST_LOG("%*s  creation time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
  GST_LOG("%*s  modify time:   %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16));
  GST_LOG("%*s  track ID:      %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+20));
  GST_LOG("%*s  duration:      %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+28));
  GST_LOG("%*s  layer:         %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+36));
  GST_LOG("%*s  alt group:     %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+38));
  GST_LOG("%*s  volume:        %g\n", depth, "", QTDEMUX_FP16_GET(buffer+44));
  GST_LOG("%*s  track width:   %g\n", depth, "", QTDEMUX_FP32_GET(buffer+84));
  GST_LOG("%*s  track height:  %g\n", depth, "", QTDEMUX_FP32_GET(buffer+88));
894 895 896 897 898 899 900 901

}

static void qtdemux_dump_elst(GstQTDemux *qtdemux, void *buffer, int depth)
{
  int i;
  int n;

902 903
  GST_LOG("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
  GST_LOG("%*s  n entries:     %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
904 905
  n = QTDEMUX_GUINT32_GET(buffer+12);
  for(i=0;i<n;i++){
906 907 908
    GST_LOG("%*s    track dur:     %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16+i*12));
    GST_LOG("%*s    media time:    %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+20+i*12));
    GST_LOG("%*s    media rate:    %g\n", depth, "", QTDEMUX_FP32_GET(buffer+24+i*12));
Artyom Baginski's avatar
Artyom Baginski committed
909 910 911
  }
}

912
static void qtdemux_dump_mdhd(GstQTDemux *qtdemux, void *buffer, int depth)
Artyom Baginski's avatar
Artyom Baginski committed
913
{
914 915 916 917 918 919 920
  GST_LOG("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
  GST_LOG("%*s  creation time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
  GST_LOG("%*s  modify time:   %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16));
  GST_LOG("%*s  time scale:    1/%u sec\n", depth, "", QTDEMUX_GUINT32_GET(buffer+20));
  GST_LOG("%*s  duration:      %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+24));
  GST_LOG("%*s  language:      %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+28));
  GST_LOG("%*s  quality:       %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+30));
921

Artyom Baginski's avatar
Artyom Baginski committed
922 923
}

924
static void qtdemux_dump_hdlr(GstQTDemux *qtdemux, void *buffer, int depth)
Artyom Baginski's avatar
Artyom Baginski committed
925
{
926 927
  GST_LOG("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
  GST_LOG("%*s  type:          " GST_FOURCC_FORMAT "\n", depth, "",
928
      GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+12)));
929
  GST_LOG("%*s  subtype:       " GST_FOURCC_FORMAT "\n", depth, "",
930
      GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+16)));
931
  GST_LOG("%*s  manufacturer:  " GST_FOURCC_FORMAT "\n", depth, "",
932
      GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+20)));
933 934 935
  GST_LOG("%*s  flags:         %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+24));
  GST_LOG("%*s  flags mask:    %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+28));
  GST_LOG("%*s  name:          %*s\n", depth, "",
936
      QTDEMUX_GUINT8_GET(buffer+32), (char *)(buffer+33));
Artyom Baginski's avatar
Artyom Baginski committed
937 938 939

}

940
static void qtdemux_dump_vmhd(GstQTDemux *qtdemux, void *buffer, int depth)
Artyom Baginski's avatar
Artyom Baginski committed
941
{
942 943
  GST_LOG("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
  GST_LOG("%*s  mode/color:    %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16));
944
}
Artyom Baginski's avatar
Artyom Baginski committed
945

946 947 948 949 950 951
static void qtdemux_dump_dref(GstQTDemux *qtdemux, void *buffer, int depth)
{
  int n;
  int i;
  int offset;

952 953
  GST_LOG("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
  GST_LOG("%*s  n entries:     %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
954 955 956
  n = QTDEMUX_GUINT32_GET(buffer+12);
  offset = 16;
  for(i=0;i<n;i++){
957 958
    GST_LOG("%*s    size:          %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
    GST_LOG("%*s    type:          " GST_FOURCC_FORMAT "\n", depth, "",
959 960
	GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+offset+4)));
    offset += QTDEMUX_GUINT32_GET(buffer+offset);
Artyom Baginski's avatar
Artyom Baginski committed
961 962 963
  }
}

964
static void qtdemux_dump_stsd(GstQTDemux *qtdemux, void *buffer, int depth)
Artyom Baginski's avatar
Artyom Baginski committed
965
{
966 967 968 969
  int i;
  int n;
  int offset;

970 971
  GST_LOG("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
  GST_LOG("%*s  n entries:     %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
972 973 974
  n = QTDEMUX_GUINT32_GET(buffer+12);
  offset = 16;
  for(i=0;i<n;i++){
975 976
    GST_LOG("%*s    size:          %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
    GST_LOG("%*s    type:          " GST_FOURCC_FORMAT "\n", depth, "",
977
	GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+offset+4)));
978
    GST_LOG("%*s    data reference:%d\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+14));
979

980 981
    GST_LOG("%*s    version/rev.:  %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+16));
    GST_LOG("%*s    vendor:        " GST_FOURCC_FORMAT "\n", depth, "",
982
	GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+offset+20)));
983 984 985 986 987 988 989 990 991
    GST_LOG("%*s    temporal qual: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+24));
    GST_LOG("%*s    spatial qual:  %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+28));
    GST_LOG("%*s    width:         %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+32));
    GST_LOG("%*s    height:        %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+34));
    GST_LOG("%*s    horiz. resol:  %g\n", depth, "", QTDEMUX_FP32_GET(buffer+offset+36));
    GST_LOG("%*s    vert. resol.:  %g\n", depth, "", QTDEMUX_FP32_GET(buffer+offset+40));
    GST_LOG("%*s    data size:     %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+44));
    GST_LOG("%*s    frame count:   %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+48));
    GST_LOG("%*s    compressor:    %*s\n", depth, "",
992
	QTDEMUX_GUINT8_GET(buffer+offset+49), (char *)(buffer+offset+51));
993 994
    GST_LOG("%*s    depth:         %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+82));
    GST_LOG("%*s    color table ID:%u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+84));
995 996 997

    offset += QTDEMUX_GUINT32_GET(buffer+offset);
  }
Artyom Baginski's avatar
Artyom Baginski committed
998 999
}

1000
static void qtdemux_dump_stts(GstQTDemux *qtdemux, void *buffer, int depth)
Artyom Baginski's avatar
Artyom Baginski committed
1001
{
1002 1003 1004 1005
  int i;
  int n;
  int offset;

1006 1007
  GST_LOG("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
  GST_LOG("%*s  n entries:     %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1008 1009 1010
  n = QTDEMUX_GUINT32_GET(buffer+12);
  offset = 16;
  for(i=0;i<n;i++){
1011 1012
    GST_LOG("%*s    count:         %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
    GST_LOG("%*s    duration:      %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset + 4));
1013 1014 1015

    offset += 8;
  }
Artyom Baginski's avatar
Artyom Baginski committed
1016
}
1017 1018

static void qtdemux_dump_stss(GstQTDemux *qtdemux, void *buffer, int depth)
Artyom Baginski's avatar
Artyom Baginski committed
1019
{
1020 1021 1022 1023
  int i;
  int n;
  int offset;

1024 1025
  GST_LOG("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
  GST_LOG("%*s  n entries:     %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1026 1027 1028
  n = QTDEMUX_GUINT32_GET(buffer+12);
  offset = 16;
  for(i=0;i<n;i++){
1029
    GST_LOG("%*s    sample:        %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1030 1031 1032

    offset += 4;
  }
Artyom Baginski's avatar
Artyom Baginski committed
1033 1034
}

1035
static void qtdemux_dump_stsc(GstQTDemux *qtdemux, void *buffer, int depth)
Artyom Baginski's avatar
Artyom Baginski committed
1036
{
1037 1038 1039 1040
  int i;
  int n;
  int offset;

1041 1042
  GST_LOG("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
  GST_LOG("%*s  n entries:     %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1043 1044 1045
  n = QTDEMUX_GUINT32_GET(buffer+12);
  offset = 16;
  for(i=0;i<n;i++){
1046 1047 1048
    GST_LOG("%*s    first chunk:   %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
    GST_LOG("%*s    sample per ch: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+4));
    GST_LOG("%*s    sample desc id:%08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+8));
1049 1050 1051

    offset += 12;
  }
Artyom Baginski's avatar
Artyom Baginski committed
1052 1053
}

1054
static void qtdemux_dump_stsz(GstQTDemux *qtdemux, void *buffer, int depth)
Artyom Baginski's avatar
Artyom Baginski committed
1055
{
1056 1057 1058 1059 1060
  int i;
  int n;
  int offset;
  int sample_size;

1061 1062
  GST_LOG("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
  GST_LOG("%*s  sample size:   %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1063 1064
  sample_size = QTDEMUX_GUINT32_GET(buffer+12);
  if(sample_size == 0){
1065
    GST_LOG("%*s  n entries:     %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16));
1066 1067 1068
    n = QTDEMUX_GUINT32_GET(buffer+16);
    offset = 20;
    for(i=0;i<n;i++){
1069
      GST_LOG("%*s    sample size:   %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1070 1071 1072 1073

      offset += 4;
    }
  }
Artyom Baginski's avatar
Artyom Baginski committed
1074 1075
}

1076
static void qtdemux_dump_stco(GstQTDemux *qtdemux, void *buffer, int depth)
Artyom Baginski's avatar
Artyom Baginski committed
1077
{
1078 1079 1080 1081
  int i;
  int n;
  int offset;

1082 1083
  GST_LOG("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
  GST_LOG("%*s  n entries:     %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1084 1085 1086
  n = QTDEMUX_GUINT32_GET(buffer+12);
  offset = 16;
  for(i=0;i<n;i++){
1087
    GST_LOG("%*s    chunk offset:  %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1088 1089 1090

    offset += 4;
  }
Artyom Baginski's avatar
Artyom Baginski committed
1091 1092
}

1093 1094 1095 1096 1097 1098
static void qtdemux_dump_co64(GstQTDemux *qtdemux, void *buffer, int depth)
{
  int i;
  int n;
  int offset;