gst/matroska/ebml-write.c: Use GDOUBLE_TO_BE() instead of (probably slower) custom code.

Original commit message from CVS:
* gst/matroska/ebml-write.c: (gst_ebml_write_float):
Use GDOUBLE_TO_BE() instead of (probably slower) custom code.
* gst/matroska/matroska-demux.c: (gst_matroska_demux_base_init),
(gst_matroska_demux_class_init), (gst_matroska_demux_init),
(gst_matroska_track_free), (gst_matroska_demux_encoding_cmp),
(gst_matroska_demux_read_track_encodings),
(gst_matroska_demux_add_stream),
(gst_matroska_demux_handle_src_query),
(gst_matroska_demux_init_stream),
(gst_matroska_demux_parse_index_cuetrack),
(gst_matroska_demux_parse_index_pointentry),
(gst_matroska_demux_parse_info),
(gst_matroska_demux_parse_metadata_id_simple_tag),
(gst_matroska_demux_parse_metadata),
(gst_matroska_demux_add_wvpk_header), (gst_matroska_decode_buffer),
(gst_matroska_demux_parse_blockgroup_or_simpleblock),
(gst_matroska_demux_parse_cluster),
(gst_matroska_demux_parse_contents_seekentry),
(gst_matroska_demux_loop_stream_parse_id),
(gst_matroska_demux_loop), (gst_matroska_demux_video_caps),
(gst_matroska_demux_audio_caps),
(gst_matroska_demux_subtitle_caps):
* gst/matroska/matroska-demux.h:
* gst/matroska/matroska-ids.c:
(gst_matroska_track_init_subtitle_context):
* gst/matroska/matroska-ids.h:
* gst/matroska/matroska-mux.c: (gst_matroska_mux_base_init),
(gst_matroska_mux_class_init), (gst_matroska_mux_init),
(gst_matroska_mux_create_uid), (gst_matroska_mux_reset),
(gst_matroska_mux_video_pad_setcaps),
(gst_matroska_mux_audio_pad_setcaps),
(gst_matroska_mux_subtitle_pad_setcaps),
(gst_matroska_mux_request_new_pad),
(gst_matroska_mux_track_header), (gst_matroska_mux_start),
(gst_matroska_mux_write_simple_tag), (gst_matroska_mux_finish),
(gst_matroska_mux_write_data), (gst_matroska_mux_collected),
(gst_matroska_mux_set_property):
Add many FIXMEs/TODOs all over the matroska muxer and demuxer
elements, do some checks for valid values in the demuxer, handle
tracktimecodescale in the demuxer, set correct default values for all
settings in the demuxer, review and add all missing matroska
IDs and some more raw YUV formats, and some trivial cleanup.
This commit is contained in:
Sebastian Dröge 2008-06-10 10:44:53 +00:00
parent 74e9eb72c5
commit a778b414b8
7 changed files with 1023 additions and 313 deletions

View file

@ -1,3 +1,49 @@
2008-06-10 Sebastian Dröge <slomo@circular-chaos.org>
* gst/matroska/ebml-write.c: (gst_ebml_write_float):
Use GDOUBLE_TO_BE() instead of (probably slower) custom code.
* gst/matroska/matroska-demux.c: (gst_matroska_demux_base_init),
(gst_matroska_demux_class_init), (gst_matroska_demux_init),
(gst_matroska_track_free), (gst_matroska_demux_encoding_cmp),
(gst_matroska_demux_read_track_encodings),
(gst_matroska_demux_add_stream),
(gst_matroska_demux_handle_src_query),
(gst_matroska_demux_init_stream),
(gst_matroska_demux_parse_index_cuetrack),
(gst_matroska_demux_parse_index_pointentry),
(gst_matroska_demux_parse_info),
(gst_matroska_demux_parse_metadata_id_simple_tag),
(gst_matroska_demux_parse_metadata),
(gst_matroska_demux_add_wvpk_header), (gst_matroska_decode_buffer),
(gst_matroska_demux_parse_blockgroup_or_simpleblock),
(gst_matroska_demux_parse_cluster),
(gst_matroska_demux_parse_contents_seekentry),
(gst_matroska_demux_loop_stream_parse_id),
(gst_matroska_demux_loop), (gst_matroska_demux_video_caps),
(gst_matroska_demux_audio_caps),
(gst_matroska_demux_subtitle_caps):
* gst/matroska/matroska-demux.h:
* gst/matroska/matroska-ids.c:
(gst_matroska_track_init_subtitle_context):
* gst/matroska/matroska-ids.h:
* gst/matroska/matroska-mux.c: (gst_matroska_mux_base_init),
(gst_matroska_mux_class_init), (gst_matroska_mux_init),
(gst_matroska_mux_create_uid), (gst_matroska_mux_reset),
(gst_matroska_mux_video_pad_setcaps),
(gst_matroska_mux_audio_pad_setcaps),
(gst_matroska_mux_subtitle_pad_setcaps),
(gst_matroska_mux_request_new_pad),
(gst_matroska_mux_track_header), (gst_matroska_mux_start),
(gst_matroska_mux_write_simple_tag), (gst_matroska_mux_finish),
(gst_matroska_mux_write_data), (gst_matroska_mux_collected),
(gst_matroska_mux_set_property):
Add many FIXMEs/TODOs all over the matroska muxer and demuxer
elements, do some checks for valid values in the demuxer, handle
tracktimecodescale in the demuxer, set correct default values for all
settings in the demuxer, review and add all missing matroska
IDs and some more raw YUV formats, and some trivial cleanup.
2008-06-10 Sebastian Dröge <slomo@circular-chaos.org> 2008-06-10 Sebastian Dröge <slomo@circular-chaos.org>
* ext/pulse/pulsemixer.c: (gst_pulsemixer_base_init), * ext/pulse/pulsemixer.c: (gst_pulsemixer_base_init),

View file

@ -25,6 +25,7 @@
#endif #endif
#include <string.h> #include <string.h>
#include <gst/floatcast/floatcast.h>
#include "ebml-write.h" #include "ebml-write.h"
#include "ebml-ids.h" #include "ebml-ids.h"
@ -541,21 +542,12 @@ gst_ebml_write_sint (GstEbmlWrite * ebml, guint32 id, gint64 num)
void void
gst_ebml_write_float (GstEbmlWrite * ebml, guint32 id, gdouble num) gst_ebml_write_float (GstEbmlWrite * ebml, guint32 id, gdouble num)
{ {
#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
gint n;
#endif
GstBuffer *buf = gst_ebml_write_element_new (ebml, sizeof (num)); GstBuffer *buf = gst_ebml_write_element_new (ebml, sizeof (num));
gst_ebml_write_element_id (buf, id); gst_ebml_write_element_id (buf, id);
gst_ebml_write_element_size (buf, 8); gst_ebml_write_element_size (buf, 8);
#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) num = GDOUBLE_TO_BE (num);
for (n = 0; n < 8; n++) {
GST_BUFFER_DATA (buf)[GST_BUFFER_SIZE (buf)] = ((guint8 *) & num)[7 - n];
GST_BUFFER_SIZE (buf) += 1;
}
#else
gst_ebml_write_element_data (buf, (guint8 *) & num, 8); gst_ebml_write_element_data (buf, (guint8 *) & num, 8);
#endif
gst_ebml_write_element_push (ebml, buf); gst_ebml_write_element_push (ebml, buf);
} }

File diff suppressed because it is too large Load diff

View file

@ -40,7 +40,9 @@ G_BEGIN_DECLS
#define GST_IS_MATROSKA_DEMUX_CLASS(klass) \ #define GST_IS_MATROSKA_DEMUX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MATROSKA_DEMUX)) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MATROSKA_DEMUX))
#define GST_MATROSKA_DEMUX_MAX_STREAMS 64 /* The spec says that more than 127 stream is discouraged so
* take this as a limit for now */
#define GST_MATROSKA_DEMUX_MAX_STREAMS 127
typedef enum { typedef enum {
GST_MATROSKA_DEMUX_STATE_START, GST_MATROSKA_DEMUX_STATE_START,

View file

@ -109,25 +109,3 @@ gst_matroska_track_init_subtitle_context (GstMatroskaTrackContext ** p_context)
subtitle_context->invalid_utf8 = FALSE; subtitle_context->invalid_utf8 = FALSE;
return TRUE; return TRUE;
} }
gboolean
gst_matroska_track_init_complex_context (GstMatroskaTrackContext ** p_context)
{
GstMatroskaTrackComplexContext *complex_context;
g_assert (p_context != NULL && *p_context != NULL);
/* already set up? (track info might come before track type) */
if ((*p_context)->type == GST_MATROSKA_TRACK_TYPE_COMPLEX)
return TRUE;
/* it better not have been set up as some other track type ... */
if ((*p_context)->type != 0) {
g_return_val_if_reached (FALSE);
}
complex_context = g_renew (GstMatroskaTrackComplexContext, *p_context, 1);
*p_context = (GstMatroskaTrackContext *) complex_context;
(*p_context)->type = GST_MATROSKA_TRACK_TYPE_COMPLEX;
return TRUE;
}

