summaryrefslogtreecommitdiffstats
path: root/gst/qtmux/gstqtmux.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/qtmux/gstqtmux.c')
-rw-r--r--gst/qtmux/gstqtmux.c542
1 files changed, 391 insertions, 151 deletions
diff --git a/gst/qtmux/gstqtmux.c b/gst/qtmux/gstqtmux.c
index 03b0a1a6..8d811f41 100644
--- a/gst/qtmux/gstqtmux.c
+++ b/gst/qtmux/gstqtmux.c
@@ -111,9 +111,11 @@ enum
PROP_FAST_START_TEMP_FILE
};
-#define MDAT_ATOM_HEADER_SIZE 16
+/* some spare for header size as well */
+#define MDAT_LARGE_FILE_LIMIT ((guint64) 1024 * 1024 * 1024 * 2)
+
#define DEFAULT_LARGE_FILE FALSE
-#define DEFAULT_MOVIE_TIMESCALE 600
+#define DEFAULT_MOVIE_TIMESCALE 1000
#define DEFAULT_DO_CTTS FALSE
#define DEFAULT_FAST_START FALSE
#define DEFAULT_FAST_START_TEMP_FILE NULL
@@ -349,8 +351,294 @@ gst_qt_mux_finalize (GObject * object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
-/* FIXME approach below is pretty Apple/MOV/MP4/iTunes specific,
- * and as such does not comply with e.g. 3GPP specs */
+static void
+gst_qt_mux_add_mp4_tag (GstQTMux * qtmux, const GstTagList * list,
+ const char *tag, const char *tag2, guint32 fourcc)
+{
+ switch (gst_tag_get_type (tag)) {
+ /* strings */
+ case G_TYPE_STRING:
+ {
+ gchar *str = NULL;
+
+ if (!gst_tag_list_get_string (list, tag, &str) || !str)
+ break;
+ GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
+ GST_FOURCC_ARGS (fourcc), str);
+ atom_moov_add_str_tag (qtmux->moov, fourcc, str);
+ g_free (str);
+ break;
+ }
+ /* double */
+ case G_TYPE_DOUBLE:
+ {
+ gdouble value;
+
+ if (!gst_tag_list_get_double (list, tag, &value))
+ break;
+ GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %u",
+ GST_FOURCC_ARGS (fourcc), (gint) value);
+ atom_moov_add_uint_tag (qtmux->moov, fourcc, 21, (gint) value);
+ break;
+ }
+ /* paired unsigned integers */
+ case G_TYPE_UINT:
+ {
+ guint value;
+ guint count;
+
+ if (!gst_tag_list_get_uint (list, tag, &value) ||
+ !gst_tag_list_get_uint (list, tag2, &count))
+ break;
+ GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %u/%u",
+ GST_FOURCC_ARGS (fourcc), value, count);
+ atom_moov_add_uint_tag (qtmux->moov, fourcc, 0,
+ value << 16 | (count & 0xFFFF));
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static void
+gst_qt_mux_add_mp4_date (GstQTMux * qtmux, const GstTagList * list,
+ const char *tag, const char *tag2, guint32 fourcc)
+{
+ GDate *date = NULL;
+ GDateYear year;
+ GDateMonth month;
+ GDateDay day;
+ gchar *str;
+
+ g_return_if_fail (gst_tag_get_type (tag) == GST_TYPE_DATE);
+
+ if (!gst_tag_list_get_date (list, tag, &date) || !date)
+ return;
+
+ year = g_date_get_year (date);
+ month = g_date_get_month (date);
+ day = g_date_get_day (date);
+
+ if (year == G_DATE_BAD_YEAR && month == G_DATE_BAD_MONTH &&
+ day == G_DATE_BAD_DAY) {
+ GST_WARNING_OBJECT (qtmux, "invalid date in tag");
+ return;
+ }
+
+ str = g_strdup_printf ("%u-%u-%u", year, month, day);
+ GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
+ GST_FOURCC_ARGS (fourcc), str);
+ atom_moov_add_str_tag (qtmux->moov, fourcc, str);
+}
+
+static void
+gst_qt_mux_add_mp4_cover (GstQTMux * qtmux, const GstTagList * list,
+ const char *tag, const char *tag2, guint32 fourcc)
+{
+ GValue value = { 0, };
+ GstBuffer *buf;
+ GstCaps *caps;
+ GstStructure *structure;
+ gint flags = 0;
+
+ g_return_if_fail (gst_tag_get_type (tag) == GST_TYPE_BUFFER);
+
+ if (!gst_tag_list_copy_value (&value, list, tag))
+ return;
+
+ buf = gst_value_get_buffer (&value);
+ if (!buf)
+ goto done;
+
+ caps = gst_buffer_get_caps (buf);
+ if (!caps) {
+ GST_WARNING_OBJECT (qtmux, "preview image without caps");
+ goto done;
+ }
+
+ GST_DEBUG_OBJECT (qtmux, "preview image caps %" GST_PTR_FORMAT, caps);
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (gst_structure_has_name (structure, "image/jpeg"))
+ flags = 13;
+ else if (gst_structure_has_name (structure, "image/png"))
+ flags = 14;
+ gst_caps_unref (caps);
+
+ if (!flags) {
+ GST_WARNING_OBJECT (qtmux, "preview image format not supported");
+ goto done;
+ }
+
+ GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT
+ " -> image size %d", GST_FOURCC_ARGS (fourcc), GST_BUFFER_SIZE (buf));
+ atom_moov_add_tag (qtmux->moov, fourcc, flags, GST_BUFFER_DATA (buf),
+ GST_BUFFER_SIZE (buf));
+done:
+ g_value_unset (&value);
+}
+
+static void
+gst_qt_mux_add_3gp_str (GstQTMux * qtmux, const GstTagList * list,
+ const char *tag, const char *tag2, guint32 fourcc)
+{
+ gchar *str = NULL;
+ guint number;
+
+ g_return_if_fail (gst_tag_get_type (tag) == G_TYPE_STRING);
+ g_return_if_fail (!tag2 || gst_tag_get_type (tag2) == G_TYPE_UINT);
+
+ if (!gst_tag_list_get_string (list, tag, &str) || !str)
+ return;
+
+ if (tag2)
+ if (!gst_tag_list_get_uint (list, tag2, &number))
+ tag2 = NULL;
+
+ if (!tag2) {
+ GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
+ GST_FOURCC_ARGS (fourcc), str);
+ atom_moov_add_3gp_str_tag (qtmux->moov, fourcc, str);
+ } else {
+ GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s/%d",
+ GST_FOURCC_ARGS (fourcc), str, number);
+ atom_moov_add_3gp_str_int_tag (qtmux->moov, fourcc, str, number);
+ }
+
+ g_free (str);
+}
+
+static void
+gst_qt_mux_add_3gp_date (GstQTMux * qtmux, const GstTagList * list,
+ const char *tag, const char *tag2, guint32 fourcc)
+{
+ GDate *date = NULL;
+ GDateYear year;
+
+ g_return_if_fail (gst_tag_get_type (tag) == GST_TYPE_DATE);
+
+ if (!gst_tag_list_get_date (list, tag, &date) || !date)
+ return;
+
+ year = g_date_get_year (date);
+
+ if (year == G_DATE_BAD_YEAR) {
+ GST_WARNING_OBJECT (qtmux, "invalid date in tag");
+ return;
+ }
+
+ GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %d", year);
+ atom_moov_add_3gp_uint_tag (qtmux->moov, fourcc, year);
+}
+
+static void
+gst_qt_mux_add_3gp_location (GstQTMux * qtmux, const GstTagList * list,
+ const char *tag, const char *tag2, guint32 fourcc)
+{
+ gdouble latitude = -360, longitude = -360, altitude = 0;
+ gchar *location = NULL;
+ guint8 *data, *ddata;
+ gint size = 0, len = 0;
+ gboolean ret = FALSE;
+
+ g_return_if_fail (strcmp (tag, GST_TAG_GEO_LOCATION_NAME) == 0);
+
+ ret = gst_tag_list_get_string (list, tag, &location);
+ ret |= gst_tag_list_get_double (list, GST_TAG_GEO_LOCATION_LONGITUDE,
+ &longitude);
+ ret |= gst_tag_list_get_double (list, GST_TAG_GEO_LOCATION_LATITUDE,
+ &latitude);
+ ret |= gst_tag_list_get_double (list, GST_TAG_GEO_LOCATION_ELEVATION,
+ &altitude);
+
+ if (!ret)
+ return;
+
+ if (location)
+ len = strlen (location);
+ size += len + 1 + 2;
+
+ /* role + (long, lat, alt) + body + notes */
+ size += 1 + 3 * 4 + 1 + 1;
+
+ data = ddata = g_malloc (size);
+
+ /* language tag */
+ GST_WRITE_UINT16_BE (data, language_code (GST_QT_MUX_DEFAULT_TAG_LANGUAGE));
+ /* location */
+ if (location)
+ memcpy (data + 2, location, len);
+ GST_WRITE_UINT8 (data + 2 + len, 0);
+ data += len + 1 + 2;
+ /* role */
+ GST_WRITE_UINT8 (data, 0);
+ /* long, lat, alt */
+ GST_WRITE_UINT32_BE (data + 1, (guint32) (longitude * 65536.0));
+ GST_WRITE_UINT32_BE (data + 5, (guint32) (latitude * 65536.0));
+ GST_WRITE_UINT32_BE (data + 9, (guint32) (altitude * 65536.0));
+ /* neither astronomical body nor notes */
+ GST_WRITE_UINT16_BE (data + 13, 0);
+
+ GST_DEBUG_OBJECT (qtmux, "Adding tag 'loci'");
+ atom_moov_add_3gp_tag (qtmux->moov, fourcc, ddata, size);
+ g_free (ddata);
+}
+
+static void
+gst_qt_mux_add_3gp_keywords (GstQTMux * qtmux, const GstTagList * list,
+ const char *tag, const char *tag2, guint32 fourcc)
+{
+ gchar *keywords = NULL;
+ guint8 *data, *ddata;
+ gint size = 0, i;
+ gchar **kwds;
+
+ g_return_if_fail (strcmp (tag, GST_TAG_KEYWORDS) == 0);
+
+ if (!gst_tag_list_get_string (list, tag, &keywords) || !keywords)
+ return;
+
+ kwds = g_strsplit (keywords, ",", 0);
+
+ size = 0;
+ for (i = 0; kwds[i]; i++) {
+ /* size byte + null-terminator */
+ size += strlen (kwds[i]) + 1 + 1;
+ }
+
+ /* language tag + count + keywords */
+ size += 2 + 1;
+
+ data = ddata = g_malloc (size);
+
+ /* language tag */
+ GST_WRITE_UINT16_BE (data, language_code (GST_QT_MUX_DEFAULT_TAG_LANGUAGE));
+ /* count */
+ GST_WRITE_UINT8 (data + 2, i);
+ data += 3;
+ /* keywords */
+ for (i = 0; kwds[i]; ++i) {
+ gint len = strlen (kwds[i]);
+
+ GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
+ GST_FOURCC_ARGS (fourcc), kwds[i]);
+ /* size */
+ GST_WRITE_UINT8 (data, len + 1);
+ memcpy (data + 1, kwds[i], len + 1);
+ data += len + 2;
+ }
+
+ g_strfreev (kwds);
+
+ atom_moov_add_3gp_tag (qtmux->moov, fourcc, ddata, size);
+ g_free (ddata);
+}
+
+
+typedef void (*GstQTMuxAddTagFunc) (GstQTMux * mux, const GstTagList * list,
+ const char *tag, const char *tag2, guint32 fourcc);
/*
* Struct to record mappings from gstreamer tags to fourcc codes
@@ -360,25 +648,42 @@ typedef struct _GstTagToFourcc
guint32 fourcc;
const gchar *gsttag;
const gchar *gsttag2;
+ const GstQTMuxAddTagFunc func;
} GstTagToFourcc;
/* tag list tags to fourcc matching */
-static const GstTagToFourcc tag_matches[] = {
- {FOURCC__alb, GST_TAG_ALBUM,},
- {FOURCC__ART, GST_TAG_ARTIST,},
- {FOURCC__cmt, GST_TAG_COMMENT,},
- {FOURCC__wrt, GST_TAG_COMPOSER,},
- {FOURCC__gen, GST_TAG_GENRE,},
- {FOURCC__nam, GST_TAG_TITLE,},
- {FOURCC__des, GST_TAG_DESCRIPTION,},
- {FOURCC__too, GST_TAG_ENCODER,},
- {FOURCC_cprt, GST_TAG_COPYRIGHT,},
- {FOURCC_keyw, GST_TAG_KEYWORDS,},
- {FOURCC__day, GST_TAG_DATE,},
- {FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE,},
- {FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT},
- {FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT},
- {FOURCC_covr, GST_TAG_PREVIEW_IMAGE,},
+static const GstTagToFourcc tag_matches_mp4[] = {
+ {FOURCC__alb, GST_TAG_ALBUM, NULL, gst_qt_mux_add_mp4_tag},
+ {FOURCC__ART, GST_TAG_ARTIST, NULL, gst_qt_mux_add_mp4_tag},
+ {FOURCC__cmt, GST_TAG_COMMENT, NULL, gst_qt_mux_add_mp4_tag},
+ {FOURCC__wrt, GST_TAG_COMPOSER, NULL, gst_qt_mux_add_mp4_tag},
+ {FOURCC__gen, GST_TAG_GENRE, NULL, gst_qt_mux_add_mp4_tag},
+ {FOURCC__nam, GST_TAG_TITLE, NULL, gst_qt_mux_add_mp4_tag},
+ {FOURCC__des, GST_TAG_DESCRIPTION, NULL, gst_qt_mux_add_mp4_tag},
+ {FOURCC__too, GST_TAG_ENCODER, NULL, gst_qt_mux_add_mp4_tag},
+ {FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, gst_qt_mux_add_mp4_tag},
+ {FOURCC_keyw, GST_TAG_KEYWORDS, NULL, gst_qt_mux_add_mp4_tag},
+ {FOURCC__day, GST_TAG_DATE, NULL, gst_qt_mux_add_mp4_date},
+ {FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, gst_qt_mux_add_mp4_tag},
+ {FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT,
+ gst_qt_mux_add_mp4_tag},
+ {FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
+ gst_qt_mux_add_mp4_tag},
+ {FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, gst_qt_mux_add_mp4_cover},
+ {0, NULL,}
+};
+
+static const GstTagToFourcc tag_matches_3gp[] = {
+ {FOURCC_titl, GST_TAG_TITLE, NULL, gst_qt_mux_add_3gp_str},
+ {FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, gst_qt_mux_add_3gp_str},
+ {FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, gst_qt_mux_add_3gp_str},
+ {FOURCC_perf, GST_TAG_ARTIST, NULL, gst_qt_mux_add_3gp_str},
+ {FOURCC_auth, GST_TAG_COMPOSER, NULL, gst_qt_mux_add_3gp_str},
+ {FOURCC_gnre, GST_TAG_GENRE, NULL, gst_qt_mux_add_3gp_str},
+ {FOURCC_kywd, GST_TAG_KEYWORDS, NULL, gst_qt_mux_add_3gp_keywords},
+ {FOURCC_yrrc, GST_TAG_DATE, NULL, gst_qt_mux_add_3gp_date},
+ {FOURCC_albm, GST_TAG_ALBUM, GST_TAG_TRACK_NUMBER, gst_qt_mux_add_3gp_str},
+ {FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, gst_qt_mux_add_3gp_location},
{0, NULL,}
};
@@ -388,127 +693,35 @@ static const GstTagToFourcc tag_matches[] = {
static void
gst_qt_mux_add_metadata_tags (GstQTMux * qtmux, const GstTagList * list)
{
+ GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
guint32 fourcc;
gint i;
const gchar *tag, *tag2;
+ const GstTagToFourcc *tag_matches;
+
+ switch (qtmux_klass->format) {
+ case GST_QT_MUX_FORMAT_3GP:
+ tag_matches = tag_matches_3gp;
+ break;
+ case GST_QT_MUX_FORMAT_MJ2:
+ tag_matches = NULL;
+ break;
+ default:
+ /* sort of iTunes style for mp4 and QT (?) */
+ tag_matches = tag_matches_mp4;
+ break;
+ }
+
+ if (!tag_matches)
+ return;
for (i = 0; tag_matches[i].fourcc; i++) {
fourcc = tag_matches[i].fourcc;
tag = tag_matches[i].gsttag;
tag2 = tag_matches[i].gsttag2;
- switch (gst_tag_get_type (tag)) {
- /* strings */
- case G_TYPE_STRING:
- {
- gchar *str = NULL;
-
- if (!gst_tag_list_get_string (list, tag, &str) || !str)
- break;
- GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
- GST_FOURCC_ARGS (fourcc), str);
- atom_moov_add_str_tag (qtmux->moov, fourcc, str);
- g_free (str);
- break;
- }
- /* double */
- case G_TYPE_DOUBLE:
- {
- gdouble value;
-
- if (!gst_tag_list_get_double (list, tag, &value))
- break;
- GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %u",
- GST_FOURCC_ARGS (fourcc), (gint) value);
- atom_moov_add_uint_tag (qtmux->moov, fourcc, 21, (gint) value);
- break;
- }
- /* paired unsigned integers */
- case G_TYPE_UINT:
- {
- guint value;
- guint count;
-
- if (!gst_tag_list_get_uint (list, tag, &value) ||
- !gst_tag_list_get_uint (list, tag2, &count))
- break;
- GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %u/%u",
- GST_FOURCC_ARGS (fourcc), value, count);
- atom_moov_add_uint_tag (qtmux->moov, fourcc, 0,
- value << 16 | (count & 0xFFFF));
- break;
- }
- default:
- {
- if (gst_tag_get_type (tag) == GST_TYPE_DATE) {
- GDate *date = NULL;
- GDateYear year;
- GDateMonth month;
- GDateDay day;
- gchar *str;
-
- if (!gst_tag_list_get_date (list, tag, &date) || !date)
- break;
- year = g_date_get_year (date);
- month = g_date_get_month (date);
- day = g_date_get_day (date);
-
- if (year == G_DATE_BAD_YEAR && month == G_DATE_BAD_MONTH &&
- day == G_DATE_BAD_DAY) {
- GST_WARNING_OBJECT (qtmux, "invalid date in tag");
- break;
- }
-
- str = g_strdup_printf ("%u-%u-%u", year, month, day);
- GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
- GST_FOURCC_ARGS (fourcc), str);
- atom_moov_add_str_tag (qtmux->moov, fourcc, str);
- } else if (gst_tag_get_type (tag) == GST_TYPE_BUFFER) {
- GValue value = { 0, };
- GstBuffer *buf;
- GstCaps *caps;
- GstStructure *structure;
- gint flags = 0;
-
- if (!gst_tag_list_copy_value (&value, list, tag))
- break;
-
- buf = gst_value_get_buffer (&value);
- if (!buf)
- goto done;
-
- caps = gst_buffer_get_caps (buf);
- if (!caps) {
- GST_WARNING_OBJECT (qtmux, "preview image without caps");
- goto done;
- }
-
- GST_DEBUG_OBJECT (qtmux, "preview image caps %" GST_PTR_FORMAT, caps);
-
- structure = gst_caps_get_structure (caps, 0);
- if (gst_structure_has_name (structure, "image/jpeg"))
- flags = 13;
- else if (gst_structure_has_name (structure, "image/png"))
- flags = 14;
- gst_caps_unref (caps);
-
- if (!flags) {
- GST_WARNING_OBJECT (qtmux, "preview image format not supported");
- goto done;
- }
-
- GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT
- " -> image size %d", GST_FOURCC_ARGS (fourcc),
- GST_BUFFER_SIZE (buf));
- atom_moov_add_tag (qtmux->moov, fourcc, flags, GST_BUFFER_DATA (buf),
- GST_BUFFER_SIZE (buf));
- done:
- g_value_unset (&value);
- } else
- g_assert_not_reached ();
- break;
- }
- }
+ g_assert (tag_matches[i].func);
+ tag_matches[i].func (qtmux, list, tag, tag2, fourcc);
}
/* add unparsed blobs if present */
@@ -532,8 +745,12 @@ gst_qt_mux_add_metadata_tags (GstQTMux * qtmux, const GstTagList * list)
GST_PTR_FORMAT, i, num_tags, GST_BUFFER_SIZE (buf), caps);
s = gst_caps_get_structure (caps, 0);
if (s && (style = gst_structure_get_string (s, "style"))) {
- /* FIXME make into a parameter */
- if (strcmp (style, "itunes") == 0) {
+ /* try to prevent some style tag ending up into another variant
+ * (todo: make into a list if more cases) */
+ if ((strcmp (style, "itunes") == 0 &&
+ qtmux_klass->format == GST_QT_MUX_FORMAT_MP4) ||
+ (strcmp (style, "iso") == 0 &&
+ qtmux_klass->format == GST_QT_MUX_FORMAT_3GP)) {
GST_DEBUG_OBJECT (qtmux, "Adding private tag");
atom_moov_add_blob_tag (qtmux->moov, GST_BUFFER_DATA (buf),
GST_BUFFER_SIZE (buf));
@@ -600,7 +817,7 @@ gst_qt_mux_send_buffer (GstQTMux * qtmux, GstBuffer * buf, guint64 * offset,
res = gst_pad_push (qtmux->srcpad, buf);
}
- if (offset)
+ if (G_LIKELY (offset))
*offset += size;
return res;
@@ -690,7 +907,8 @@ seek_failed:
* seek back to it later and update when the streams have finished.
*/
static GstFlowReturn
-gst_qt_mux_send_mdat_header (GstQTMux * qtmux, guint64 * off, guint64 size)
+gst_qt_mux_send_mdat_header (GstQTMux * qtmux, guint64 * off, guint64 size,
+ gboolean extended)
{
Atom *node_header;
GstBuffer *buf;
@@ -702,11 +920,15 @@ gst_qt_mux_send_mdat_header (GstQTMux * qtmux, guint64 * off, guint64 size)
node_header = g_malloc0 (sizeof (Atom));
node_header->type = FOURCC_mdat;
- /* use extended size */
- node_header->size = 1;
- node_header->extended_size = 0;
- if (size)
- node_header->extended_size = size;
+ if (extended) {
+ /* use extended size */
+ node_header->size = 1;
+ node_header->extended_size = 0;
+ if (size)
+ node_header->extended_size = size + 16;
+ } else {
+ node_header->size = size + 8;
+ }
size = offset = 0;
if (atom_copy_data (node_header, &data, &size, &offset) == 0)
@@ -740,14 +962,31 @@ gst_qt_mux_update_mdat_size (GstQTMux * qtmux, guint64 mdat_pos,
{
GstEvent *event;
GstBuffer *buf;
+ gboolean large_file;
+
+ large_file = (mdat_size > MDAT_LARGE_FILE_LIMIT);
+
+ if (large_file)
+ mdat_pos += 8;
/* seek and rewrite the header */
event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
mdat_pos, GST_CLOCK_TIME_NONE, 0);
gst_pad_push_event (qtmux->srcpad, event);
- buf = gst_buffer_new_and_alloc (sizeof (guint64));
- GST_WRITE_UINT64_BE (GST_BUFFER_DATA (buf), mdat_size);
+ if (large_file) {
+ buf = gst_buffer_new_and_alloc (sizeof (guint64));
+ GST_WRITE_UINT64_BE (GST_BUFFER_DATA (buf), mdat_size + 16);
+ } else {
+ guint8 *data;
+
+ buf = gst_buffer_new_and_alloc (16);
+ data = GST_BUFFER_DATA (buf);
+ GST_WRITE_UINT32_BE (data, 8);
+ GST_WRITE_UINT32_LE (data + 4, FOURCC_free);
+ GST_WRITE_UINT32_BE (data + 8, mdat_size + 8);
+ GST_WRITE_UINT32_LE (data + 12, FOURCC_mdat);
+ }
return gst_qt_mux_send_buffer (qtmux, buf, offset, FALSE);
}
@@ -798,6 +1037,7 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
/* tags into file metadata */
gst_qt_mux_setup_metadata (qtmux);
+ large_file = (qtmux->mdat_size > MDAT_LARGE_FILE_LIMIT);
/* if faststart, update the offset of the atoms in the movie with the offset
* that the movie headers before mdat will cause */
if (qtmux->fast_start_file) {
@@ -807,7 +1047,7 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
goto serialize_error;
GST_DEBUG_OBJECT (qtmux, "calculated moov atom size %" G_GUINT64_FORMAT,
size);
- offset += qtmux->header_size + MDAT_ATOM_HEADER_SIZE;
+ offset += qtmux->header_size + (large_file ? 16 : 8);
} else
offset = qtmux->header_size;
atom_moov_chunks_add_offset (qtmux->moov, offset);
@@ -828,12 +1068,11 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
GST_DEBUG_OBJECT (qtmux, "Pushing movie atoms");
gst_qt_mux_send_buffer (qtmux, buffer, NULL, FALSE);
- /* total mdat size as of now also includes the atom header */
- qtmux->mdat_size += MDAT_ATOM_HEADER_SIZE;
/* if needed, send mdat atom and move buffered data into it */
if (qtmux->fast_start_file) {
/* mdat size = accumulated (buffered data) + mdat atom header */
- ret = gst_qt_mux_send_mdat_header (qtmux, NULL, qtmux->mdat_size);
+ ret = gst_qt_mux_send_mdat_header (qtmux, NULL, qtmux->mdat_size,
+ large_file);
if (ret != GST_FLOW_OK)
return ret;
ret = gst_qt_mux_send_buffered_data (qtmux, NULL);
@@ -927,9 +1166,9 @@ gst_qt_mux_start_file (GstQTMux * qtmux)
if (!qtmux->fast_start_file)
goto open_failed;
} else {
- ret = gst_qt_mux_send_mdat_header (qtmux, &qtmux->header_size, 0);
- /* mdat size position = current header pos - extended header size */
- qtmux->mdat_pos = qtmux->header_size - sizeof (guint64);
+ /* extended to ensure some spare space */
+ qtmux->mdat_pos = qtmux->header_size;
+ ret = gst_qt_mux_send_mdat_header (qtmux, &qtmux->header_size, 0, TRUE);
}
GST_OBJECT_UNLOCK (qtmux);
@@ -1464,7 +1703,6 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
par_den = 1;
gst_structure_get_fraction (structure, "pixel-aspect-ratio", &par_num,
&par_den);
- /* FIXME: pixel-aspect-ratio */
qtpad->is_out_of_order = FALSE;
@@ -1477,6 +1715,8 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
/* set common properties */
entry.width = width;
entry.height = height;
+ entry.par_n = par_num;
+ entry.par_d = par_den;
/* should be OK according to qt and iso spec, override if really needed */
entry.color_table_id = -1;
entry.frame_count = 1;