~ubuntu-branches/ubuntu/dapper/gst-plugins-good0.10/dapper-security

« back to all changes in this revision

Viewing changes to gst/matroska/matroska-mux.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2006-05-05 19:10:19 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20060505191019-mge3njl5173jfldb
Tags: 0.10.3-0ubuntu1
* New upstream version (Ubuntu: #43135):
  Changes since 0.10.2:
  - Annodex/CMML support
  - RTSP and RTP enhancements
  - HAL configured audio device support
  - FLAC, Matroska, AVI, WAV, ID3, APE, DV and JPEG plugin improvements
  - Recognise SSA/ASS and USF subtitles in Matroska files
  - Fixes for ESD and SunAudio output plugins
  - More uniform plugin descriptions
  - IceCast metadata reading plugin added
  - New plugins ported from 0.8: OSX audio, AVI muxer, X-Windows input,
    WAV encoder, Gdk-Pixbuf image decoder, Smoke decoder,
    Video colour balance
  - Lots of bug fixes
  Bugs fixed since 0.10.2:
  - RTSP src not working with WMServer servers
  - Replacing icy demuxing in gnomevfssrc
  - HAL sound device wrapper plugins
  - totem (gstreamer) crashes when playing an avi file (Ubuntu: #38800)
  - avidemux does not handle eos at end of seek-region
  - faulty GObject macros
  - [patch] Streaming support for wavparse
  - [pngdec] doesn't handle grayscale or paletted
  - Time slider does not work with avi videos from Cannon SD100
  - [auparse] .au files don't play in playbin
  - [wavparse] will not play DTS stream in malformed WAV
  - rtspsrc filter sometimes uses an odd port for rtp
  - annodex decoding and encoding support
  - [id3demux] read in replaygain information from RVA2 frame...
  - " Seek in ready " for dvdemux
  - problem with auparse or mulawdec, choppy esd playback
  - videobalance not ported to new GstVideoFilter
  - " Seek in ready " support for wavparse plugin
  - gst-plugins-good fail to compile with gcc 4.1
  - Profile support for gconfaudiosink
  - Crash playing any song from a particular album over rhyth...
  - Unable to play .fli files
  - Critical warnings when using cddacdiosrc
  - Gstreamer doesn't recognise tags
  - [alpha] state change function returns a constant
  - Another file that gstreamer can't read the tags on
  - [jpeg] smokedec not ported
  - [pngdec] does not support files with png streams
  - [PATCH] avimux ported to 0.10
  - [wavparse] does not support multichannel wavs
  - [id3demux] reads unicode tags incorrectly where .8 did it...
  - [apedemux] some WavPack files with APE tags fail to play ...
  - [sunaudio] unused variables break CVS build with -Werror
  - [PATCH] Fix gst_pad_new_from_template (gst_static_pad_tem...
  - invalid get_times implementation in gstdynudpsink
  - [patch] unref the result of gst_pad_get_parent
  - [jpegdec] wrong durations set on buffers after seeking in...
  - avi of mpeg4 video and adpcm audio from digital camera re...
  - [id3demux] mp3 fails to play because typefinding thinks i...
  - [goom] zoom filter leaked
  - [wavparse] incorrect way to calculate seek position with ...
  - rhythmbox import crasher - png?
  - Video playback out of sync (Ubuntu: #33073)
  - [speexenc] doesn't work (Ubuntu: #34904)
  - move taglib-based ID3 muxer to -good
  - plugins need better/univied descriptions
  - move ximagesrc to gst-plugins-good
  - index creation might fail with some non-indexe...
  - Problem playing some AVI file when splitting large chunks...
  - [speex] can't seek in speex-encoded audio (Ubuntu: #37552)
  - [matroska] " caps not real subset " when playing audio files
  - AVI files downloaded from vidoe.google.com won't play (Ubuntu: #30031)
  - [sunaudiosink] some fixes
  - [flacdec] can't play .flac files where header says total_...
  - [flacdec] segment seek not supported
  - [id3demux] TCO genre tags (id3v2.2) don't get read by gst...
  - [shout2send] fix crash on error and tags received before ...
  - [wavenc] " not negotiated " error with CVS core
  - [matroskademux] blocks on segmenting seek (and other seek...
  - [matroska] can't play file if details come before type in...
  - [matroska] enhancement for VfW compatibility cases
  - [matroskamux] wrong timestamps of B-frames
  - [matroskamux] blocks upon muxing video and vorbis-audio
  - rtpamrdec discards non-transmitted frames
  - use a duration based on the index if available (Ubuntu: #29962)
* debian/build-deps.in:
  - Build-Depends on libgtk2.0-dev libhal-dev libtag1-dev libxml2-dev
  - updated libgstreamer-plugins-base0.10-dev requirement
* debian/control.in:
  - gstreamer0.10-plugins-good Replaces gstreamer0.10-plugins-bad (<< 0.10.3)
* debian/gstreamer-plugins-good.install:
  - list new elements to install
* debian/rules:
  - updated libgstreamer0.10-dev requirement

Show diffs side-by-side

added added

removed removed

Lines of Context:
72
72
        COMMON_VIDEO_CAPS "; "
73
73
        "video/x-xvid, "
74
74
        COMMON_VIDEO_CAPS "; "
 
75
        "video/x-huffyuv, "
 
76
        COMMON_VIDEO_CAPS "; "
 
77
        "video/x-dv, "
 
78
        COMMON_VIDEO_CAPS "; "
 
79
        "video/x-h263, "
 
80
        COMMON_VIDEO_CAPS "; "
75
81
        "video/x-msmpeg, "
76
82
        COMMON_VIDEO_CAPS "; "
77
83
        "image/jpeg, "
166
172
gst_matroska_mux_base_init (gpointer g_class)
167
173
{
168
174
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
169
 
  static GstElementDetails gst_matroska_mux_details = {
170
 
    "Matroska muxer",
171
 
    "Codec/Muxer",
172
 
    "Muxes video/audio/subtitle streams into a matroska stream",
173
 
    "Ronald Bultje <rbultje@ronald.bitfreak.net>"
174
 
  };
 
175
  static const GstElementDetails gst_matroska_mux_details =
 
176
      GST_ELEMENT_DETAILS ("Matroska muxer",
 
177
      "Codec/Muxer",
 
178
      "Muxes video/audio/subtitle streams into a matroska stream",
 
179
      "Ronald Bultje <rbultje@ronald.bitfreak.net>");
175
180
 
176
181
  gst_element_class_add_pad_template (element_class,
177
182
      gst_static_pad_template_get (&videosink_templ));
232
237
 
233
238
  mux->collect = gst_collect_pads_new ();
234
239
  gst_collect_pads_set_function (mux->collect,
235
 
      (GstCollectPadsFunction) gst_matroska_mux_collected, mux);
 
240
      (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_matroska_mux_collected),
 
241
      mux);
236
242
 
237
243
  mux->ebml_write = gst_ebml_write_new (mux->srcpad);
238
244
 
484
490
    context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MJPEG);
485
491
 
486
492
    return TRUE;
487
 
  } else if (!strcmp (mimetype, "video/x-divx")) {
488
 
    gint divxversion;
489
 
    BITMAPINFOHEADER *bih;
490
 
 
491
 
    bih = (BITMAPINFOHEADER *) g_malloc0 (sizeof (BITMAPINFOHEADER));
492
 
    GST_WRITE_UINT32_LE (&bih->bi_size, sizeof (BITMAPINFOHEADER));
493
 
    GST_WRITE_UINT32_LE (&bih->bi_width, videocontext->pixel_width);
494
 
    GST_WRITE_UINT32_LE (&bih->bi_height, videocontext->pixel_height);
495
 
    GST_WRITE_UINT16_LE (&bih->bi_planes, (guint16) 1);
496
 
    GST_WRITE_UINT16_LE (&bih->bi_bit_count, (guint16) 24);
497
 
    GST_WRITE_UINT32_LE (&bih->bi_size_image, videocontext->pixel_width *
498
 
        videocontext->pixel_height * 3);
499
 
 
500
 
    gst_structure_get_int (structure, "divxversion", &divxversion);
501
 
    switch (divxversion) {
502
 
      case 3:
503
 
        GST_WRITE_UINT32_LE (&bih->bi_compression, GST_STR_FOURCC ("DIV3"));
504
 
        break;
505
 
      case 4:
506
 
        GST_WRITE_UINT32_LE (&bih->bi_compression, GST_STR_FOURCC ("DIVX"));
507
 
        break;
508
 
      case 5:
509
 
        GST_WRITE_UINT32_LE (&bih->bi_compression, GST_STR_FOURCC ("DX50"));
510
 
        break;
511
 
    }
512
 
 
513
 
    context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
514
 
    context->codec_priv = (gpointer) bih;
515
 
    context->codec_priv_size = sizeof (BITMAPINFOHEADER);
516
 
 
517
 
    return TRUE;
518
 
  } else if (!strcmp (mimetype, "video/x-xvid")) {
519
 
    BITMAPINFOHEADER *bih;
520
 
 
521
 
    bih = (BITMAPINFOHEADER *) g_malloc0 (sizeof (BITMAPINFOHEADER));
522
 
    GST_WRITE_UINT32_LE (&bih->bi_size, sizeof (BITMAPINFOHEADER));
523
 
    GST_WRITE_UINT32_LE (&bih->bi_width, videocontext->pixel_width);
524
 
    GST_WRITE_UINT32_LE (&bih->bi_height, videocontext->pixel_height);
525
 
    GST_WRITE_UINT16_LE (&bih->bi_planes, (guint16) 1);
526
 
    GST_WRITE_UINT16_LE (&bih->bi_bit_count, (guint16) 24);
527
 
    GST_WRITE_UINT32_LE (&bih->bi_compression, GST_STR_FOURCC ("XVID"));
528
 
    GST_WRITE_UINT32_LE (&bih->bi_size_image, videocontext->pixel_width *
529
 
        videocontext->pixel_height * 3);
530
 
 
531
 
    context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
532
 
    context->codec_priv = (gpointer) bih;
533
 
    context->codec_priv_size = sizeof (BITMAPINFOHEADER);
 
493
  } else if (!strcmp (mimetype, "video/x-xvid") /* MS/VfW compatibility cases */
 
494
      ||!strcmp (mimetype, "video/x-huffyuv")
 
495
      || !strcmp (mimetype, "video/x-divx")
 
496
      || !strcmp (mimetype, "video/x-dv")
 
497
      || !strcmp (mimetype, "video/x-h263")) {
 
498
    BITMAPINFOHEADER *bih;
 
499
    const GValue *codec_data;
 
500
    gint size = sizeof (BITMAPINFOHEADER);
 
501
 
 
502
    bih = g_new0 (BITMAPINFOHEADER, 1);
 
503
    GST_WRITE_UINT32_LE (&bih->bi_size, size);
 
504
    GST_WRITE_UINT32_LE (&bih->bi_width, videocontext->pixel_width);
 
505
    GST_WRITE_UINT32_LE (&bih->bi_height, videocontext->pixel_height);
 
506
    GST_WRITE_UINT16_LE (&bih->bi_planes, (guint16) 1);
 
507
    GST_WRITE_UINT16_LE (&bih->bi_bit_count, (guint16) 24);
 
508
    GST_WRITE_UINT32_LE (&bih->bi_size_image, videocontext->pixel_width *
 
509
        videocontext->pixel_height * 3);
 
510
 
 
511
    if (!strcmp (mimetype, "video/x-xvid"))
 
512
      GST_WRITE_UINT32_LE (&bih->bi_compression, GST_STR_FOURCC ("XVID"));
 
513
    else if (!strcmp (mimetype, "video/x-huffyuv"))
 
514
      GST_WRITE_UINT32_LE (&bih->bi_compression, GST_STR_FOURCC ("HFYU"));
 
515
    else if (!strcmp (mimetype, "video/x-dv"))
 
516
      GST_WRITE_UINT32_LE (&bih->bi_compression, GST_STR_FOURCC ("DVSD"));
 
517
    else if (!strcmp (mimetype, "video/x-h263"))
 
518
      GST_WRITE_UINT32_LE (&bih->bi_compression, GST_STR_FOURCC ("H263"));
 
519
    else if (!strcmp (mimetype, "video/x-divx")) {
 
520
      gint divxversion;
 
521
 
 
522
      gst_structure_get_int (structure, "divxversion", &divxversion);
 
523
      switch (divxversion) {
 
524
        case 3:
 
525
          GST_WRITE_UINT32_LE (&bih->bi_compression, GST_STR_FOURCC ("DIV3"));
 
526
          break;
 
527
        case 4:
 
528
          GST_WRITE_UINT32_LE (&bih->bi_compression, GST_STR_FOURCC ("DIVX"));
 
529
          break;
 
530
        case 5:
 
531
          GST_WRITE_UINT32_LE (&bih->bi_compression, GST_STR_FOURCC ("DX50"));
 
532
          break;
 
533
      }
 
534
    }
 
535
 
 
536
    /* process codec private/initialization data, if any */
 
537
    codec_data = gst_structure_get_value (structure, "codec_data");
 
538
    if (codec_data) {
 
539
      GstBuffer *codec_data_buf;
 
540
 
 
541
      codec_data_buf = g_value_peek_pointer (codec_data);
 
542
      size += GST_BUFFER_SIZE (codec_data_buf);
 
543
      bih = g_realloc (bih, size);
 
544
      GST_WRITE_UINT32_LE (&bih->bi_size, size);
 
545
      memcpy ((guint8 *) bih + sizeof (BITMAPINFOHEADER),
 
546
          GST_BUFFER_DATA (codec_data_buf), GST_BUFFER_SIZE (codec_data_buf));
 
547
    }
 
548
 
 
549
    context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
 
550
    context->codec_priv = (gpointer) bih;
 
551
    context->codec_priv_size = size;
534
552
 
535
553
    return TRUE;
536
554
  } else if (!strcmp (mimetype, "video/x-h264")) {
1066
1084
    gst_object_unref (peerpad);
1067
1085
  }
1068
1086
  gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
1069
 
      duration / mux->time_scale);
 
1087
      duration / gst_guint64_to_gdouble (mux->time_scale));
1070
1088
  gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
1071
 
      "GStreamer plugin version " GST_PLUGINS_GOOD_VERSION);
 
1089
      "GStreamer plugin version " PACKAGE_VERSION);
