Write track and segment UIDs, write muxing date, write TRACKDEFAULTDURATION for TTA audio, write BLOCKDURATION if known.

Original commit message from CVS:
Write track and segment UIDs, write muxing date, write TRACKDEFAULTDURATION for TTA audio, write BLOCKDURATION if known.
This commit is contained in:
Arwed v. Merkatz 2004-09-01 12:10:21 +00:00
parent 5488fa27bc
commit e83fb2a3c2
6 changed files with 91 additions and 9 deletions

View file

@ -1,3 +1,17 @@
2004-09-01 Arwed v. Merkatz <v.merkatz@gmx.net>
* gst/matroska/ebml-ids.h:
* gst/matroska/ebml-read.c: (gst_ebml_read_date):
* gst/matroska/ebml-write.c: (gst_ebml_write_date):
automatically convert unix time <-> ebml time when reading/writing a date
* gst/matroska/matroska-ids.h:
* gst/matroska/matroska-mux.c: (gst_matroska_mux_create_uid),
(gst_matroska_mux_reset), (gst_matroska_mux_audio_pad_link),
(gst_matroska_mux_track_header), (gst_matroska_mux_start),
(gst_matroska_mux_write_data):
Write track and segment UIDs, write muxing date, write
TRACKDEFAULTDURATION for TTA audio, write BLOCKDURATION if known.
2004-08-31 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_build_list):

View file

@ -42,6 +42,9 @@ G_BEGIN_DECLS
/* general EBML types */
#define GST_EBML_ID_VOID 0xEC
/* EbmlDate offset from the unix epoch in seconds, 2001/01/01 00:00:00 UTC */
#define GST_EBML_DATE_OFFSET 978307200
G_END_DECLS
#endif /* __GST_EBML_IDS_H__ */

View file

@ -591,13 +591,18 @@ gst_ebml_read_utf8 (GstEbmlRead * ebml, guint32 * id, gchar ** str)
}
/*
* Read the next element as a date (nanoseconds since 1/1/2000).
* Read the next element as a date.
* Returns the seconds since the unix epoch.
*/
gboolean
gst_ebml_read_date (GstEbmlRead * ebml, guint32 * id, gint64 * date)
{
return gst_ebml_read_sint (ebml, id, date);
gint64 ebml_date;
gboolean res = gst_ebml_read_sint (ebml, id, &ebml_date);
*date = (ebml_date / GST_SECOND) + GST_EBML_DATE_OFFSET;
return res;
}
/*

View file

@ -430,10 +430,11 @@ gst_ebml_write_utf8 (GstEbmlWrite * ebml, guint32 id, const gchar * str)
gst_ebml_write_ascii (ebml, id, str);
}
/* date should be in seconds since the unix epoch */
void
gst_ebml_write_date (GstEbmlWrite * ebml, guint32 id, gint64 date)
{
gst_ebml_write_sint (ebml, id, date);
gst_ebml_write_sint (ebml, id, (date - GST_EBML_DATE_OFFSET) * GST_SECOND);
}
/*

View file

@ -45,6 +45,7 @@
#define GST_MATROSKA_ID_WRITINGAPP 0x5741
#define GST_MATROSKA_ID_MUXINGAPP 0x4D80
#define GST_MATROSKA_ID_DATEUTC 0x4461
#define GST_MATROSKA_ID_SEGMENTUID 0x73A4
/* ID in the tracks master */
#define GST_MATROSKA_ID_TRACKENTRY 0xAE

View file