View file

@ -30,117 +30,289 @@
* Matroska element IDs. max. 32-bit. * Matroska element IDs. max. 32-bit.
*/ */
/* toplevel segment */ /* toplevel Segment */
#define GST_MATROSKA_ID_SEGMENT 0x18538067 #define GST_MATROSKA_ID_SEGMENT 0x18538067
/* matroska top-level master IDs */ /* matroska top-level master IDs, childs of Segment */
#define GST_MATROSKA_ID_INFO 0x1549A966 #define GST_MATROSKA_ID_SEGMENTINFO 0x1549A966
#define GST_MATROSKA_ID_TRACKS 0x1654AE6B #define GST_MATROSKA_ID_TRACKS 0x1654AE6B
#define GST_MATROSKA_ID_CUES 0x1C53BB6B #define GST_MATROSKA_ID_CUES 0x1C53BB6B
#define GST_MATROSKA_ID_TAGS 0x1254C367 #define GST_MATROSKA_ID_TAGS 0x1254C367
#define GST_MATROSKA_ID_SEEKHEAD 0x114D9B74 #define GST_MATROSKA_ID_SEEKHEAD 0x114D9B74
#define GST_MATROSKA_ID_CLUSTER 0x1F43B675 #define GST_MATROSKA_ID_CLUSTER 0x1F43B675
#define GST_MATROSKA_ID_ATTACHMENTS 0x1941A469
#define GST_MATROSKA_ID_CHAPTERS 0x1043A770
/* IDs in the info master */ /* IDs in the SegmentInfo master */
#define GST_MATROSKA_ID_TIMECODESCALE 0x2AD7B1 #define GST_MATROSKA_ID_TIMECODESCALE 0x2AD7B1
#define GST_MATROSKA_ID_DURATION 0x4489 #define GST_MATROSKA_ID_DURATION 0x4489
#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 #define GST_MATROSKA_ID_SEGMENTUID 0x73A4
#define GST_MATROSKA_ID_SEGMENTFILENAME 0x7384
#define GST_MATROSKA_ID_PREVUID 0x3CB923
#define GST_MATROSKA_ID_PREVFILENAME 0x3C83AB
#define GST_MATROSKA_ID_NEXTUID 0x3EB923
#define GST_MATROSKA_ID_NEXTFILENAME 0x3E83BB
#define GST_MATROSKA_ID_TITLE 0x7BA9
#define GST_MATROSKA_ID_SEGMENTFAMILY 0x4444
#define GST_MATROSKA_ID_CHAPTERTRANSLATE 0x6924
/* ID in the tracks master */ /* IDs in the ChapterTranslate master */
#define GST_MATROSKA_ID_TRACKENTRY 0xAE #define GST_MATROSKA_ID_CHAPTERTRANSLATEEDITIONUID 0x69FC
#define GST_MATROSKA_ID_CHAPTERTRANSLATECODEC 0x69BF
#define GST_MATROSKA_ID_CHAPTERTRANSLATEID 0x69A5
/* IDs in the trackentry master */ /* ID in the Tracks master */
#define GST_MATROSKA_ID_TRACKNUMBER 0xD7 #define GST_MATROSKA_ID_TRACKENTRY 0xAE
#define GST_MATROSKA_ID_TRACKUID 0x73C5
#define GST_MATROSKA_ID_TRACKTYPE 0x83
#define GST_MATROSKA_ID_TRACKAUDIO 0xE1
#define GST_MATROSKA_ID_TRACKVIDEO 0xE0
#define GST_MATROSKA_ID_CODECID 0x86
#define GST_MATROSKA_ID_CODECPRIVATE 0x63A2
#define GST_MATROSKA_ID_CODECNAME 0x258688
#define GST_MATROSKA_ID_CODECINFOURL 0x3B4040
#define GST_MATROSKA_ID_CODECDOWNLOADURL 0x26B240
#define GST_MATROSKA_ID_TRACKNAME 0x536E
#define GST_MATROSKA_ID_TRACKLANGUAGE 0x22B59C
#define GST_MATROSKA_ID_TRACKFLAGENABLED 0xB9
#define GST_MATROSKA_ID_TRACKFLAGDEFAULT 0x88
#define GST_MATROSKA_ID_TRACKFLAGLACING 0x9C
#define GST_MATROSKA_ID_TRACKMINCACHE 0x6DE7
#define GST_MATROSKA_ID_TRACKMAXCACHE 0x6DF8
#define GST_MATROSKA_ID_TRACKDEFAULTDURATION 0x23E383
#define GST_MATROSKA_ID_CONTENTENCODINGS 0x6D80
/* IDs in the trackvideo master */ /* IDs in the TrackEntry master */
#define GST_MATROSKA_ID_VIDEOFRAMERATE 0x2383E3 #define GST_MATROSKA_ID_TRACKNUMBER 0xD7
#define GST_MATROSKA_ID_VIDEODISPLAYWIDTH 0x54B0 #define GST_MATROSKA_ID_TRACKUID 0x73C5
#define GST_MATROSKA_ID_VIDEODISPLAYHEIGHT 0x54BA #define GST_MATROSKA_ID_TRACKTYPE 0x83
#define GST_MATROSKA_ID_VIDEOPIXELWIDTH 0xB0 #define GST_MATROSKA_ID_TRACKAUDIO 0xE1
#define GST_MATROSKA_ID_VIDEOPIXELHEIGHT 0xBA #define GST_MATROSKA_ID_TRACKVIDEO 0xE0
#define GST_MATROSKA_ID_VIDEOFLAGINTERLACED 0x9A #define GST_MATROSKA_ID_CONTENTENCODINGS 0x6D80
#define GST_MATROSKA_ID_VIDEOSTEREOMODE 0x53B9 #define GST_MATROSKA_ID_CODECID 0x86
#define GST_MATROSKA_ID_VIDEOASPECTRATIO 0x54B3 #define GST_MATROSKA_ID_CODECPRIVATE 0x63A2
#define GST_MATROSKA_ID_VIDEOCOLOURSPACE 0x2EB524 #define GST_MATROSKA_ID_CODECNAME 0x258688
#define GST_MATROSKA_ID_TRACKNAME 0x536E
#define GST_MATROSKA_ID_TRACKLANGUAGE 0x22B59C
#define GST_MATROSKA_ID_TRACKFLAGENABLED 0xB9
#define GST_MATROSKA_ID_TRACKFLAGDEFAULT 0x88
#define GST_MATROSKA_ID_TRACKFLAGFORCED 0x55AA
#define GST_MATROSKA_ID_TRACKFLAGLACING 0x9C
#define GST_MATROSKA_ID_TRACKMINCACHE 0x6DE7
#define GST_MATROSKA_ID_TRACKMAXCACHE 0x6DF8
#define GST_MATROSKA_ID_TRACKDEFAULTDURATION 0x23E383
#define GST_MATROSKA_ID_TRACKTIMECODESCALE 0x23314F
#define GST_MATROSKA_ID_MAXBLOCKADDITIONID 0x55EE
#define GST_MATROSKA_ID_TRACKATTACHMENTLINK 0x7446
#define GST_MATROSKA_ID_TRACKOVERLAY 0x6FAB
#define GST_MATROSKA_ID_TRACKTRANSLATE 0x6624
/* semi-draft */
#define GST_MATROSKA_ID_TRACKOFFSET 0x537F
/* semi-draft */
#define GST_MATROSKA_ID_CODECSETTINGS 0x3A9697
/* semi-draft */
#define GST_MATROSKA_ID_CODECINFOURL 0x3B4040
/* semi-draft */
#define GST_MATROSKA_ID_CODECDOWNLOADURL 0x26B240
/* semi-draft */
#define GST_MATROSKA_ID_CODECDECODEALL 0xAA
/* IDs in the trackaudio master */ /* IDs in the TrackTranslate master */
#define GST_MATROSKA_ID_AUDIOSAMPLINGFREQ 0xB5 #define GST_MATROSKA_ID_TRACKTRANSLATEEDITIONUID 0x66FC
#define GST_MATROSKA_ID_AUDIOBITDEPTH 0x6264 #define GST_MATROSKA_ID_TRACKTRANSLATECODEC 0x66BF
#define GST_MATROSKA_ID_AUDIOCHANNELS 0x9F #define GST_MATROSKA_ID_TRACKTRANSLATETRACKID 0x66A5
/* ID in the cues master */
#define GST_MATROSKA_ID_POINTENTRY 0xBB /* IDs in the TrackVideo master */
/* NOTE: This one is here only for backward compatibility.
* Use _TRACKDEFAULDURATION */
#define GST_MATROSKA_ID_VIDEOFRAMERATE 0x2383E3
#define GST_MATROSKA_ID_VIDEODISPLAYWIDTH 0x54B0
#define GST_MATROSKA_ID_VIDEODISPLAYHEIGHT 0x54BA
#define GST_MATROSKA_ID_VIDEODISPLAYUNIT 0x54B2
#define GST_MATROSKA_ID_VIDEOPIXELWIDTH 0xB0
#define GST_MATROSKA_ID_VIDEOPIXELHEIGHT 0xBA
#define GST_MATROSKA_ID_VIDEOPIXELCROPBOTTOM 0x54AA
#define GST_MATROSKA_ID_VIDEOPIXELCROPTOP 0x54BB
#define GST_MATROSKA_ID_VIDEOPIXELCROPLEFT 0x54CC
#define GST_MATROSKA_ID_VIDEOPIXELCROPRIGHT 0x54DD
#define GST_MATROSKA_ID_VIDEOFLAGINTERLACED 0x9A
/* semi-draft */
#define GST_MATROSKA_ID_VIDEOSTEREOMODE 0x53B8
#define GST_MATROSKA_ID_VIDEOASPECTRATIOTYPE 0x54B3
#define GST_MATROSKA_ID_VIDEOCOLOURSPACE 0x2EB524
/* semi-draft */
#define GST_MATROSKA_ID_VIDEOGAMMAVALUE 0x2FB523
/* IDs in the TrackAudio master */
#define GST_MATROSKA_ID_AUDIOSAMPLINGFREQ 0xB5
#define GST_MATROSKA_ID_AUDIOBITDEPTH 0x6264
#define GST_MATROSKA_ID_AUDIOCHANNELS 0x9F
/* semi-draft */
#define GST_MATROSKA_ID_AUDIOCHANNELPOSITIONS 0x7D7B
#define GST_MATROSKA_ID_AUDIOOUTPUTSAMPLINGFREQ 0x78B5
/* IDs in the TrackContentEncoding master */
#define GST_MATROSKA_ID_CONTENTENCODING 0x6240
/* IDs in the ContentEncoding master */
#define GST_MATROSKA_ID_CONTENTENCODINGORDER 0x5031
#define GST_MATROSKA_ID_CONTENTENCODINGSCOPE 0x5032
#define GST_MATROSKA_ID_CONTENTENCODINGTYPE 0x5033
#define GST_MATROSKA_ID_CONTENTCOMPRESSION 0x5034
#define GST_MATROSKA_ID_CONTENTENCRYPTION 0x5035
/* IDs in the ContentCompression master */
#define GST_MATROSKA_ID_CONTENTCOMPALGO 0x4254
#define GST_MATROSKA_ID_CONTENTCOMPSETTINGS 0x4255
/* IDs in the ContentEncryption master */
#define GST_MATROSKA_ID_CONTENTENCALGO 0x47E1
#define GST_MATROSKA_ID_CONTENTENCKEYID 0x47E2
#define GST_MATROSKA_ID_CONTENTSIGNATURE 0x47E3
#define GST_MATROSKA_ID_CONTENTSIGKEYID 0x47E4
#define GST_MATROSKA_ID_CONTENTSIGALGO 0x47E5
#define GST_MATROSKA_ID_CONTENTSIGHASHALGO 0x47E6
/* ID in the CUEs master */
#define GST_MATROSKA_ID_POINTENTRY 0xBB
/* IDs in the pointentry master */ /* IDs in the pointentry master */
#define GST_MATROSKA_ID_CUETIME 0xB3 #define GST_MATROSKA_ID_CUETIME 0xB3
#define GST_MATROSKA_ID_CUETRACKPOSITION 0xB7 #define GST_MATROSKA_ID_CUETRACKPOSITIONS 0xB7
/* IDs in the cuetrackposition master */ /* IDs in the CueTrackPositions master */
#define GST_MATROSKA_ID_CUETRACK 0xF7 #define GST_MATROSKA_ID_CUETRACK 0xF7
#define GST_MATROSKA_ID_CUECLUSTERPOSITION 0xF1 #define GST_MATROSKA_ID_CUECLUSTERPOSITION 0xF1
#define GST_MATROSKA_ID_CUEBLOCKNUMBER 0x5378
/* semi-draft */
#define GST_MATROSKA_ID_CUECODECSTATE 0xEA
/* semi-draft */
#define GST_MATROSKA_ID_CUEREFERENCE 0xDB
/* IDs in the tags master */ /* IDs in the CueReference master */
#define GST_MATROSKA_ID_TAG 0x7373 /* semi-draft */
#define GST_MATROSKA_ID_CUEREFTIME 0x96
/* semi-draft */
#define GST_MATROSKA_ID_CUEREFCLUSTER 0x97
/* semi-draft */
#define GST_MATROSKA_ID_CUEREFNUMBER 0x535F
/* semi-draft */
#define GST_MATROSKA_ID_CUEREFCODECSTATE 0xEB
/* in the tag master */ /* IDs in the Tags master */
#define GST_MATROSKA_ID_SIMPLETAG 0x67C8 #define GST_MATROSKA_ID_TAG 0x7373
/* in the simpletag master */ /* in the Tag master */
#define GST_MATROSKA_ID_TAGNAME 0x45A3 #define GST_MATROSKA_ID_SIMPLETAG 0x67C8
#define GST_MATROSKA_ID_TAGSTRING 0x4487 #define GST_MATROSKA_ID_TARGETS 0x63C0
/* IDs in the seekhead master */ /* in the SimpleTag master */
#define GST_MATROSKA_ID_SEEKENTRY 0x4DBB #define GST_MATROSKA_ID_TAGNAME 0x45A3
#define GST_MATROSKA_ID_TAGSTRING 0x4487
#define GST_MATROSKA_ID_TAGLANGUAGE 0x447A
#define GST_MATROSKA_ID_TAGDEFAULT 0x4484
#define GST_MATROSKA_ID_TAGBINARY 0x4485
/* IDs in the seekpoint master */ /* in the Targets master */
#define GST_MATROSKA_ID_SEEKID 0x53AB #define GST_MATROSKA_ID_TARGETTYPEVALUE 0x68CA
#define GST_MATROSKA_ID_SEEKPOSITION 0x53AC #define GST_MATROSKA_ID_TARGETTYPE 0x63CA
#define GST_MATROSKA_ID_TARGETTRACKUID 0x63C5
#define GST_MATROSKA_ID_TARGETEDITIONUID 0x63C5
#define GST_MATROSKA_ID_TARGETCHAPTERUID 0x63C4
#define GST_MATROSKA_ID_TARGETATTACHMENTUID 0x63C6
/* IDs in the cluster master */ /* IDs in the SeekHead master */
#define GST_MATROSKA_ID_CLUSTERTIMECODE 0xE7 #define GST_MATROSKA_ID_SEEKENTRY 0x4DBB
#define GST_MATROSKA_ID_BLOCKGROUP 0xA0
#define GST_MATROSKA_ID_SIMPLEBLOCK 0xA3
#define GST_MATROSKA_ID_REFERENCEBLOCK 0xFB
/* IDs in the blockgroup master */ /* IDs in the SeekEntry master */
#define GST_MATROSKA_ID_BLOCK 0xA1 #define GST_MATROSKA_ID_SEEKID 0x53AB
#define GST_MATROSKA_ID_BLOCKDURATION 0x9B #define GST_MATROSKA_ID_SEEKPOSITION 0x53AC
/* IDs in the contentencodings master */ /* IDs in the Cluster master */
#define GST_MATROSKA_ID_CONTENTENCODING 0x6240 #define GST_MATROSKA_ID_CLUSTERTIMECODE 0xE7
#define GST_MATROSKA_ID_BLOCKGROUP 0xA0
#define GST_MATROSKA_ID_SIMPLEBLOCK 0xA3
#define GST_MATROSKA_ID_REFERENCEBLOCK 0xFB
#define GST_MATROSKA_ID_POSITION 0xA7
#define GST_MATROSKA_ID_PREVSIZE 0xAB
/* semi-draft */
#define GST_MATROSKA_ID_ENCRYPTEDBLOCK 0xAF
#define GST_MATROSKA_ID_SILENTTRACKS 0x5854
/* IDS IN THE CONTENTENCODING MASTER */ /* IDs in the SilentTracks master */
#define GST_MATROSKA_ID_CONTENTENCODINGORDER 0X5031 #define GST_MATROSKA_ID_SILENTTRACKNUMBER 0x58D7
#define GST_MATROSKA_ID_CONTENTENCODINGSCOPE 0X5032
#define GST_MATROSKA_ID_CONTENTENCODINGTYPE 0X5033
#define GST_MATROSKA_ID_CONTENTCOMPRESSION 0X5034
#define GST_MATROSKA_ID_CONTENTENCRYPTION 0X5035
/* IDS IN THE CONTENTCOMPRESSION MASTER */ /* IDs in the BlockGroup master */
#define GST_MATROSKA_ID_CONTENTCOMPALGO 0X4254 #define GST_MATROSKA_ID_BLOCK 0xA1
#define GST_MATROSKA_ID_CONTENTCOMPSETTINGS 0X4255 #define GST_MATROSKA_ID_BLOCKDURATION 0x9B
/* semi-draft */
#define GST_MATROSKA_ID_BLOCKVIRTUAL 0xA2
#define GST_MATROSKA_ID_REFERENCEBLOCK 0xFB
#define GST_MATROSKA_ID_BLOCKADDITIONS 0x75A1
#define GST_MATROSKA_ID_REFERENCEPRIORITY 0xFA
/* semi-draft */
#define GST_MATROSKA_ID_REFERENCEVIRTUAL 0xFD
/* semi-draft */
#define GST_MATROSKA_ID_CODECSTATE 0xA4
#define GST_MATROSKA_ID_SLICES 0x8E
/* IDs in the BlockAdditions master */
#define GST_MATROSKA_ID_BLOCKMORE 0xA6
/* IDs in the BlockMore master */
#define GST_MATROSKA_ID_BLOCKADDID 0xEE
#define GST_MATROSKA_ID_BLOCKADDITIONAL 0xA5
/* IDs in the Slices master */
#define GST_MATROSKA_ID_TIMESLICE 0xE8
/* IDs in the TimeSlice master */
#define GST_MATROSKA_ID_LACENUMBER 0xCC
/* semi-draft */
#define GST_MATROSKA_ID_FRAMENUMBER 0xCD
/* semi-draft */
#define GST_MATROSKA_ID_BLOCKADDITIONID 0xCB
/* semi-draft */
#define GST_MATROSKA_ID_TIMESLICEDELAY 0xCE
#define GST_MATROSKA_ID_TIMESLICEDURATION 0xCF
/* IDs in the Attachments master */
#define GST_MATROSKA_ID_ATTACHEDFILE 0x61A7
/* IDs in the AttachedFile master */
#define GST_MATROSKA_ID_FILEDESCRIPTION 0x467E
#define GST_MATROSKA_ID_FILENAME 0x466E
#define GST_MATROSKA_ID_FILEMIMETYPE 0x4660
#define GST_MATROSKA_ID_FILEDATA 0x465C
#define GST_MATROSKA_ID_FILEUID 0x46AE
/* semi-draft */
#define GST_MATROSKA_ID_FILEREFERRAL 0x4675
/* IDs in the Chapters master */
#define GST_MATROSKA_ID_EDITIONENTRY 0x45B9
/* IDs in the EditionEntry master */
#define GST_MATROSKA_ID_EDITIONUID 0x45BC
#define GST_MATROSKA_ID_EDITIONFLAGHIDDEN 0x45BD
#define GST_MATROSKA_ID_EDITIONFLAGDEFAULT 0x45DB
#define GST_MATROSKA_ID_EDITIONFLAGORDERED 0x45DD
#define GST_MATROSKA_ID_CHAPTERATOM 0xB6
/* IDs in the ChapterAtom master */
#define GST_MATROSKA_ID_CHAPTERUID 0x73C4
#define GST_MATROSKA_ID_CHAPTERTIMESTART 0x91
#define GST_MATROSKA_ID_CHAPTERTIMESTOP 0x92
#define GST_MATROSKA_ID_CHAPTERFLAGHIDDEN 0x98
#define GST_MATROSKA_ID_CHAPTERFLAGENABLED 0x4598
#define GST_MATROSKA_ID_CHAPTERSEGMENTUID 0x6E67
#define GST_MATROSKA_ID_CHAPTERSEGMENTEDITIONUID 0x6EBC
#define GST_MATROSKA_ID_CHAPTERPHYSICALEQUIV 0x63C3
#define GST_MATROSKA_ID_CHAPTERTRACK 0x8F
#define GST_MATROSKA_ID_CHAPTERDISPLAY 0x80
#define GST_MATROSKA_ID_CHAPPROCESS 0x6944
/* IDs in the ChapProcess master */
#define GST_MATROSKA_ID_CHAPPROCESSCODECID 0x6955
#define GST_MATROSKA_ID_CHAPPROCESSPRIVATE 0x450D
#define GST_MATROSKA_ID_CHAPPROCESSCOMMAND 0x6911
/* IDs in the ChapProcessCommand master */
#define GST_MATROSKA_ID_CHAPPROCESSTIME 0x6922
#define GST_MATROSKA_ID_CHAPPROCESSDATA 0x6933
/* IDs in the ChapterDisplay master */
#define GST_MATROSKA_ID_CHAPSTRING 0x85
#define GST_MATROSKA_ID_CHAPLANGUAGE 0x437C
#define GST_MATROSKA_ID_CHAPCOUNTRY 0x437E
/* IDs in the ChapterTrack master */
#define GST_MATROSKA_ID_CHAPTERTRACKNUMBER 0x89
/* /*
* Matroska Codec IDs. Strings. * Matroska Codec IDs. Strings.
@ -155,49 +327,61 @@
#define GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3 "V_MPEG4/MS/V3" #define GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3 "V_MPEG4/MS/V3"
#define GST_MATROSKA_CODEC_ID_VIDEO_MPEG1 "V_MPEG1" #define GST_MATROSKA_CODEC_ID_VIDEO_MPEG1 "V_MPEG1"
#define GST_MATROSKA_CODEC_ID_VIDEO_MPEG2 "V_MPEG2" #define GST_MATROSKA_CODEC_ID_VIDEO_MPEG2 "V_MPEG2"
/* FIXME: not (yet) in the spec! */
#define GST_MATROSKA_CODEC_ID_VIDEO_MJPEG "V_MJPEG" #define GST_MATROSKA_CODEC_ID_VIDEO_MJPEG "V_MJPEG"
#define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1 "V_REAL/RV10" #define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1 "V_REAL/RV10"
#define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2 "V_REAL/RV20" #define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2 "V_REAL/RV20"
#define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3 "V_REAL/RV30" #define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3 "V_REAL/RV30"
#define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4 "V_REAL/RV40" #define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4 "V_REAL/RV40"
#define GST_MATROSKA_CODEC_ID_VIDEO_THEORA "V_THEORA" #define GST_MATROSKA_CODEC_ID_VIDEO_THEORA "V_THEORA"
#define GST_MATROSKA_CODEC_ID_VIDEO_QUICKTIME "V_QUICKTIME"
#define GST_MATROSKA_CODEC_ID_VIDEO_SNOW "V_SNOW"
#define GST_MATROSKA_CODEC_ID_VIDEO_DIRAC "V_DIRAC" #define GST_MATROSKA_CODEC_ID_VIDEO_DIRAC "V_DIRAC"
/* TODO: Quicktime */
#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1 "A_MPEG/L1" #define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1 "A_MPEG/L1"
#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2 "A_MPEG/L2" #define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2 "A_MPEG/L2"
#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3 "A_MPEG/L3" #define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3 "A_MPEG/L3"
#define GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE "A_PCM/INT/BIG" #define GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE "A_PCM/INT/BIG"
#define GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE "A_PCM/INT/LIT" #define GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE "A_PCM/INT/LIT"
#define GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT "A_PCM/FLOAT/IEEE" #define GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT "A_PCM/FLOAT/IEEE"
#define GST_MATROSKA_CODEC_ID_AUDIO_AC3 "A_AC3" #define GST_MATROSKA_CODEC_ID_AUDIO_AC3 "A_AC3"
#define GST_MATROSKA_CODEC_ID_AUDIO_DTS "A_DTS" #define GST_MATROSKA_CODEC_ID_AUDIO_AC3_BSID9 "A_AC3/BSID9"
#define GST_MATROSKA_CODEC_ID_AUDIO_VORBIS "A_VORBIS" #define GST_MATROSKA_CODEC_ID_AUDIO_AC3_BSID10 "A_AC3/BSID10"
#define GST_MATROSKA_CODEC_ID_AUDIO_FLAC "A_FLAC" #define GST_MATROSKA_CODEC_ID_AUDIO_DTS "A_DTS"
#define GST_MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM" #define GST_MATROSKA_CODEC_ID_AUDIO_VORBIS "A_VORBIS"
#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG2 "A_AAC/MPEG2/" #define GST_MATROSKA_CODEC_ID_AUDIO_FLAC "A_FLAC"
#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG4 "A_AAC/MPEG4/" #define GST_MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM"
#define GST_MATROSKA_CODEC_ID_AUDIO_TTA "A_TTA1" #define GST_MATROSKA_CODEC_ID_AUDIO_TTA "A_TTA1"
#define GST_MATROSKA_CODEC_ID_AUDIO_WAVPACK4 "A_WAVPACK4" #define GST_MATROSKA_CODEC_ID_AUDIO_WAVPACK4 "A_WAVPACK4"
#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4 "A_REAL/28_8" #define GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4 "A_REAL/14_4"
#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8 "A_REAL/28_8" #define GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8 "A_REAL/28_8"
#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK "A_REAL/COOK" #define GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK "A_REAL/COOK"
#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_SIPR "A_REAL/SIPR" #define GST_MATROSKA_CODEC_ID_AUDIO_REAL_SIPR "A_REAL/SIPR"
#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_RALF "A_REAL/RALF" #define GST_MATROSKA_CODEC_ID_AUDIO_REAL_RALF "A_REAL/RALF"
#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_ATRC "A_REAL/ATRC" #define GST_MATROSKA_CODEC_ID_AUDIO_REAL_ATRC "A_REAL/ATRC"
#define GST_MATROSKA_CODEC_ID_AUDIO_AAC "A_AAC"
/* TODO: AC3-9/10 (?), Musepack, Quicktime */ #define GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG2 "A_AAC/MPEG2/"
#define GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4 "A_AAC/MPEG4/"
#define GST_MATROSKA_CODEC_ID_AUDIO_QUICKTIME_QDMC "A_QUICKTIME/QDMC"
#define GST_MATROSKA_CODEC_ID_AUDIO_QUICKTIME_QDM2 "A_QUICKTIME/QDM2"
/* Undefined for now:
#define GST_MATROSKA_CODEC_ID_AUDIO_MPC "A_MPC"
*/
#define GST_MATROSKA_CODEC_ID_SUBTITLE_ASCII "S_TEXT/ASCII"
#define GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8 "S_TEXT/UTF8" #define GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8 "S_TEXT/UTF8"
#define GST_MATROSKA_CODEC_ID_SUBTITLE_SSA "S_TEXT/SSA" #define GST_MATROSKA_CODEC_ID_SUBTITLE_SSA "S_TEXT/SSA"
#define GST_MATROSKA_CODEC_ID_SUBTITLE_ASS "S_TEXT/ASS" #define GST_MATROSKA_CODEC_ID_SUBTITLE_ASS "S_TEXT/ASS"
#define GST_MATROSKA_CODEC_ID_SUBTITLE_USF "S_TEXT/USF" #define GST_MATROSKA_CODEC_ID_SUBTITLE_USF "S_TEXT/USF"
#define GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB "S_VOBSUB" #define GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB "S_VOBSUB"
#define GST_MATROSKA_CODEC_ID_SUBTITLE_BMP "S_IMAGE/BMP"
/* /*
* Matrodka tags. Strings. * Matroska tags. Strings.
*/ */
/* TODO: check for other tags */
#define GST_MATROSKA_TAG_ID_TITLE "TITLE" #define GST_MATROSKA_TAG_ID_TITLE "TITLE"
#define GST_MATROSKA_TAG_ID_AUTHOR "AUTHOR" #define GST_MATROSKA_TAG_ID_AUTHOR "AUTHOR"
#define GST_MATROSKA_TAG_ID_ALBUM "ALBUM" #define GST_MATROSKA_TAG_ID_ALBUM "ALBUM"
@ -208,6 +392,30 @@
#define GST_MATROSKA_TAG_ID_ISRC "ISRC" #define GST_MATROSKA_TAG_ID_ISRC "ISRC"
#define GST_MATROSKA_TAG_ID_COPYRIGHT "COPYRIGHT" #define GST_MATROSKA_TAG_ID_COPYRIGHT "COPYRIGHT"
/*
* TODO: add this tag & mappings
* "URL" -> GST_TAG_LOCATION
* "BPS" -> GST_TAG_BITRATE
* "BPM" -> GST_TAG_BEATS_PER_MINUTE
* "REPLAYGAIN_GAIN" -> GST_TAG_*_GAIN see http://replaygain.hydrogenaudio.org/rg_data_format.html
* "REPLAYGAIN_PEAK" -> GST_TAG_*_PEAK see http://replaygain.hydrogenaudio.org/peak_data_format.html
* "TERMS_OF_USE" -> GST_TAG_LICENSE
* "DATE_RECORDED" -> GST_TAG_DATE
* "COMPOSER" -> GST_TAG_COMPOSER
* "LEAD_PERFORMER" -> GST_TAG_PERFORMER
* "GENRE" -> GST_TAG_GENRE
*
* "TOTAL_PARTS" -> GST_TAG_TRACK_COUNT depending on target
* "PART_NUMBER" -> GST_TAG_TRACK_NUMBER depending on target
*
* "EMAIL" ->
* "ADDRESS" ->
* "FAX" -> GST_TAG_CONTACT
* "PHONE" ->
*
* TODO: maybe add custom gstreamer tags for other standard matroska tags
*/
/* /*
* Enumerations for various types (mapping from binary * Enumerations for various types (mapping from binary
* value to what it actually means). * value to what it actually means).
@ -219,6 +427,7 @@ typedef enum {
GST_MATROSKA_TRACK_TYPE_COMPLEX = 0x3, GST_MATROSKA_TRACK_TYPE_COMPLEX = 0x3,
GST_MATROSKA_TRACK_TYPE_LOGO = 0x10, GST_MATROSKA_TRACK_TYPE_LOGO = 0x10,
GST_MATROSKA_TRACK_TYPE_SUBTITLE = 0x11, GST_MATROSKA_TRACK_TYPE_SUBTITLE = 0x11,
GST_MATROSKA_TRACK_TYPE_BUTTONS = 0x12,
GST_MATROSKA_TRACK_TYPE_CONTROL = 0x20, GST_MATROSKA_TRACK_TYPE_CONTROL = 0x20,
} GstMatroskaTrackType; } GstMatroskaTrackType;
@ -244,6 +453,7 @@ typedef enum {
GST_MATROSKA_TRACK_ENABLED = (1<<0), GST_MATROSKA_TRACK_ENABLED = (1<<0),
GST_MATROSKA_TRACK_DEFAULT = (1<<1), GST_MATROSKA_TRACK_DEFAULT = (1<<1),
GST_MATROSKA_TRACK_LACING = (1<<2), GST_MATROSKA_TRACK_LACING = (1<<2),
GST_MATROSKA_TRACK_FORCED = (1<<3),
GST_MATROSKA_TRACK_SHIFT = (1<<16) GST_MATROSKA_TRACK_SHIFT = (1<<16)
} GstMatroskaTrackFlags; } GstMatroskaTrackFlags;
@ -251,6 +461,7 @@ typedef enum {
GST_MATROSKA_VIDEOTRACK_INTERLACED = (GST_MATROSKA_TRACK_SHIFT<<0) GST_MATROSKA_VIDEOTRACK_INTERLACED = (GST_MATROSKA_TRACK_SHIFT<<0)
} GstMatroskaVideoTrackFlags; } GstMatroskaVideoTrackFlags;
/* TODO: check if all fields are used */
typedef struct _GstMatroskaTrackContext { typedef struct _GstMatroskaTrackContext {
GstPad *pad; GstPad *pad;
GstCaps *caps; GstCaps *caps;
@ -266,6 +477,7 @@ typedef struct _GstMatroskaTrackContext {
GstMatroskaTrackFlags flags; GstMatroskaTrackFlags flags;
guint64 default_duration; guint64 default_duration;
guint64 pos; guint64 pos;
gdouble timecodescale;
gboolean set_discont; /* TRUE = set DISCONT flag on next buffer */ gboolean set_discont; /* TRUE = set DISCONT flag on next buffer */
@ -313,12 +525,6 @@ typedef struct _GstMatroskaTrackAudioContext {
guint samplerate, channels, bitdepth; guint samplerate, channels, bitdepth;
} GstMatroskaTrackAudioContext; } GstMatroskaTrackAudioContext;
typedef struct _GstMatroskaTrackComplexContext {
GstMatroskaTrackContext parent;
/* nothing special goes here, apparently */
} GstMatroskaTrackComplexContext;
typedef struct _GstMatroskaTrackSubtitleContext { typedef struct _GstMatroskaTrackSubtitleContext {
GstMatroskaTrackContext parent; GstMatroskaTrackContext parent;
@ -357,6 +563,5 @@ typedef struct _GstMatroskaTrackEncoding {
gboolean gst_matroska_track_init_video_context (GstMatroskaTrackContext ** p_context); gboolean gst_matroska_track_init_video_context (GstMatroskaTrackContext ** p_context);
gboolean gst_matroska_track_init_audio_context (GstMatroskaTrackContext ** p_context); gboolean gst_matroska_track_init_audio_context (GstMatroskaTrackContext ** p_context);
gboolean gst_matroska_track_init_subtitle_context (GstMatroskaTrackContext ** p_context); gboolean gst_matroska_track_init_subtitle_context (GstMatroskaTrackContext ** p_context);
gboolean gst_matroska_track_init_complex_context (GstMatroskaTrackContext ** p_context);
#endif /* __GST_MATROSKA_IDS_H__ */ #endif /* __GST_MATROSKA_IDS_H__ */

View file

@ -20,6 +20,10 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
/* TODO: - check everywhere that we don't write invalid values
* - make sure timestamps are correctly scaled everywhere
*/
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
@ -55,6 +59,10 @@ static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
"width = (int) [ 16, 4096 ], " \ "width = (int) [ 16, 4096 ], " \
"height = (int) [ 16, 4096 ] " "height = (int) [ 16, 4096 ] "
/* FIXME:
* * require codec data, etc as needed
*/
static GstStaticPadTemplate videosink_templ = static GstStaticPadTemplate videosink_templ =
GST_STATIC_PAD_TEMPLATE ("video_%d", GST_STATIC_PAD_TEMPLATE ("video_%d",
GST_PAD_SINK, GST_PAD_SINK,
@ -92,6 +100,7 @@ static GstStaticPadTemplate videosink_templ =
/* FIXME: /* FIXME:
* * audio/x-raw-float: endianness needs defining. * * audio/x-raw-float: endianness needs defining.
* * require codec data, etc as needed
*/ */
static GstStaticPadTemplate audiosink_templ = static GstStaticPadTemplate audiosink_templ =
GST_STATIC_PAD_TEMPLATE ("audio_%d", GST_STATIC_PAD_TEMPLATE ("audio_%d",
@ -184,11 +193,6 @@ static void
gst_matroska_mux_base_init (gpointer g_class) gst_matroska_mux_base_init (gpointer g_class)
{ {
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
static const GstElementDetails gst_matroska_mux_details =
GST_ELEMENT_DETAILS ("Matroska muxer",
"Codec/Muxer",
"Muxes video/audio/subtitle streams into a matroska stream",
"Ronald Bultje <rbultje@ronald.bitfreak.net>");
gst_element_class_add_pad_template (element_class, gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&videosink_templ)); gst_static_pad_template_get (&videosink_templ));
@ -198,7 +202,10 @@ gst_matroska_mux_base_init (gpointer g_class)
gst_static_pad_template_get (&subtitlesink_templ)); gst_static_pad_template_get (&subtitlesink_templ));
gst_element_class_add_pad_template (element_class, gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_templ)); gst_static_pad_template_get (&src_templ));
gst_element_class_set_details (element_class, &gst_matroska_mux_details); gst_element_class_set_details_simple (element_class, "Matroska muxer",
"Codec/Muxer",
"Muxes video/audio/subtitle streams into a matroska stream",
"Ronald Bultje <rbultje@ronald.bitfreak.net>");
GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0, GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0,
"Matroska muxer"); "Matroska muxer");
@ -208,12 +215,13 @@ static void
gst_matroska_mux_class_init (GstMatroskaMuxClass * klass) gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
{ {
GObjectClass *gobject_class; GObjectClass *gobject_class;
GstElementClass *gstelement_class; GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass; gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass; gstelement_class = (GstElementClass *) klass;
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_matroska_mux_finalize); gobject_class->finalize = gst_matroska_mux_finalize;
gobject_class->get_property = gst_matroska_mux_get_property; gobject_class->get_property = gst_matroska_mux_get_property;
gobject_class->set_property = gst_matroska_mux_set_property; gobject_class->set_property = gst_matroska_mux_set_property;
@ -246,11 +254,7 @@ gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
static void static void
gst_matroska_mux_init (GstMatroskaMux * mux, GstMatroskaMuxClass * g_class) gst_matroska_mux_init (GstMatroskaMux * mux, GstMatroskaMuxClass * g_class)
{ {
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); mux->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
mux->srcpad =
gst_pad_new_from_template (gst_element_class_get_pad_template
(gstelement_class, "src"), "src");
gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event); gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event);
gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad); gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
@ -301,8 +305,10 @@ static guint32
gst_matroska_mux_create_uid (void) gst_matroska_mux_create_uid (void)
{ {
guint32 uid = 0; guint32 uid = 0;
GRand *rand = g_rand_new (); GRand *rand = g_rand_new ();
/* FIXME: array needs locking or moved into instance structure */
while (!uid) { while (!uid) {
guint i; guint i;
@ -357,6 +363,7 @@ static void
gst_matroska_mux_reset (GstElement * element) gst_matroska_mux_reset (GstElement * element)
{ {
GstMatroskaMux *mux = GST_MATROSKA_MUX (element); GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
GSList *walk; GSList *walk;
/* reset EBML write */ /* reset EBML write */
@ -368,6 +375,7 @@ gst_matroska_mux_reset (GstElement * element)
/* clean up existing streams */ /* clean up existing streams */
while ((walk = mux->collect->data) != NULL) { while ((walk = mux->collect->data) != NULL) {
GstMatroskaPad *collect_pad; GstMatroskaPad *collect_pad;
GstPad *thepad; GstPad *thepad;
collect_pad = (GstMatroskaPad *) walk->data; collect_pad = (GstMatroskaPad *) walk->data;
@ -396,7 +404,7 @@ gst_matroska_mux_reset (GstElement * element)
mux->index = NULL; mux->index = NULL;
/* reset timers */ /* reset timers */
mux->time_scale = 1000000; mux->time_scale = GST_MSECOND;
mux->duration = 0; mux->duration = 0;
/* reset uid array */ /* reset uid array */
@ -463,9 +471,13 @@ static gboolean
gst_matroska_mux_handle_sink_event (GstPad * pad, GstEvent * event) gst_matroska_mux_handle_sink_event (GstPad * pad, GstEvent * event)
{ {
GstMatroskaTrackContext *context; GstMatroskaTrackContext *context;
GstMatroskaPad *collect_pad; GstMatroskaPad *collect_pad;
GstMatroskaMux *mux; GstMatroskaMux *mux;
GstTagList *list; GstTagList *list;
gboolean ret; gboolean ret;
mux = GST_MATROSKA_MUX (gst_pad_get_parent (pad)); mux = GST_MATROSKA_MUX (gst_pad_get_parent (pad));
@ -514,12 +526,19 @@ static gboolean
gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps) gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
{ {
GstMatroskaTrackContext *context = NULL; GstMatroskaTrackContext *context = NULL;
GstMatroskaTrackVideoContext *videocontext; GstMatroskaTrackVideoContext *videocontext;
GstMatroskaMux *mux; GstMatroskaMux *mux;
GstMatroskaPad *collect_pad; GstMatroskaPad *collect_pad;
GstStructure *structure; GstStructure *structure;
const gchar *mimetype; const gchar *mimetype;
gint width, height, pixel_width, pixel_height; gint width, height, pixel_width, pixel_height;
gint fps_d, fps_n; gint fps_d, fps_n;
mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad)); mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
@ -578,6 +597,11 @@ skip_details:
videocontext->eye_mode = GST_MATROSKA_EYE_MODE_MONO; videocontext->eye_mode = GST_MATROSKA_EYE_MODE_MONO;
videocontext->fourcc = 0; videocontext->fourcc = 0;
/* TODO: - check if we handle all codecs by the spec, i.e. codec private
* data and other settings
* - add new formats
*/
/* find type */ /* find type */
if (!strcmp (mimetype, "video/x-raw-yuv")) { if (!strcmp (mimetype, "video/x-raw-yuv")) {
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED); context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
@ -594,7 +618,9 @@ skip_details:
|| !strcmp (mimetype, "video/x-dv") || !strcmp (mimetype, "video/x-dv")
|| !strcmp (mimetype, "video/x-h263")) { || !strcmp (mimetype, "video/x-h263")) {
BITMAPINFOHEADER *bih; BITMAPINFOHEADER *bih;
const GValue *codec_data; const GValue *codec_data;
gint size = sizeof (BITMAPINFOHEADER); gint size = sizeof (BITMAPINFOHEADER);
bih = g_new0 (BITMAPINFOHEADER, 1); bih = g_new0 (BITMAPINFOHEADER, 1);
@ -666,6 +692,7 @@ skip_details:
if (codec_data != NULL) { if (codec_data != NULL) {
guint8 *priv_data = NULL; guint8 *priv_data = NULL;
guint priv_data_size = 0; guint priv_data_size = 0;
GstBuffer *codec_data_buf = g_value_peek_pointer (codec_data); GstBuffer *codec_data_buf = g_value_peek_pointer (codec_data);
@ -735,8 +762,11 @@ xiph3_streamheader_to_codecdata (const GValue * streamheader,
GstMatroskaTrackContext * context, GstBuffer ** p_buf0) GstMatroskaTrackContext * context, GstBuffer ** p_buf0)
{ {
GstBuffer *buf[3]; GstBuffer *buf[3];
GArray *bufarr; GArray *bufarr;
guint8 *priv_data; guint8 *priv_data;
guint i, offset, priv_data_size; guint i, offset, priv_data_size;
if (streamheader == NULL) if (streamheader == NULL)
@ -835,6 +865,7 @@ vorbis_streamheader_to_codecdata (const GValue * streamheader,
} else { } else {
if (memcmp (GST_BUFFER_DATA (buf0) + 1, "vorbis", 6) == 0) { if (memcmp (GST_BUFFER_DATA (buf0) + 1, "vorbis", 6) == 0) {
GstMatroskaTrackAudioContext *audiocontext; GstMatroskaTrackAudioContext *audiocontext;
guint8 *hdr; guint8 *hdr;
hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 4; hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 4;
@ -865,7 +896,9 @@ theora_streamheader_to_codecdata (const GValue * streamheader,
GST_WARNING ("First header not a theora identification header, ignoring"); GST_WARNING ("First header not a theora identification header, ignoring");
} else { } else {
GstMatroskaTrackVideoContext *videocontext; GstMatroskaTrackVideoContext *videocontext;
guint fps_num, fps_denom, par_num, par_denom; guint fps_num, fps_denom, par_num, par_denom;
guint8 *hdr; guint8 *hdr;
hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 3 + 2 + 2; hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 3 + 2 + 2;
@ -920,11 +953,17 @@ static gboolean
gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps) gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
{ {
GstMatroskaTrackContext *context = NULL; GstMatroskaTrackContext *context = NULL;
GstMatroskaTrackAudioContext *audiocontext; GstMatroskaTrackAudioContext *audiocontext;
GstMatroskaMux *mux; GstMatroskaMux *mux;
GstMatroskaPad *collect_pad; GstMatroskaPad *collect_pad;
const gchar *mimetype; const gchar *mimetype;
gint samplerate = 0, channels = 0; gint samplerate = 0, channels = 0;
GstStructure *structure; GstStructure *structure;
mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad)); mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
@ -949,6 +988,11 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
audiocontext->bitdepth = 0; audiocontext->bitdepth = 0;
context->default_duration = 0; context->default_duration = 0;
/* TODO: - check if we handle all codecs by the spec, i.e. codec private
* data and other settings
* - add new formats
*/
if (!strcmp (mimetype, "audio/mpeg")) { if (!strcmp (mimetype, "audio/mpeg")) {
gint mpegversion = 0; gint mpegversion = 0;
@ -957,6 +1001,10 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
case 1:{ case 1:{
gint layer; gint layer;
/* FIXME: number of samples per frame also depends on the mpegversion
* which we don't pass as a caps field
*/
gst_structure_get_int (structure, "layer", &layer); gst_structure_get_int (structure, "layer", &layer);
switch (layer) { switch (layer) {
case 1: case 1:
@ -980,10 +1028,12 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
break; break;
} }
case 2: case 2:
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG2 "MAIN"); context->codec_id =
g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG2 "MAIN");
break; break;
case 4: case 4:
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG4 "MAIN"); context->codec_id =
g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4 "MAIN");
break; break;
default: default:
return FALSE; return FALSE;
@ -992,6 +1042,7 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
return TRUE; return TRUE;
} else if (!strcmp (mimetype, "audio/x-raw-int")) { } else if (!strcmp (mimetype, "audio/x-raw-int")) {
gint endianness, width, depth; gint endianness, width, depth;
gboolean signedness; gboolean signedness;
if (!gst_structure_get_int (structure, "width", &width) || if (!gst_structure_get_int (structure, "width", &width) ||
@ -1078,7 +1129,8 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
static gboolean static gboolean
gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps) gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
{ {
/* Consider this as boilerplate code for now. There is /* FIXME:
* Consider this as boilerplate code for now. There is
* no single subtitle creation element in GStreamer, * no single subtitle creation element in GStreamer,
* neither do I know how subtitling works at all. */ * neither do I know how subtitling works at all. */
@ -1101,30 +1153,36 @@ gst_matroska_mux_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * pad_name) GstPadTemplate * templ, const gchar * pad_name)
{ {
GstElementClass *klass = GST_ELEMENT_GET_CLASS (element); GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
GstMatroskaMux *mux = GST_MATROSKA_MUX (element); GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
GstMatroskaPad *collect_pad; GstMatroskaPad *collect_pad;
GstPad *newpad = NULL; GstPad *newpad = NULL;
gchar *name = NULL; gchar *name = NULL;
GstPadSetCapsFunction setcapsfunc = NULL; GstPadSetCapsFunction setcapsfunc = NULL;
GstMatroskaTrackContext *context = NULL; GstMatroskaTrackContext *context = NULL;
if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) { if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
name = g_strdup_printf ("audio_%d", mux->num_a_streams++); name = g_strdup_printf ("audio_%d", mux->num_a_streams++);
setcapsfunc = gst_matroska_mux_audio_pad_setcaps; setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
context = (GstMatroskaTrackContext *) context = (GstMatroskaTrackContext *)
g_new0 (GstMatroskaTrackAudioContext, 1); g_new0 (GstMatroskaTrackAudioContext, 1);
context->type = GST_MATROSKA_TRACK_TYPE_AUDIO; context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
context->name = g_strdup ("Audio"); context->name = g_strdup ("Audio");
} else if (templ == gst_element_class_get_pad_template (klass, "video_%d")) { } else if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
name = g_strdup_printf ("video_%d", mux->num_v_streams++); name = g_strdup_printf ("video_%d", mux->num_v_streams++);
setcapsfunc = gst_matroska_mux_video_pad_setcaps; setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
context = (GstMatroskaTrackContext *) context = (GstMatroskaTrackContext *)
g_new0 (GstMatroskaTrackVideoContext, 1); g_new0 (GstMatroskaTrackVideoContext, 1);
context->type = GST_MATROSKA_TRACK_TYPE_VIDEO; context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
context->name = g_strdup ("Video"); context->name = g_strdup ("Video");
} else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%d")) { } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%d")) {
name = g_strdup_printf ("subtitle_%d", mux->num_t_streams++); name = g_strdup_printf ("subtitle_%d", mux->num_t_streams++);
setcapsfunc = gst_matroska_mux_subtitle_pad_setcaps; setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
context = (GstMatroskaTrackContext *) context = (GstMatroskaTrackContext *)
g_new0 (GstMatroskaTrackSubtitleContext, 1); g_new0 (GstMatroskaTrackSubtitleContext, 1);
context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE; context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
@ -1138,6 +1196,8 @@ gst_matroska_mux_request_new_pad (GstElement * element,
g_free (name); g_free (name);
collect_pad = (GstMatroskaPad *) collect_pad = (GstMatroskaPad *)
gst_collect_pads_add_pad (mux->collect, newpad, sizeof (GstMatroskaPad)); gst_collect_pads_add_pad (mux->collect, newpad, sizeof (GstMatroskaPad));
/* TODO: check default values for the context */
context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT; context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
collect_pad->track = context; collect_pad->track = context;
collect_pad->buffer = NULL; collect_pad->buffer = NULL;
@ -1174,12 +1234,14 @@ static void
gst_matroska_mux_release_pad (GstElement * element, GstPad * pad) gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
{ {
GstMatroskaMux *mux; GstMatroskaMux *mux;
GSList *walk; GSList *walk;
mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad)); mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) { for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
GstCollectData *cdata = (GstCollectData *) walk->data; GstCollectData *cdata = (GstCollectData *) walk->data;
GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata; GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
if (cdata->pad == pad) { if (cdata->pad == pad) {
@ -1219,8 +1281,11 @@ gst_matroska_mux_track_header (GstMatroskaMux * mux,
GstMatroskaTrackContext * context) GstMatroskaTrackContext * context)
{ {
GstEbmlWrite *ebml = mux->ebml_write; GstEbmlWrite *ebml = mux->ebml_write;
guint64 master; guint64 master;
/* TODO: check if everything necessary is written and check default values */
/* track type goes before the type-specific stuff */ /* track type goes before the type-specific stuff */
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);
@ -1298,6 +1363,7 @@ gst_matroska_mux_track_header (GstMatroskaMux * mux,
/* FIXME: until we have a nice way of getting the codecname /* FIXME: until we have a nice way of getting the codecname
* out of the caps, I'm not going to enable this. Too much * out of the caps, I'm not going to enable this. Too much
* (useless, double, boring) work... */ * (useless, double, boring) work... */
/* TODO: Use value from tags if any */
/*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME, /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
context->codec_name); */ context->codec_name); */
gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name); gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
@ -1314,7 +1380,8 @@ static void
gst_matroska_mux_start (GstMatroskaMux * mux) gst_matroska_mux_start (GstMatroskaMux * mux)
{ {
GstEbmlWrite *ebml = mux->ebml_write; GstEbmlWrite *ebml = mux->ebml_write;
guint32 seekhead_id[] = { GST_MATROSKA_ID_INFO,
guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
GST_MATROSKA_ID_TRACKS, GST_MATROSKA_ID_TRACKS,
GST_MATROSKA_ID_CUES, GST_MATROSKA_ID_CUES,
GST_MATROSKA_ID_SEEKHEAD, GST_MATROSKA_ID_SEEKHEAD,
@ -1322,11 +1389,17 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
0 0
}; };
guint64 master, child; guint64 master, child;
GSList *collected; GSList *collected;
int i; int i;
guint tracknum = 1; guint tracknum = 1;
GstClockTime duration = 0; GstClockTime duration = 0;
guint32 *segment_uid = (guint32 *) g_malloc (16); guint32 *segment_uid = (guint32 *) g_malloc (16);
GRand *rand = g_rand_new (); GRand *rand = g_rand_new ();
GTimeVal time = { 0, 0 }; GTimeVal time = { 0, 0 };
@ -1354,7 +1427,7 @@ 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_SEGMENTINFO);
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
segment_uid[i] = g_rand_int (rand); segment_uid[i] = g_rand_int (rand);
} }
@ -1368,8 +1441,11 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
for (collected = mux->collect->data; collected; for (collected = mux->collect->data; collected;
collected = g_slist_next (collected)) { collected = g_slist_next (collected)) {
GstMatroskaPad *collect_pad; GstMatroskaPad *collect_pad;
GstFormat format = GST_FORMAT_TIME; GstFormat format = GST_FORMAT_TIME;
GstPad *thepad; GstPad *thepad;
gint64 trackduration; gint64 trackduration;
collect_pad = (GstMatroskaPad *) collected->data; collect_pad = (GstMatroskaPad *) collected->data;
@ -1406,6 +1482,7 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
collected = g_slist_next (collected)) { collected = g_slist_next (collected)) {
GstMatroskaPad *collect_pad; GstMatroskaPad *collect_pad;
GstPad *thepad; GstPad *thepad;
collect_pad = (GstMatroskaPad *) collected->data; collect_pad = (GstMatroskaPad *) collected->data;
@ -1429,6 +1506,7 @@ static void
gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag, gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
gpointer data) gpointer data)
{ {
/* TODO: more sensible tag mappings */
struct struct
{ {
gchar *matroska_tagname; gchar *matroska_tagname;
@ -1446,11 +1524,14 @@ gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT} GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}
}; };
GstEbmlWrite *ebml = (GstEbmlWrite *) data; GstEbmlWrite *ebml = (GstEbmlWrite *) data;
guint i; guint i;
guint64 simpletag_master; guint64 simpletag_master;
for (i = 0; i < G_N_ELEMENTS (tag_conv); i++) { for (i = 0; i < G_N_ELEMENTS (tag_conv); i++) {
const gchar *tagname_gst = tag_conv[i].gstreamer_tagname; const gchar *tagname_gst = tag_conv[i].gstreamer_tagname;
const gchar *tagname_mkv = tag_conv[i].matroska_tagname; const gchar *tagname_mkv = tag_conv[i].matroska_tagname;
if (strcmp (tagname_gst, tag) == 0) { if (strcmp (tagname_gst, tag) == 0) {
@ -1486,9 +1567,13 @@ static void
gst_matroska_mux_finish (GstMatroskaMux * mux) gst_matroska_mux_finish (GstMatroskaMux * mux)
{ {
GstEbmlWrite *ebml = mux->ebml_write; GstEbmlWrite *ebml = mux->ebml_write;
guint64 pos; guint64 pos;
guint64 duration = 0; guint64 duration = 0;
GSList *collected; GSList *collected;
GstTagList *tags; GstTagList *tags;
/* finish last cluster */ /* finish last cluster */
@ -1499,6 +1584,7 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
/* cues */ /* cues */
if (mux->index != NULL) { if (mux->index != NULL) {
guint n; guint n;
guint64 master, pointentry_master, trackpos_master; guint64 master, pointentry_master, trackpos_master;
mux->cues_pos = ebml->pos; mux->cues_pos = ebml->pos;
@ -1513,7 +1599,7 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME, gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
idx->time / mux->time_scale); idx->time / mux->time_scale);
trackpos_master = gst_ebml_write_master_start (ebml, trackpos_master = gst_ebml_write_master_start (ebml,
GST_MATROSKA_ID_CUETRACKPOSITION); GST_MATROSKA_ID_CUETRACKPOSITIONS);
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track); gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION, gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
idx->pos - mux->segment_master); idx->pos - mux->segment_master);
@ -1527,6 +1613,7 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
if (mux->meta_index != NULL) { if (mux->meta_index != NULL) {
guint n; guint n;
guint64 master, seekentry_master; guint64 master, seekentry_master;
mux->meta_pos = ebml->pos; mux->meta_pos = ebml->pos;
@ -1554,6 +1641,7 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
if (tags != NULL) { if (tags != NULL) {
guint64 master_tags, master_tag; guint64 master_tags, master_tag;
/* TODO: maybe limit via the TARGETS id by looking at the source pad */
mux->tags_pos = ebml->pos; mux->tags_pos = ebml->pos;
master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS); master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG); master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
@ -1618,6 +1706,7 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
for (collected = mux->collect->data; collected; for (collected = mux->collect->data; collected;
collected = g_slist_next (collected)) { collected = g_slist_next (collected)) {
GstMatroskaPad *collect_pad; GstMatroskaPad *collect_pad;
GstClockTime min_duration; /* observed minimum duration */ GstClockTime min_duration; /* observed minimum duration */
collect_pad = (GstMatroskaPad *) collected->data; collect_pad = (GstMatroskaPad *) collected->data;
@ -1650,6 +1739,13 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
gst_guint64_to_gdouble (duration) / gst_guint64_to_gdouble (duration) /
gst_guint64_to_gdouble (mux->time_scale)); gst_guint64_to_gdouble (mux->time_scale));
gst_ebml_write_seek (ebml, pos); gst_ebml_write_seek (ebml, pos);
} else {
/* void'ify */
guint64 my_pos = ebml->pos;
gst_ebml_write_seek (ebml, mux->duration_pos);
gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
gst_ebml_write_seek (ebml, my_pos);
} }
/* finish segment - this also writes element length */ /* finish segment - this also writes element length */
@ -1671,6 +1767,7 @@ static GstMatroskaPad *
gst_matroska_mux_best_pad (GstMatroskaMux * mux, gboolean * popped) gst_matroska_mux_best_pad (GstMatroskaMux * mux, gboolean * popped)
{ {
GSList *collected; GSList *collected;
GstMatroskaPad *best = NULL; GstMatroskaPad *best = NULL;
*popped = FALSE; *popped = FALSE;
@ -1743,12 +1840,19 @@ static GstFlowReturn
gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad) gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
{ {
GstEbmlWrite *ebml = mux->ebml_write; GstEbmlWrite *ebml = mux->ebml_write;
GstBuffer *buf, *hdr; GstBuffer *buf, *hdr;
guint64 cluster, blockgroup; guint64 cluster, blockgroup;
gboolean write_duration; gboolean write_duration;
gint16 relative_timestamp; gint16 relative_timestamp;
gint64 relative_timestamp64; gint64 relative_timestamp64;
guint64 block_duration; guint64 block_duration;
gboolean is_video_keyframe = FALSE; gboolean is_video_keyframe = FALSE;
/* write data */ /* write data */
@ -1765,6 +1869,8 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
/* hm, invalid timestamp (due to --to be fixed--- element upstream); /* hm, invalid timestamp (due to --to be fixed--- element upstream);
* this would wreak havoc with time stored in matroska file */ * this would wreak havoc with time stored in matroska file */
/* TODO: maybe calculate a timestamp by using the previous timestamp
* and default duration */
if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
GST_WARNING_OBJECT (collect_pad->collect.pad, GST_WARNING_OBJECT (collect_pad->collect.pad,
"Invalid buffer timestamp; dropping buffer"); "Invalid buffer timestamp; dropping buffer");
@ -1871,7 +1977,7 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
/* write the block, for matroska v2 use SimpleBlock if possible /* write the block, for matroska v2 use SimpleBlock if possible
* one slice (*breath*). * one slice (*breath*).
* FIXME: lacing, etc. */ * FIXME: Need to do correct lacing! */
relative_timestamp64 = GST_BUFFER_TIMESTAMP (buf) - mux->cluster_time; relative_timestamp64 = GST_BUFFER_TIMESTAMP (buf) - mux->cluster_time;
if (relative_timestamp64 >= 0) { if (relative_timestamp64 >= 0) {
/* round the timestamp */ /* round the timestamp */
@ -1926,8 +2032,11 @@ static GstFlowReturn
gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data) gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data)
{ {
GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data); GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
GstMatroskaPad *best; GstMatroskaPad *best;
gboolean popped; gboolean popped;
GstFlowReturn ret; GstFlowReturn ret;
GST_DEBUG_OBJECT (mux, "Collected pads"); GST_DEBUG_OBJECT (mux, "Collected pads");
@ -1965,6 +2074,7 @@ gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data)
* the actual duration later when we send an updated header on eos */ * the actual duration later when we send an updated header on eos */
if (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)) { if (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)) {
GstClockTime start_ts = GST_BUFFER_TIMESTAMP (best->buffer); GstClockTime start_ts = GST_BUFFER_TIMESTAMP (best->buffer);
GstClockTime end_ts = start_ts; GstClockTime end_ts = start_ts;
if (GST_BUFFER_DURATION_IS_VALID (best->buffer)) if (GST_BUFFER_DURATION_IS_VALID (best->buffer))
@ -2001,6 +2111,7 @@ static GstStateChangeReturn
gst_matroska_mux_change_state (GstElement * element, GstStateChange transition) gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
{ {
GstStateChangeReturn ret; GstStateChangeReturn ret;
GstMatroskaMux *mux = GST_MATROSKA_MUX (element); GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
switch (transition) { switch (transition) {
@ -2051,7 +2162,7 @@ gst_matroska_mux_set_property (GObject * object,
break; break;
} }
g_free (mux->writing_app); g_free (mux->writing_app);
mux->writing_app = g_strdup (g_value_get_string (value)); mux->writing_app = g_value_dup_string (value);
break; break;
case ARG_MATROSKA_VERSION: case ARG_MATROSKA_VERSION:
mux->matroska_version = g_value_get_int (value); mux->matroska_version = g_value_get_int (value);