1072
1090
  if (mux->writing_app && mux->writing_app[0]) {
1073
1091
    gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
1074
1092
  }
1232
1250
    pos = mux->ebml_write->pos;
1233
1251
    gst_ebml_write_seek (ebml, mux->duration_pos);
1234
1252
    gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
1235
 
        (gdouble) duration / mux->time_scale);
 
1253
        gst_guint64_to_gdouble (duration / mux->time_scale));
1236
1254
    gst_ebml_write_seek (ebml, pos);
1237
1255
  }
1238
1256
 
1274
1292
 
1275
1293
    /* if we have a buffer check if it is better then the current best one */
1276
1294
    if (collect_pad->buffer != NULL) {
1277
 
      if (best == NULL
1278
 
          || GST_BUFFER_TIMESTAMP (collect_pad->buffer) <
1279
 
          GST_BUFFER_TIMESTAMP (best->buffer)) {
 
1295
      if (best == NULL || !GST_BUFFER_TIMESTAMP_IS_VALID (collect_pad->buffer)
 
1296
          || (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)
 
1297
              && GST_BUFFER_TIMESTAMP (collect_pad->buffer) <
 
1298
              GST_BUFFER_TIMESTAMP (best->buffer))) {
1280
1299
        best = collect_pad;
1281
1300
      }
1282
1301
    }