@ -114,6 +114,8 @@ GST_STATIC_PAD_TEMPLATE ("subtitle_%d",
GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY);
static GArray *used_uids;
/* gobject magic foo */
static void gst_matroska_mux_base_init (GstMatroskaMuxClass * klass);
static void gst_matroska_mux_class_init (GstMatroskaMuxClass * klass);
@ -139,6 +141,9 @@ static void gst_matroska_mux_get_property (GObject * object,
/* reset muxer */
static void gst_matroska_mux_reset (GstElement * element);
/* uid generation */
static guint32 gst_matroska_mux_create_uid ();
static GstEbmlWriteClass *parent_class = NULL;
/*static guint gst_matroska_mux_signals[LAST_SIGNAL] = { 0 };*/
@ -242,6 +247,28 @@ gst_matroska_mux_init (GstMatroskaMux * mux)
gst_matroska_mux_reset (GST_ELEMENT (mux));
}
static guint32
gst_matroska_mux_create_uid ()
{
guint32 uid = 0;
GRand *rand = g_rand_new ();
while (!uid) {
guint i;
uid = g_rand_int (rand);
for (i = 0; i < used_uids->len; i++) {
if (g_array_index (used_uids, guint32, i) == uid) {
uid = 0;
break;
}
}
g_array_append_val (used_uids, uid);
}
g_free (rand);
return uid;
}
static void
gst_matroska_mux_reset (GstElement * element)
{
@ -289,6 +316,13 @@ gst_matroska_mux_reset (GstElement * element)
/* reset timers */
mux->time_scale = 1000000;
mux->duration = 0;
/* reset uid array */
if (used_uids) {
g_free (used_uids);
}
/* arbitrary size, 10 should be enough in most cases */
used_uids = g_array_sized_new (FALSE, FALSE, sizeof (guint32), 10);
}
static GstPadLinkReturn
@ -468,6 +502,7 @@ gst_matroska_mux_audio_pad_link (GstPad * pad, const GstCaps * caps)
audiocontext->samplerate = samplerate;
audiocontext->channels = channels;
audiocontext->bitdepth = 0;
context->default_duration = 0;
if (!strcmp (mimetype, "audio/mpeg")) {
gint mpegversion = 0;
@ -530,6 +565,9 @@ gst_matroska_mux_audio_pad_link (GstPad * pad, const GstCaps * caps)
} else if (!strcmp (mimetype, "audio/x-raw-tta")) {
gint width;
/* TTA frame duration */
context->default_duration = 1.04489795918367346939 * GST_SECOND;
gst_structure_get_int (structure, "width", &width);
audiocontext->bitdepth = width;
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_TTA);
@ -610,16 +648,19 @@ gst_matroska_mux_track_header (GstMatroskaMux * mux,
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID,
gst_matroska_mux_create_uid ());
if (context->default_duration) {
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
context->default_duration);
}
/* type-specific stuff */
switch (context->type) {
case GST_MATROSKA_TRACK_TYPE_VIDEO:{
GstMatroskaTrackVideoContext *videocontext =
(GstMatroskaTrackVideoContext *) context;
/* framerate, but not in the video part */
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
context->default_duration);
master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
videocontext->pixel_width);
@ -697,6 +738,9 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
gint i;
guint tracknum = 1;
gdouble duration = 0;
guint32 *segment_uid = (guint32 *) g_malloc (16);
GRand *rand = g_rand_new ();
GTimeVal time = { 0, 0 };
/* we start with a EBML header */
gst_ebml_write_header (ebml, "matroska", 1);
@ -723,6 +767,12 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
/* segment info */
mux->info_pos = ebml->pos;
master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_INFO);
for (i = 0; i < 4; i++) {
segment_uid[i] = g_rand_int (rand);
}
g_free (rand);
gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
(guint8 *) segment_uid, 16);
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
mux->duration_pos = ebml->pos;
/* get duration */
@ -752,8 +802,8 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, app);
}
}
/* FIXME: how do I get this? Automatic? Via tags? */
/*gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, 0); */
g_get_current_time (&time);
gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time.tv_sec);
gst_ebml_write_master_finish (ebml, master);
/* tracks */
@ -956,6 +1006,14 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux)
GST_BUFFER_DATA (hdr)[3] = 0;
gst_ebml_write_buffer (ebml, hdr);
gst_ebml_write_buffer (ebml, buf);
if (GST_BUFFER_DURATION_IS_VALID (buf)) {
guint64 block_duration = GST_BUFFER_DURATION (buf);
if (block_duration != mux->sink[i].track->default_duration) {
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION,
block_duration / mux->time_scale);
}
}
gst_ebml_write_master_finish (ebml, blockgroup);
gst_ebml_write_master_finish (ebml, cluster);
}