summaryrefslogtreecommitdiffstats
path: root/gst
diff options
context:
space:
mode:
authorMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>2008-06-29 19:52:51 +0000
committerMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>2008-06-29 19:52:51 +0000
commitae82126a56898c37b4e242cc370dfa28c151c471 (patch)
tree39d933da9b256e851706ea1bc2745a3bc0aed16b /gst
parentcb0b3da393b5d695d852bfb683eeb042dd62ec96 (diff)
gst/avi/avi-ids.h: Add vprp chunk related structures.
Original commit message from CVS: * gst/avi/avi-ids.h: Add vprp chunk related structures. * gst/avi/gstavidemux.c: (gst_avi_demux_riff_parse_vprp), (gst_avi_demux_parse_stream): Parse optional vprp chunk and add calculated pixel-aspect-ratio to caps. Fixes #539482. * gst/avi/gstavimux.h: * gst/avi/gstavimux.c: (gst_avi_mux_pad_reset), (gst_avi_mux_vidsink_set_caps), (gst_avi_mux_riff_get_avi_header): Add a vprp chunk if non-trival pixel-aspect-ratio provided in caps.
Diffstat (limited to 'gst')
-rw-r--r--gst/avi/avi-ids.h29
-rw-r--r--gst/avi/gstavidemux.c164
-rw-r--r--gst/avi/gstavimux.c81
-rw-r--r--gst/avi/gstavimux.h2
4 files changed, 273 insertions, 3 deletions
diff --git a/gst/avi/avi-ids.h b/gst/avi/avi-ids.h
index f9e2dd31..8ca550bf 100644
--- a/gst/avi/avi-ids.h
+++ b/gst/avi/avi-ids.h
@@ -45,4 +45,33 @@ typedef struct _gst_riff_avih {
guint32 length;
} gst_riff_avih;
+/* vprp (video properties) ODML header */
+/* see ODML spec for some/more explanation */
+#define GST_RIFF_TAG_vprp GST_MAKE_FOURCC ('v','p','r','p')
+#define GST_RIFF_VPRP_VIDEO_FIELDS (2)
+
+typedef struct _gst_riff_vprp_video_field_desc {
+ guint32 compressed_bm_height;
+ guint32 compressed_bm_width;
+ guint32 valid_bm_height;
+ guint32 valid_bm_width;
+ guint32 valid_bm_x_offset;
+ guint32 valid_bm_y_offset;
+ guint32 video_x_t_offset;
+ guint32 video_y_start;
+} gst_riff_vprp_video_field_desc;
+
+typedef struct _gst_riff_vprp {
+ guint32 format_token; /* whether fields defined by standard */
+ guint32 standard; /* video display standard, UNKNOWN, PAL, etc */
+ guint32 vert_rate; /* vertical refresh rate */
+ guint32 hor_t_total; /* width */
+ guint32 vert_lines; /* height */
+ guint32 aspect; /* aspect ratio high word:low word */
+ guint32 width; /* active width */
+ guint32 height; /* active height */
+ guint32 fields; /* field count */
+ gst_riff_vprp_video_field_desc field_info[GST_RIFF_VPRP_VIDEO_FIELDS];
+} gst_riff_vprp;
+
#endif /* __GST_AVI_H__ */
diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c
index 38211be1..a48ceee4 100644
--- a/gst/avi/gstavidemux.c
+++ b/gst/avi/gstavidemux.c
@@ -1197,6 +1197,127 @@ gst_avi_demux_read_subindexes_pull (GstAviDemux * avi,
}
/*
+ * gst_avi_demux_riff_parse_vprp:
+ * @element: caller element (used for debugging/error).
+ * @buf: input data to be used for parsing, stripped from header.
+ * @vprp: a pointer (returned by this function) to a filled-in vprp
+ * structure. Caller should free it.
+ *
+ * Parses a video streamĀ“s vprp. This function takes ownership of @buf.
+ *
+ * Returns: TRUE if parsing succeeded, otherwise FALSE. The stream
+ * should be skipped on error, but it is not fatal.
+ */
+static gboolean
+gst_avi_demux_riff_parse_vprp (GstElement * element,
+ GstBuffer * buf, gst_riff_vprp ** _vprp)
+{
+ gst_riff_vprp *vprp;
+ gint k;
+
+ g_return_val_if_fail (buf != NULL, FALSE);
+ g_return_val_if_fail (_vprp != NULL, FALSE);
+
+ if (GST_BUFFER_SIZE (buf) < G_STRUCT_OFFSET (gst_riff_vprp, field_info))
+ goto too_small;
+
+ vprp = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+
+#if (G_BYTE_ORDER == G_BIG_ENDIAN)
+ vprp->format_token = GUINT32_FROM_LE (vprp->format_token);
+ vprp->standard = GUINT32_FROM_LE (vprp->standard);
+ vprp->vert_rate = GUINT32_FROM_LE (vprp->vert_rate);
+ vprp->hor_t_total = GUINT32_FROM_LE (vprp->hor_t_total);
+ vprp->vert_lines = GUINT32_FROM_LE (vprp->vert_lines);
+ vprp->aspect = GUINT32_FROM_LE (vprp->aspect);
+ vprp->width = GUINT32_FROM_LE (vprp->width);
+ vprp->height = GUINT32_FROM_LE (vprp->height);
+ vprp->fields = GUINT32_FROM_LE (vprp->fields);
+#endif
+
+ /* size checking */
+ /* calculate fields based on size */
+ k = (GST_BUFFER_SIZE (buf) - G_STRUCT_OFFSET (gst_riff_vprp, field_info)) /
+ vprp->fields;
+ if (vprp->fields > k) {
+ GST_WARNING_OBJECT (element,
+ "vprp header indicated %d fields, only %d available", vprp->fields, k);
+ vprp->fields = k;
+ }
+ if (vprp->fields > GST_RIFF_VPRP_VIDEO_FIELDS) {
+ GST_WARNING_OBJECT (element,
+ "vprp header indicated %d fields, at most %d supported", vprp->fields,
+ GST_RIFF_VPRP_VIDEO_FIELDS);
+ vprp->fields = GST_RIFF_VPRP_VIDEO_FIELDS;
+ }
+#if (G_BYTE_ORDER == G_BIG_ENDIAN)
+ for (k = 0; k < vprp->fields; k++) {
+ gst_riff_vprp_video_field_desc *fd;
+
+ fd = &(vidpad->vprp.field_info[k]);
+ fd->compressed_bm_height = GUINT32_FROM_LE (fd->compressed_bm_height);
+ fd->compressed_bm_width = GUINT32_FROM_LE (fd->compressed_bm_width);
+ fd->valid_bm_height = GUINT32_FROM_LE (fd->valid_bm_height);
+ fd->valid_bm_width = GUINT16_FROM_LE (fd->valid_bm_width);
+ fd->valid_bm_x_offset = GUINT16_FROM_LE (fd->valid_bm_x_offset);
+ fd->valid_bm_y_offset = GUINT32_FROM_LE (fd->valid_bm_y_offset);
+ fd->video_x_t_offset = GUINT32_FROM_LE (fd->video_x_t_offset);
+ fd->video_y_start = GUINT32_FROM_LE (fd->video_y_start);
+ }
+#endif
+
+ /* debug */
+ GST_INFO_OBJECT (element, "vprp tag found in context vids:");
+ GST_INFO_OBJECT (element, " format_token %d", vprp->format_token);
+ GST_INFO_OBJECT (element, " standard %d", vprp->standard);
+ GST_INFO_OBJECT (element, " vert_rate %d", vprp->vert_rate);
+ GST_INFO_OBJECT (element, " hor_t_total %d", vprp->hor_t_total);
+ GST_INFO_OBJECT (element, " vert_lines %d", vprp->vert_lines);
+ GST_INFO_OBJECT (element, " aspect %d:%d", vprp->aspect >> 16,
+ vprp->aspect & 0xffff);
+ GST_INFO_OBJECT (element, " width %d", vprp->width);
+ GST_INFO_OBJECT (element, " height %d", vprp->height);
+ GST_INFO_OBJECT (element, " fields %d", vprp->fields);
+ for (k = 0; k < vprp->fields; k++) {
+ gst_riff_vprp_video_field_desc *fd;
+
+ fd = &(vprp->field_info[k]);
+ GST_INFO_OBJECT (element, " field %u description:", k);
+ GST_INFO_OBJECT (element, " compressed_bm_height %d",
+ fd->compressed_bm_height);
+ GST_INFO_OBJECT (element, " compressed_bm_width %d",
+ fd->compressed_bm_width);
+ GST_INFO_OBJECT (element, " valid_bm_height %d",
+ fd->valid_bm_height);
+ GST_INFO_OBJECT (element, " valid_bm_width %d", fd->valid_bm_width);
+ GST_INFO_OBJECT (element, " valid_bm_x_offset %d",
+ fd->valid_bm_x_offset);
+ GST_INFO_OBJECT (element, " valid_bm_y_offset %d",
+ fd->valid_bm_y_offset);
+ GST_INFO_OBJECT (element, " video_x_t_offset %d",
+ fd->video_x_t_offset);
+ GST_INFO_OBJECT (element, " video_y_start %d", fd->video_y_start);
+ }
+
+ gst_buffer_unref (buf);
+
+ *_vprp = vprp;
+
+ return TRUE;
+
+ /* ERRORS */
+too_small:
+ {
+ GST_ERROR_OBJECT (element,
+ "Too small vprp (%d available, at least %d needed)",
+ GST_BUFFER_SIZE (buf),
+ (int) G_STRUCT_OFFSET (gst_riff_vprp, field_info));
+ gst_buffer_unref (buf);
+ return FALSE;
+ }
+}
+
+/*
* gst_avi_demux_parse_stream:
* @avi: calling element (used for debugging/errors).
* @buf: input buffer used to parse the stream.
@@ -1223,7 +1344,8 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf)
GstCaps *caps = NULL;
GstPad *pad;
GstElement *element;
- gboolean got_strh = FALSE, got_strf = FALSE;
+ gboolean got_strh = FALSE, got_strf = FALSE, got_vprp = FALSE;
+ gst_riff_vprp *vprp = NULL;
element = GST_ELEMENT_CAST (avi);
@@ -1294,6 +1416,30 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf)
got_strf = TRUE;
break;
}
+ case GST_RIFF_TAG_vprp:
+ {
+ if (got_vprp) {
+ GST_WARNING_OBJECT (avi, "Ignoring additional vprp chunk");
+ break;
+ }
+ if (!got_strh) {
+ GST_ERROR_OBJECT (avi, "Found vprp chunk before strh chunk");
+ goto fail;
+ }
+ if (!got_strf) {
+ GST_ERROR_OBJECT (avi, "Found vprp chunk before strf chunk");
+ goto fail;
+ }
+
+ if (!gst_avi_demux_riff_parse_vprp (element, sub, &vprp)) {
+ GST_WARNING_OBJECT (avi, "Failed to parse vprp chunk");
+ /* not considered fatal */
+ g_free (vprp);
+ vprp = NULL;
+ } else
+ got_vprp = TRUE;
+ break;
+ }
case GST_RIFF_TAG_strd:
if (stream->initdata)
gst_buffer_unref (stream->initdata);
@@ -1362,6 +1508,21 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf)
if (!caps) {
caps = gst_caps_new_simple ("video/x-avi-unknown", "fourcc",
GST_TYPE_FOURCC, fourcc, NULL);
+ } else if (got_vprp && vprp) {
+ guint32 aspect_n, aspect_d;
+ gint n, d;
+
+ aspect_n = vprp->aspect >> 16;
+ aspect_d = vprp->aspect & 0xffff;
+ /* calculate the pixel aspect ratio using w/h and aspect ratio */
+ n = aspect_n * stream->strf.vids->height;
+ d = aspect_d * stream->strf.vids->width;
+ if (n && d)
+ gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+ n, d, NULL);
+ /* very local, not needed elsewhere */
+ g_free (vprp);
+ vprp = NULL;
}
tag_name = GST_TAG_VIDEO_CODEC;
avi->num_v_streams++;
@@ -1483,6 +1644,7 @@ fail:
gst_buffer_unref (buf);
if (sub)
gst_buffer_unref (sub);
+ g_free (vprp);
g_free (codec_name);
g_free (stream->strh);
g_free (stream->strf.data);
diff --git a/gst/avi/gstavimux.c b/gst/avi/gstavimux.c
index 3beff5e4..80d8ba8d 100644
--- a/gst/avi/gstavimux.c
+++ b/gst/avi/gstavimux.c
@@ -337,6 +337,7 @@ gst_avi_mux_pad_reset (GstAviPad * avipad, gboolean free)
}
memset (&(vidpad->vids), 0, sizeof (gst_riff_strf_vids));
+ memset (&(vidpad->vprp), 0, sizeof (gst_riff_vprp));
} else {
GstAviAudioPad *audpad = (GstAviAudioPad *) avipad;
@@ -425,9 +426,10 @@ gst_avi_mux_vidsink_set_caps (GstPad * pad, GstCaps * vscaps)
GstAviCollectData *collect_pad;
GstStructure *structure;
const gchar *mimetype;
- const GValue *fps;
+ const GValue *fps, *par;
const GValue *codec_data;
gint width, height;
+ gint par_n, par_d;
avimux = GST_AVI_MUX (gst_pad_get_parent (pad));
@@ -463,6 +465,36 @@ gst_avi_mux_vidsink_set_caps (GstPad * pad, GstCaps * vscaps)
avipad->parent.hdr.rate = gst_value_get_fraction_numerator (fps);
avipad->parent.hdr.scale = gst_value_get_fraction_denominator (fps);
+ /* (pixel) aspect ratio data, if any */
+ par = gst_structure_get_value (structure, "pixel-aspect-ratio");
+ /* only use video properties header if there is non-trivial aspect info */
+ if (par && GST_VALUE_HOLDS_FRACTION (par) &&
+ ((par_n = gst_value_get_fraction_numerator (par)) !=
+ (par_d = gst_value_get_fraction_denominator (par)))) {
+ GValue to_ratio = { 0, };
+ guint ratio_n, ratio_d;
+
+ /* some fraction voodoo to obtain simplest possible ratio */
+ g_value_init (&to_ratio, GST_TYPE_FRACTION);
+ gst_value_set_fraction (&to_ratio, width * par_n, height * par_d);
+ ratio_n = gst_value_get_fraction_numerator (&to_ratio);
+ ratio_d = gst_value_get_fraction_denominator (&to_ratio);
+ GST_DEBUG_OBJECT (avimux, "generating vprp data with aspect ratio %d/%d",
+ ratio_n, ratio_d);
+ /* simply fill in */
+ avipad->vprp.vert_rate = avipad->parent.hdr.rate / avipad->parent.hdr.scale;
+ avipad->vprp.hor_t_total = width;
+ avipad->vprp.vert_lines = height;
+ avipad->vprp.aspect = (ratio_n) << 16 | (ratio_d & 0xffff);
+ avipad->vprp.width = width;
+ avipad->vprp.height = height;
+ avipad->vprp.fields = 1;
+ avipad->vprp.field_info[0].compressed_bm_height = height;
+ avipad->vprp.field_info[0].compressed_bm_width = width;
+ avipad->vprp.field_info[0].valid_bm_height = height;
+ avipad->vprp.field_info[0].valid_bm_width = width;
+ }
+
/* codec initialization data, if any */
codec_data = gst_structure_get_value (structure, "codec_data");
if (codec_data) {
@@ -957,6 +989,7 @@ gst_avi_mux_riff_get_avi_header (GstAviMux * avimux)
size += avimux->codec_data_size + 100 + sizeof (gst_riff_avih)
+ (g_slist_length (avimux->sinkpads) * (100 + sizeof (gst_riff_strh_full)
+ sizeof (gst_riff_strf_vids)
+ + sizeof (gst_riff_vprp)
+ sizeof (gst_riff_strf_auds)
+ ODML_SUPERINDEX_SIZE));
buffer = gst_buffer_new_and_alloc (size);
@@ -1003,13 +1036,21 @@ gst_avi_mux_riff_get_avi_header (GstAviMux * avimux)
GstAviPad *avipad = (GstAviPad *) node->data;
GstAviVideoPad *vidpad = (GstAviVideoPad *) avipad;
GstAviAudioPad *audpad = (GstAviAudioPad *) avipad;
- guint codec_size = 0, strl_size = 0;
+ guint codec_size = 0, strl_size = 0, vprp_size = 0;
if (avipad->is_video) {
if (vidpad->vids_codec_data)
codec_size = GST_BUFFER_SIZE (vidpad->vids_codec_data);
strl_size = sizeof (gst_riff_strh_full) + sizeof (gst_riff_strf_vids)
+ codec_size + 4 * 5 + ODML_SUPERINDEX_SIZE;
+ if (vidpad->vprp.aspect) {
+ /* let's be on the safe side */
+ vidpad->vprp.fields = MIN (vidpad->vprp.fields,
+ GST_RIFF_VPRP_VIDEO_FIELDS);
+ vprp_size = G_STRUCT_OFFSET (gst_riff_vprp, field_info)
+ + (vidpad->vprp.fields * sizeof (gst_riff_vprp_video_field_desc));
+ strl_size += 4 * 2 + vprp_size;
+ }
} else {
if (audpad->auds_codec_data)
codec_size = GST_BUFFER_SIZE (audpad->auds_codec_data);
@@ -1072,6 +1113,42 @@ gst_avi_mux_riff_get_avi_header (GstAviMux * avimux)
buffdata += codec_size;
highmark += codec_size;
}
+
+ /* add video property data, mainly for aspect ratio, if any */
+ if (vprp_size) {
+ gint f;
+
+ /* the vprp header */
+ memcpy (buffdata + 0, "vprp", 4);
+ GST_WRITE_UINT32_LE (buffdata + 4, vprp_size);
+ /* the actual data */
+ GST_WRITE_UINT32_LE (buffdata + 8, vidpad->vprp.format_token);
+ GST_WRITE_UINT32_LE (buffdata + 12, vidpad->vprp.standard);
+ GST_WRITE_UINT32_LE (buffdata + 16, vidpad->vprp.vert_rate);
+ GST_WRITE_UINT32_LE (buffdata + 20, vidpad->vprp.hor_t_total);
+ GST_WRITE_UINT32_LE (buffdata + 24, vidpad->vprp.vert_lines);
+ GST_WRITE_UINT32_LE (buffdata + 28, vidpad->vprp.aspect);
+ GST_WRITE_UINT32_LE (buffdata + 32, vidpad->vprp.width);
+ GST_WRITE_UINT32_LE (buffdata + 36, vidpad->vprp.height);
+ GST_WRITE_UINT32_LE (buffdata + 40, vidpad->vprp.fields);
+ buffdata += codec_size + 44;
+ highmark += codec_size + 44;
+ for (f = 0; f < vidpad->vprp.fields; ++f) {
+ gst_riff_vprp_video_field_desc *fd;
+
+ fd = &(vidpad->vprp.field_info[f]);
+ GST_WRITE_UINT32_LE (buffdata + 0, fd->compressed_bm_height);
+ GST_WRITE_UINT32_LE (buffdata + 4, fd->compressed_bm_width);
+ GST_WRITE_UINT32_LE (buffdata + 8, fd->valid_bm_height);
+ GST_WRITE_UINT32_LE (buffdata + 12, fd->valid_bm_width);
+ GST_WRITE_UINT32_LE (buffdata + 16, fd->valid_bm_x_offset);
+ GST_WRITE_UINT32_LE (buffdata + 20, fd->valid_bm_y_offset);
+ GST_WRITE_UINT32_LE (buffdata + 24, fd->video_x_t_offset);
+ GST_WRITE_UINT32_LE (buffdata + 28, fd->video_y_start);
+ buffdata += codec_size + 32;
+ highmark += codec_size + 32;
+ }
+ }
} else {
/* the audio header */
memcpy (buffdata + 0, "strf", 4);
diff --git a/gst/avi/gstavimux.h b/gst/avi/gstavimux.h
index 0100e031..6fb9a475 100644
--- a/gst/avi/gstavimux.h
+++ b/gst/avi/gstavimux.h
@@ -89,6 +89,8 @@ typedef struct _GstAviVideoPad {
gst_riff_strf_vids vids;
/* extra data */
GstBuffer *vids_codec_data;
+ /* ODML video properties */
+ gst_riff_vprp vprp;
} GstAviVideoPad;