1285
1304
  return best;
1286
1305
}
1287
1306
 
 
1307
static gboolean
 
1308
gst_matroska_mux_stream_is_vorbis_header (GstMatroskaMux * mux,
 
1309
    GstMatroskaPad * collect_pad)
 
1310
{
 
1311
  GstMatroskaTrackAudioContext *audio_ctx;
 
1312
 
 
1313
  audio_ctx = (GstMatroskaTrackAudioContext *) collect_pad->track;
 
1314
 
 
1315
  if (collect_pad->track->type != GST_MATROSKA_TRACK_TYPE_AUDIO)
 
1316
    return FALSE;
 
1317
 
 
1318
  if (audio_ctx->first_frame != FALSE)
 
1319
    return FALSE;
 
1320
 
 
1321
  if (collect_pad->track->codec_id == NULL ||
 
1322
      strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_VORBIS))
 
1323
    return FALSE;
 
1324
 
 
1325
  /* HACK: three frame headers are counted using pos */
 
1326
  if (++collect_pad->track->pos <= 3)
 
1327
    return TRUE;
 
1328
 
 
1329
  /* 4th vorbis packet => skipped all headers */
 
1330
  collect_pad->track->pos = 0;
 
1331
  audio_ctx->first_frame = TRUE;
 
1332
  return FALSE;
 
