mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
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.
This commit is contained in:
parent
cb0b3da393
commit
ae82126a56
5 changed files with 286 additions and 3 deletions
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
|||
2008-06-29 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
|
||||
|
||||
* 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.
|
||||
|
||||
2008-06-28 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
|
||||
|
||||
* tests/check/elements/avimux.c: (check_avimux_pad):
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -1196,6 +1196,127 @@ gst_avi_demux_read_subindexes_pull (GstAviDemux * avi,
|
|||
GST_DEBUG_OBJECT (avi, "index %s", ((*index) ? "!= 0" : "== 0"));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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).
|
||||
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue