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> 2004-08-31 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_build_list): * ext/alsa/gstalsamixer.c: (gst_alsa_mixer_build_list):

View file

@ -42,6 +42,9 @@ G_BEGIN_DECLS
/* general EBML types */ /* general EBML types */
#define GST_EBML_ID_VOID 0xEC #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 G_END_DECLS
#endif /* __GST_EBML_IDS_H__ */ #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 gboolean
gst_ebml_read_date (GstEbmlRead * ebml, guint32 * id, gint64 * date) 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); gst_ebml_write_ascii (ebml, id, str);
} }
/* date should be in seconds since the unix epoch */
void void
gst_ebml_write_date (GstEbmlWrite * ebml, guint32 id, gint64 date) 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_WRITINGAPP 0x5741
#define GST_MATROSKA_ID_MUXINGAPP 0x4D80 #define GST_MATROSKA_ID_MUXINGAPP 0x4D80
#define GST_MATROSKA_ID_DATEUTC 0x4461 #define GST_MATROSKA_ID_DATEUTC 0x4461
#define GST_MATROSKA_ID_SEGMENTUID 0x73A4
/* ID in the tracks master */ /* ID in the tracks master */
#define GST_MATROSKA_ID_TRACKENTRY 0xAE #define GST_MATROSKA_ID_TRACKENTRY 0xAE

View file

@ -114,6 +114,8 @@ GST_STATIC_PAD_TEMPLATE ("subtitle_%d",
GST_PAD_REQUEST, GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY); GST_STATIC_CAPS_ANY);
static GArray *used_uids;
/* gobject magic foo */ /* gobject magic foo */
static void gst_matroska_mux_base_init (GstMatroskaMuxClass * klass); static void gst_matroska_mux_base_init (GstMatroskaMuxClass * klass);
static void gst_matroska_mux_class_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 */ /* reset muxer */
static void gst_matroska_mux_reset (GstElement * element); static void gst_matroska_mux_reset (GstElement * element);
/* uid generation */
static guint32 gst_matroska_mux_create_uid ();
static GstEbmlWriteClass *parent_class = NULL; static GstEbmlWriteClass *parent_class = NULL;
/*static guint gst_matroska_mux_signals[LAST_SIGNAL] = { 0 };*/ /*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)); 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 static void
gst_matroska_mux_reset (GstElement * element) gst_matroska_mux_reset (GstElement * element)
{ {
@ -289,6 +316,13 @@ gst_matroska_mux_reset (GstElement * element)
/* reset timers */ /* reset timers */
mux->time_scale = 1000000; mux->time_scale = 1000000;
mux->duration = 0; 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 static GstPadLinkReturn
@ -468,6 +502,7 @@ gst_matroska_mux_audio_pad_link (GstPad * pad, const GstCaps * caps)
audiocontext->samplerate = samplerate; audiocontext->samplerate = samplerate;
audiocontext->channels = channels; audiocontext->channels = channels;
audiocontext->bitdepth = 0; audiocontext->bitdepth = 0;
context->default_duration = 0;
if (!strcmp (mimetype, "audio/mpeg")) { if (!strcmp (mimetype, "audio/mpeg")) {
gint mpegversion = 0; 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")) { } else if (!strcmp (mimetype, "audio/x-raw-tta")) {
gint width; gint width;
/* TTA frame duration */
context->default_duration = 1.04489795918367346939 * GST_SECOND;
gst_structure_get_int (structure, "width", &width); gst_structure_get_int (structure, "width", &width);
audiocontext->bitdepth = width; audiocontext->bitdepth = width;
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_TTA); 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_TRACKNUMBER, context->num);
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type); 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 */ /* type-specific stuff */
switch (context->type) { switch (context->type) {
case GST_MATROSKA_TRACK_TYPE_VIDEO:{ case GST_MATROSKA_TRACK_TYPE_VIDEO:{
GstMatroskaTrackVideoContext *videocontext = GstMatroskaTrackVideoContext *videocontext =
(GstMatroskaTrackVideoContext *) context; (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); master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH, gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
videocontext->pixel_width); videocontext->pixel_width);
@ -697,6 +738,9 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
gint i; gint i;
guint tracknum = 1; guint tracknum = 1;
gdouble duration = 0; 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 */ /* we start with a EBML header */
gst_ebml_write_header (ebml, "matroska", 1); gst_ebml_write_header (ebml, "matroska", 1);
@ -723,6 +767,12 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
/* segment info */ /* segment info */
mux->info_pos = ebml->pos; mux->info_pos = ebml->pos;
master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_INFO); 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); gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
mux->duration_pos = ebml->pos; mux->duration_pos = ebml->pos;
/* get duration */ /* get duration */
@ -752,8 +802,8 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, app); gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, app);
} }
} }
/* FIXME: how do I get this? Automatic? Via tags? */ g_get_current_time (&time);
/*gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, 0); */ gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time.tv_sec);
gst_ebml_write_master_finish (ebml, master); gst_ebml_write_master_finish (ebml, master);
/* tracks */ /* tracks */
@ -956,6 +1006,14 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux)
GST_BUFFER_DATA (hdr)[3] = 0; GST_BUFFER_DATA (hdr)[3] = 0;
gst_ebml_write_buffer (ebml, hdr); gst_ebml_write_buffer (ebml, hdr);
gst_ebml_write_buffer (ebml, buf); 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, blockgroup);
gst_ebml_write_master_finish (ebml, cluster); gst_ebml_write_master_finish (ebml, cluster);
} }