1333
}
 
1334
 
1288
1335
 
1289
1336
/**
1290
1337
 * gst_matroska_mux_buffer_header:
1298
1345
 */
1299
1346
GstBuffer *
1300
1347
gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
1301
 
    guint16 relative_timestamp, int flags)
 
1348
    gint16 relative_timestamp, int flags)
1302
1349
{
1303
1350
  GstBuffer *hdr;
1304
1351
 
1330
1377
  GstBuffer *buf, *hdr;
1331
1378
  guint64 cluster, blockgroup;
1332
1379
  gboolean write_duration;
1333
 
  guint16 relative_timestamp;
 
1380
  gint16 relative_timestamp;
 
1381
  gint64 relative_timestamp64;
1334
1382
  guint64 block_duration;
 
1383
  gboolean is_video_keyframe = FALSE;
1335
1384
 
1336
1385
  /* write data */
1337
1386
  buf = collect_pad->buffer;
1338
1387
  collect_pad->buffer = NULL;
1339
1388
 
 
1389
  /* vorbis header are retrieved from caps and placed in CodecPrivate */
 
1390
  if (gst_matroska_mux_stream_is_vorbis_header (mux, collect_pad)) {
 
1391
    GST_LOG_OBJECT (collect_pad->collect.pad, "dropping vorbis header buffer");
 
1392
    gst_buffer_unref (buf);
 
1393
    return GST_FLOW_OK;
 
1394
  }
 
1395
 
 
1396
  /* hm, invalid timestamp (due to --to be fixed--- element upstream);
 
1397
   * this would wreak havoc with time stored in matroska file */
 
1398
  if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
 
1399
    GST_WARNING_OBJECT (collect_pad->collect.pad,
 
1400
        "Invalid buffer timestamp; dropping buffer");
 
1401
    gst_buffer_unref (buf);
 
1402
    return GST_FLOW_OK;
 
1403
  }
 
1404
 
1340
1405
  /* set the timestamp for outgoing buffers */
1341
1406
  ebml->timestamp = GST_BUFFER_TIMESTAMP (buf);
1342
1407
 
 
1408
  if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
 
1409
      !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
 
1410
    GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
 
1411
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
 
1412
    is_video_keyframe = TRUE;
 
1413
  }
 
1414
 
1343
1415
  if (mux->cluster) {
1344
 
    /* start a new cluster every two seconds */
1345
 
    if (mux->cluster_time + GST_SECOND * 2 < GST_BUFFER_TIMESTAMP (buf)) {
 
1416
    /* start a new cluster every two seconds or at keyframe */
 
1417
    if (mux->cluster_time + GST_SECOND * 2 < GST_BUFFER_TIMESTAMP (buf)
 
1418
        || is_video_keyframe) {
1346
1419
      GstMatroskaMetaSeekIndex *idx;
1347
1420
 
1348
1421
      gst_ebml_write_master_finish (ebml, mux->cluster);
1390
1463
   * for audio only files. This can be largely improved, such as doing
1391
1464
   * one for each keyframe or each second (for all-keyframe
1392
1465
   * streams), only the *first* video track. But that'll come later... */
1393
 
  if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
1394
 
      !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
 
1466
  if (is_video_keyframe) {
1395
1467
    GstMatroskaIndex *idx;
1396
1468
 
1397
1469
    if (mux->num_indexes % 32 == 0) {
1430
1502
  /* write the block, for matroska v2 use SimpleBlock if possible
1431
1503
   * one slice (*breath*).
1432
1504
   * FIXME: lacing, etc. */
1433
 
  relative_timestamp =
1434
 
      (GST_BUFFER_TIMESTAMP (buf) - mux->cluster_time) / mux->time_scale;
 
1505
  relative_timestamp64 = GST_BUFFER_TIMESTAMP (buf) - mux->cluster_time;
 
1506
  if (relative_timestamp64 >= 0) {
 
1507
    /* round the timestamp */
 
1508
    relative_timestamp64 += mux->time_scale / 2;
 
1509
  } else {
 
1510
    /* round the timestamp */
 
1511
    relative_timestamp64 -= mux->time_scale / 2;
 
1512
  }
 
1513
  relative_timestamp = relative_timestamp64 / (gint64) mux->time_scale;
1435
1514
  if (mux->matroska_version > 1 && !write_duration) {
1436
1515
    int flags =
1437
1516
        GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) ? 0 : 0x80;