mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-03 15:06:34 +00:00
avimux: clean up code for avi header using a bytewriter
https://bugzilla.gnome.org/show_bug.cgi?id=619293
This commit is contained in:
parent
66a76d1f65
commit
53365b91e6
1 changed files with 199 additions and 271 deletions
|
@ -65,6 +65,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <gst/video/video.h>
|
#include <gst/video/video.h>
|
||||||
|
#include <gst/base/gstbytewriter.h>
|
||||||
|
|
||||||
#include "gstavimux.h"
|
#include "gstavimux.h"
|
||||||
|
|
||||||
|
@ -1082,16 +1083,40 @@ gst_avi_mux_release_pad (GstElement * element, GstPad * pad)
|
||||||
g_warning ("Unknown pad %s", GST_PAD_NAME (pad));
|
g_warning ("Unknown pad %s", GST_PAD_NAME (pad));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* maybe some of these functions should be moved to riff.h? */
|
static inline guint
|
||||||
|
gst_avi_mux_start_chunk (GstByteWriter * bw, const gchar * tag, guint32 fourcc)
|
||||||
/* DISCLAIMER: this function is fairly ugly. So be it (i.e. it makes the rest easier)
|
|
||||||
* so is this struct */
|
|
||||||
|
|
||||||
typedef struct _GstMarkedBuffer
|
|
||||||
{
|
{
|
||||||
guint *highmark;
|
guint chunk_offset;
|
||||||
GstBuffer *buffer;
|
|
||||||
} GstMarkedBuffer;
|
if (tag)
|
||||||
|
gst_byte_writer_put_data (bw, (const guint8 *) tag, 4);
|
||||||
|
else
|
||||||
|
gst_byte_writer_put_uint32_le (bw, fourcc);
|
||||||
|
|
||||||
|
chunk_offset = gst_byte_writer_get_pos (bw);
|
||||||
|
/* real chunk size comes later */
|
||||||
|
gst_byte_writer_put_uint32_le (bw, 0);
|
||||||
|
|
||||||
|
return chunk_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
gst_avi_mux_end_chunk (GstByteWriter * bw, guint chunk_offset)
|
||||||
|
{
|
||||||
|
guint size;
|
||||||
|
|
||||||
|
size = gst_byte_writer_get_size (bw);
|
||||||
|
|
||||||
|
gst_byte_writer_set_pos (bw, chunk_offset);
|
||||||
|
gst_byte_writer_put_uint32_le (bw, size - chunk_offset - 4);
|
||||||
|
gst_byte_writer_set_pos (bw, size);
|
||||||
|
|
||||||
|
/* arrange for even padding */
|
||||||
|
if (size & 1)
|
||||||
|
gst_byte_writer_put_uint8 (bw, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* maybe some of these functions should be moved to riff.h? */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_avi_mux_write_tag (const GstTagList * list, const gchar * tag,
|
gst_avi_mux_write_tag (const GstTagList * list, const gchar * tag,
|
||||||
|
@ -1115,48 +1140,32 @@ gst_avi_mux_write_tag (const GstTagList * list, const gchar * tag,
|
||||||
GST_RIFF_INFO_ISRC, GST_TAG_ISRC}, {
|
GST_RIFF_INFO_ISRC, GST_TAG_ISRC}, {
|
||||||
0, NULL}
|
0, NULL}
|
||||||
};
|
};
|
||||||
gint n, len, plen;
|
gint n;
|
||||||
GstBuffer *buf = ((GstMarkedBuffer *) data)->buffer;
|
|
||||||
guint *highmark = ((GstMarkedBuffer *) data)->highmark;
|
|
||||||
guint8 *buffdata = GST_BUFFER_DATA (buf) + *highmark;
|
|
||||||
gchar *str;
|
gchar *str;
|
||||||
|
GstByteWriter *bw = data;
|
||||||
|
guint chunk;
|
||||||
|
|
||||||
for (n = 0; rifftags[n].fcc != 0; n++) {
|
for (n = 0; rifftags[n].fcc != 0; n++) {
|
||||||
if (!strcmp (rifftags[n].tag, tag) &&
|
if (!strcmp (rifftags[n].tag, tag) &&
|
||||||
gst_tag_list_get_string (list, tag, &str) && str) {
|
gst_tag_list_get_string (list, tag, &str) && str) {
|
||||||
len = strlen (str);
|
chunk = gst_avi_mux_start_chunk (bw, NULL, rifftags[n].fcc);
|
||||||
plen = len + 1;
|
gst_byte_writer_put_string (bw, str);
|
||||||
if (plen & 1)
|
gst_avi_mux_end_chunk (bw, chunk);
|
||||||
plen++;
|
|
||||||
if (GST_BUFFER_SIZE (buf) >= *highmark + 8 + plen) {
|
|
||||||
GST_WRITE_UINT32_LE (buffdata, rifftags[n].fcc);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 4, len + 1);
|
|
||||||
memcpy (buffdata + 8, str, len);
|
|
||||||
buffdata[8 + len] = 0;
|
|
||||||
*highmark += 8 + plen;
|
|
||||||
GST_DEBUG ("writing tag in buffer %p, highmark at %d", buf, *highmark);
|
|
||||||
}
|
|
||||||
g_free (str);
|
g_free (str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ODML_SUPERINDEX_SIZE \
|
|
||||||
(32 + GST_AVI_SUPERINDEX_COUNT * sizeof (gst_avi_superindex_entry))
|
|
||||||
|
|
||||||
static GstBuffer *
|
static GstBuffer *
|
||||||
gst_avi_mux_riff_get_avi_header (GstAviMux * avimux)
|
gst_avi_mux_riff_get_avi_header (GstAviMux * avimux)
|
||||||
{
|
{
|
||||||
const GstTagList *tags;
|
const GstTagList *tags;
|
||||||
GstBuffer *buffer;
|
GstBuffer *buffer;
|
||||||
guint8 *buffdata;
|
gint size = 0;
|
||||||
guint size = 0;
|
GstByteWriter bw;
|
||||||
guint highmark = 0;
|
|
||||||
|
|
||||||
/* pointer to list size field */
|
|
||||||
guint8 *riff_size, *hdrl_size;
|
|
||||||
GSList *node;
|
GSList *node;
|
||||||
|
guint avih, riff, hdrl;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (avimux, "creating avi header, data_size %u, idx_size %u",
|
GST_DEBUG_OBJECT (avimux, "creating avi header, data_size %u, idx_size %u",
|
||||||
avimux->data_size, avimux->idx_size);
|
avimux->data_size, avimux->idx_size);
|
||||||
|
@ -1170,59 +1179,32 @@ gst_avi_mux_riff_get_avi_header (GstAviMux * avimux)
|
||||||
if (tags)
|
if (tags)
|
||||||
tags = avimux->tags_snap = gst_tag_list_copy (tags);
|
tags = avimux->tags_snap = gst_tag_list_copy (tags);
|
||||||
}
|
}
|
||||||
if (tags) {
|
|
||||||
/* that should be the strlen of all tags + header sizes
|
|
||||||
* not all of tags end up in a avi, still this is a good estimate
|
|
||||||
*/
|
|
||||||
gchar *str = gst_structure_to_string (tags);
|
|
||||||
size += strlen (str) + 8 * gst_structure_n_fields (tags);
|
|
||||||
g_free (str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allocate the buffer, starting with some wild/safe upper bound */
|
gst_byte_writer_init_with_size (&bw, 1024, FALSE);
|
||||||
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_vprp_video_field_desc) * 2
|
|
||||||
+ sizeof (gst_riff_strf_auds) + 2 + ODML_SUPERINDEX_SIZE));
|
|
||||||
buffer = gst_buffer_new_and_alloc (size);
|
|
||||||
buffdata = GST_BUFFER_DATA (buffer);
|
|
||||||
highmark = 0;
|
|
||||||
GST_DEBUG_OBJECT (avimux, "creating buffer %p, size %d, highmark at 0",
|
|
||||||
buffer, GST_BUFFER_SIZE (buffer));
|
|
||||||
|
|
||||||
/* avi header metadata */
|
/* avi header metadata */
|
||||||
memcpy (buffdata + 0, "RIFF", 4);
|
riff = gst_avi_mux_start_chunk (&bw, "RIFF", 0);
|
||||||
/* fill in RIFF size later */
|
gst_byte_writer_put_data (&bw, (guint8 *) "AVI ", 4);
|
||||||
riff_size = buffdata + 4;
|
hdrl = gst_avi_mux_start_chunk (&bw, "LIST", 0);
|
||||||
memcpy (buffdata + 8, "AVI ", 4);
|
gst_byte_writer_put_data (&bw, (guint8 *) "hdrl", 4);
|
||||||
memcpy (buffdata + 12, "LIST", 4);
|
|
||||||
/* fill in header size later */
|
|
||||||
hdrl_size = buffdata + 16;
|
|
||||||
memcpy (buffdata + 20, "hdrl", 4);
|
|
||||||
memcpy (buffdata + 24, "avih", 4);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 28, sizeof (gst_riff_avih));
|
|
||||||
buffdata += 32;
|
|
||||||
highmark += 32;
|
|
||||||
|
|
||||||
|
avih = gst_avi_mux_start_chunk (&bw, "avih", 0);
|
||||||
/* the AVI header itself */
|
/* the AVI header itself */
|
||||||
GST_WRITE_UINT32_LE (buffdata + 0, avimux->avi_hdr.us_frame);
|
gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.us_frame);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 4, avimux->avi_hdr.max_bps);
|
gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.max_bps);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 8, avimux->avi_hdr.pad_gran);
|
gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.pad_gran);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 12, avimux->avi_hdr.flags);
|
gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.flags);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 16, avimux->avi_hdr.tot_frames);
|
gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.tot_frames);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 20, avimux->avi_hdr.init_frames);
|
gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.init_frames);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 24, avimux->avi_hdr.streams);
|
gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.streams);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 28, avimux->avi_hdr.bufsize);
|
gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.bufsize);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 32, avimux->avi_hdr.width);
|
gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.width);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 36, avimux->avi_hdr.height);
|
gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.height);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 40, avimux->avi_hdr.scale);
|
gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.scale);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 44, avimux->avi_hdr.rate);
|
gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.rate);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 48, avimux->avi_hdr.start);
|
gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.start);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 52, avimux->avi_hdr.length);
|
gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.length);
|
||||||
buffdata += 56;
|
gst_avi_mux_end_chunk (&bw, avih);
|
||||||
highmark += 56;
|
|
||||||
|
|
||||||
/* stream data */
|
/* stream data */
|
||||||
node = avimux->sinkpads;
|
node = avimux->sinkpads;
|
||||||
|
@ -1230,242 +1212,188 @@ gst_avi_mux_riff_get_avi_header (GstAviMux * avimux)
|
||||||
GstAviPad *avipad = (GstAviPad *) node->data;
|
GstAviPad *avipad = (GstAviPad *) node->data;
|
||||||
GstAviVideoPad *vidpad = (GstAviVideoPad *) avipad;
|
GstAviVideoPad *vidpad = (GstAviVideoPad *) avipad;
|
||||||
GstAviAudioPad *audpad = (GstAviAudioPad *) avipad;
|
GstAviAudioPad *audpad = (GstAviAudioPad *) avipad;
|
||||||
guint codec_size = 0, strl_size = 0, vprp_size = 0;
|
gint codec_size = 0;
|
||||||
|
guint strh, strl, strf, indx;
|
||||||
|
|
||||||
|
/* stream list metadata */
|
||||||
|
strl = gst_avi_mux_start_chunk (&bw, "LIST", 0);
|
||||||
|
gst_byte_writer_put_data (&bw, (guint8 *) "strl", 4);
|
||||||
|
|
||||||
|
/* generic header */
|
||||||
|
strh = gst_avi_mux_start_chunk (&bw, "strh", 0);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, avipad->hdr.type);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, avipad->hdr.fcc_handler);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, avipad->hdr.flags);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, avipad->hdr.priority);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, avipad->hdr.init_frames);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, avipad->hdr.scale);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, avipad->hdr.rate);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, avipad->hdr.start);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, avipad->hdr.length);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, avipad->hdr.bufsize);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, avipad->hdr.quality);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, avipad->hdr.samplesize);
|
||||||
|
gst_byte_writer_put_uint16_le (&bw, 0);
|
||||||
|
gst_byte_writer_put_uint16_le (&bw, 0);
|
||||||
|
gst_byte_writer_put_uint16_le (&bw, 0);
|
||||||
|
gst_byte_writer_put_uint16_le (&bw, 0);
|
||||||
|
gst_avi_mux_end_chunk (&bw, strh);
|
||||||
|
|
||||||
if (avipad->is_video) {
|
if (avipad->is_video) {
|
||||||
if (vidpad->vids_codec_data)
|
codec_size = vidpad->vids_codec_data ?
|
||||||
codec_size = GST_BUFFER_SIZE (vidpad->vids_codec_data);
|
GST_BUFFER_SIZE (vidpad->vids_codec_data) : 0;
|
||||||
strl_size = sizeof (gst_riff_strh_full) + sizeof (gst_riff_strf_vids)
|
/* the video header */
|
||||||
+ GST_ROUND_UP_2 (codec_size) + 4 * 5 + ODML_SUPERINDEX_SIZE;
|
strf = gst_avi_mux_start_chunk (&bw, "strf", 0);
|
||||||
|
/* the actual header */
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vids.size + codec_size);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vids.width);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vids.height);
|
||||||
|
gst_byte_writer_put_uint16_le (&bw, vidpad->vids.planes);
|
||||||
|
gst_byte_writer_put_uint16_le (&bw, vidpad->vids.bit_cnt);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vids.compression);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vids.image_size);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vids.xpels_meter);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vids.ypels_meter);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vids.num_colors);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vids.imp_colors);
|
||||||
|
if (vidpad->vids_codec_data) {
|
||||||
|
gst_byte_writer_put_data (&bw,
|
||||||
|
GST_BUFFER_DATA (vidpad->vids_codec_data),
|
||||||
|
GST_BUFFER_SIZE (vidpad->vids_codec_data));
|
||||||
|
}
|
||||||
|
gst_avi_mux_end_chunk (&bw, strf);
|
||||||
|
|
||||||
|
/* add video property data, mainly for aspect ratio, if any */
|
||||||
if (vidpad->vprp.aspect) {
|
if (vidpad->vprp.aspect) {
|
||||||
|
gint f;
|
||||||
|
guint vprp;
|
||||||
|
|
||||||
/* let's be on the safe side */
|
/* let's be on the safe side */
|
||||||
vidpad->vprp.fields = MIN (vidpad->vprp.fields,
|
vidpad->vprp.fields = MIN (vidpad->vprp.fields,
|
||||||
GST_RIFF_VPRP_VIDEO_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);
|
|
||||||
/* +2 is codec_size field, not part of gst_riff_strf_auds */
|
|
||||||
strl_size = sizeof (gst_riff_strh_full) + sizeof (gst_riff_strf_auds) + 2
|
|
||||||
+ GST_ROUND_UP_2 (codec_size) + 4 * 5 + ODML_SUPERINDEX_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* stream list metadata */
|
|
||||||
memcpy (buffdata + 0, "LIST", 4);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 4, strl_size);
|
|
||||||
memcpy (buffdata + 8, "strl", 4);
|
|
||||||
/* generic header */
|
|
||||||
memcpy (buffdata + 12, "strh", 4);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 16, sizeof (gst_riff_strh_full));
|
|
||||||
/* the actual header */
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 20, avipad->hdr.type);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 24, avipad->hdr.fcc_handler);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 28, avipad->hdr.flags);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 32, avipad->hdr.priority);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 36, avipad->hdr.init_frames);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 40, avipad->hdr.scale);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 44, avipad->hdr.rate);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 48, avipad->hdr.start);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 52, avipad->hdr.length);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 56, avipad->hdr.bufsize);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 60, avipad->hdr.quality);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 64, avipad->hdr.samplesize);
|
|
||||||
GST_WRITE_UINT16_LE (buffdata + 68, 0);
|
|
||||||
GST_WRITE_UINT16_LE (buffdata + 70, 0);
|
|
||||||
GST_WRITE_UINT16_LE (buffdata + 72, 0);
|
|
||||||
GST_WRITE_UINT16_LE (buffdata + 74, 0);
|
|
||||||
buffdata += 76;
|
|
||||||
highmark += 76;
|
|
||||||
|
|
||||||
if (avipad->is_video) {
|
|
||||||
/* the video header */
|
|
||||||
memcpy (buffdata + 0, "strf", 4);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 4,
|
|
||||||
sizeof (gst_riff_strf_vids) + codec_size);
|
|
||||||
/* the actual header */
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 8, vidpad->vids.size + codec_size);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 12, vidpad->vids.width);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 16, vidpad->vids.height);
|
|
||||||
GST_WRITE_UINT16_LE (buffdata + 20, vidpad->vids.planes);
|
|
||||||
GST_WRITE_UINT16_LE (buffdata + 22, vidpad->vids.bit_cnt);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 24, vidpad->vids.compression);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 28, vidpad->vids.image_size);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 32, vidpad->vids.xpels_meter);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 36, vidpad->vids.ypels_meter);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 40, vidpad->vids.num_colors);
|
|
||||||
GST_WRITE_UINT32_LE (buffdata + 44, vidpad->vids.imp_colors);
|
|
||||||
buffdata += 48;
|
|
||||||
highmark += 48;
|
|
||||||
|
|
||||||
/* include codec data, if any */
|
|
||||||
if (codec_size) {
|
|
||||||
memcpy (buffdata, GST_BUFFER_DATA (vidpad->vids_codec_data),
|
|
||||||
codec_size);
|
|
||||||
|
|
||||||
buffdata += codec_size;
|
|
||||||
highmark += codec_size;
|
|
||||||
}
|
|
||||||
/* padding */
|
|
||||||
if (highmark & 0x1) {
|
|
||||||
highmark++;
|
|
||||||
buffdata++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add video property data, mainly for aspect ratio, if any */
|
|
||||||
if (vprp_size) {
|
|
||||||
gint f;
|
|
||||||
|
|
||||||
/* the vprp header */
|
/* the vprp header */
|
||||||
memcpy (buffdata + 0, "vprp", 4);
|
vprp = gst_avi_mux_start_chunk (&bw, "vprp", 0);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 4, vprp_size);
|
|
||||||
/* the actual data */
|
/* the actual data */
|
||||||
GST_WRITE_UINT32_LE (buffdata + 8, vidpad->vprp.format_token);
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.format_token);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 12, vidpad->vprp.standard);
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.standard);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 16, vidpad->vprp.vert_rate);
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.vert_rate);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 20, vidpad->vprp.hor_t_total);
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.hor_t_total);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 24, vidpad->vprp.vert_lines);
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.vert_lines);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 28, vidpad->vprp.aspect);
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.aspect);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 32, vidpad->vprp.width);
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.width);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 36, vidpad->vprp.height);
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.height);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 40, vidpad->vprp.fields);
|
gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.fields);
|
||||||
buffdata += 44;
|
|
||||||
highmark += 44;
|
|
||||||
for (f = 0; f < vidpad->vprp.fields; ++f) {
|
for (f = 0; f < vidpad->vprp.fields; ++f) {
|
||||||
gst_riff_vprp_video_field_desc *fd;
|
gst_riff_vprp_video_field_desc *fd;
|
||||||
|
|
||||||
fd = &(vidpad->vprp.field_info[f]);
|
fd = &(vidpad->vprp.field_info[f]);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 0, fd->compressed_bm_height);
|
gst_byte_writer_put_uint32_le (&bw, fd->compressed_bm_height);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 4, fd->compressed_bm_width);
|
gst_byte_writer_put_uint32_le (&bw, fd->compressed_bm_width);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 8, fd->valid_bm_height);
|
gst_byte_writer_put_uint32_le (&bw, fd->valid_bm_height);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 12, fd->valid_bm_width);
|
gst_byte_writer_put_uint32_le (&bw, fd->valid_bm_width);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 16, fd->valid_bm_x_offset);
|
gst_byte_writer_put_uint32_le (&bw, fd->valid_bm_x_offset);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 20, fd->valid_bm_y_offset);
|
gst_byte_writer_put_uint32_le (&bw, fd->valid_bm_y_offset);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 24, fd->video_x_t_offset);
|
gst_byte_writer_put_uint32_le (&bw, fd->video_x_t_offset);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 28, fd->video_y_start);
|
gst_byte_writer_put_uint32_le (&bw, fd->video_y_start);
|
||||||
buffdata += 32;
|
|
||||||
highmark += 32;
|
|
||||||
}
|
}
|
||||||
|
gst_avi_mux_end_chunk (&bw, vprp);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
codec_size = audpad->auds_codec_data ?
|
||||||
|
GST_BUFFER_SIZE (audpad->auds_codec_data) : 0;
|
||||||
/* the audio header */
|
/* the audio header */
|
||||||
memcpy (buffdata + 0, "strf", 4);
|
strf = gst_avi_mux_start_chunk (&bw, "strf", 0);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 4,
|
|
||||||
sizeof (gst_riff_strf_auds) + 2 + codec_size);
|
|
||||||
/* the actual header */
|
/* the actual header */
|
||||||
GST_WRITE_UINT16_LE (buffdata + 8, audpad->auds.format);
|
gst_byte_writer_put_uint16_le (&bw, audpad->auds.format);
|
||||||
GST_WRITE_UINT16_LE (buffdata + 10, audpad->auds.channels);
|
gst_byte_writer_put_uint16_le (&bw, audpad->auds.channels);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 12, audpad->auds.rate);
|
gst_byte_writer_put_uint32_le (&bw, audpad->auds.rate);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 16, audpad->auds.av_bps);
|
gst_byte_writer_put_uint32_le (&bw, audpad->auds.av_bps);
|
||||||
GST_WRITE_UINT16_LE (buffdata + 20, audpad->auds.blockalign);
|
gst_byte_writer_put_uint16_le (&bw, audpad->auds.blockalign);
|
||||||
GST_WRITE_UINT16_LE (buffdata + 22, audpad->auds.size);
|
gst_byte_writer_put_uint16_le (&bw, audpad->auds.size);
|
||||||
GST_WRITE_UINT16_LE (buffdata + 24, codec_size);
|
gst_byte_writer_put_uint16_le (&bw, codec_size);
|
||||||
buffdata += 26;
|
if (audpad->auds_codec_data) {
|
||||||
highmark += 26;
|
gst_byte_writer_put_data (&bw,
|
||||||
|
GST_BUFFER_DATA (audpad->auds_codec_data),
|
||||||
/* include codec data, if any */
|
GST_BUFFER_SIZE (audpad->auds_codec_data));
|
||||||
if (codec_size) {
|
|
||||||
memcpy (buffdata, GST_BUFFER_DATA (audpad->auds_codec_data),
|
|
||||||
codec_size);
|
|
||||||
|
|
||||||
buffdata += codec_size;
|
|
||||||
highmark += codec_size;
|
|
||||||
}
|
|
||||||
/* padding */
|
|
||||||
if (highmark & 0x1) {
|
|
||||||
highmark++;
|
|
||||||
buffdata++;
|
|
||||||
}
|
}
|
||||||
|
gst_avi_mux_end_chunk (&bw, strf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* odml superindex chunk */
|
/* odml superindex chunk */
|
||||||
if (avipad->idx_index > 0)
|
if (avipad->idx_index > 0)
|
||||||
memcpy (buffdata, "indx", 4);
|
indx = gst_avi_mux_start_chunk (&bw, "indx", 0);
|
||||||
else
|
else
|
||||||
memcpy (buffdata, "JUNK", 4);
|
indx = gst_avi_mux_start_chunk (&bw, "JUNK", 0);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 4, ODML_SUPERINDEX_SIZE - 8); /* chunk size */
|
gst_byte_writer_put_uint16_le (&bw, 4); /* bytes per entry */
|
||||||
GST_WRITE_UINT16_LE (buffdata + 8, 4); /* bytes per entry */
|
gst_byte_writer_put_uint8 (&bw, 0); /* index subtype */
|
||||||
buffdata[10] = 0; /* index subtype */
|
gst_byte_writer_put_uint8 (&bw, GST_AVI_INDEX_OF_INDEXES); /* index type */
|
||||||
buffdata[11] = GST_AVI_INDEX_OF_INDEXES; /* index type */
|
gst_byte_writer_put_uint32_le (&bw, avipad->idx_index); /* entries in use */
|
||||||
GST_WRITE_UINT32_LE (buffdata + 12, avipad->idx_index); /* entries in use */
|
gst_byte_writer_put_data (&bw, (guint8 *) avipad->tag, 4); /* stream id */
|
||||||
memcpy (buffdata + 16, avipad->tag, 4); /* stream id */
|
gst_byte_writer_put_uint32_le (&bw, 0); /* reserved */
|
||||||
GST_WRITE_UINT32_LE (buffdata + 20, 0); /* reserved */
|
gst_byte_writer_put_uint32_le (&bw, 0); /* reserved */
|
||||||
GST_WRITE_UINT32_LE (buffdata + 24, 0); /* reserved */
|
gst_byte_writer_put_uint32_le (&bw, 0); /* reserved */
|
||||||
GST_WRITE_UINT32_LE (buffdata + 28, 0); /* reserved */
|
gst_byte_writer_put_data (&bw, (guint8 *) avipad->idx,
|
||||||
memcpy (buffdata + 32, avipad->idx,
|
|
||||||
GST_AVI_SUPERINDEX_COUNT * sizeof (gst_avi_superindex_entry));
|
GST_AVI_SUPERINDEX_COUNT * sizeof (gst_avi_superindex_entry));
|
||||||
buffdata += ODML_SUPERINDEX_SIZE;
|
gst_avi_mux_end_chunk (&bw, indx);
|
||||||
highmark += ODML_SUPERINDEX_SIZE;
|
|
||||||
|
/* end strl for this stream */
|
||||||
|
gst_avi_mux_end_chunk (&bw, strl);
|
||||||
|
|
||||||
node = node->next;
|
node = node->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avimux->video_pads > 0) {
|
if (avimux->video_pads > 0) {
|
||||||
|
guint odml, dmlh;
|
||||||
/* odml header */
|
/* odml header */
|
||||||
memcpy (buffdata + 0, "LIST", 4);
|
odml = gst_avi_mux_start_chunk (&bw, "LIST", 0);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 4, sizeof (guint32) + 4 * 3);
|
gst_byte_writer_put_data (&bw, (guint8 *) "odml", 4);
|
||||||
memcpy (buffdata + 8, "odml", 4);
|
dmlh = gst_avi_mux_start_chunk (&bw, "dmlh", 0);
|
||||||
memcpy (buffdata + 12, "dmlh", 4);
|
gst_byte_writer_put_uint32_le (&bw, avimux->total_frames);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 16, sizeof (guint32));
|
gst_avi_mux_end_chunk (&bw, dmlh);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 20, avimux->total_frames);
|
gst_avi_mux_end_chunk (&bw, odml);
|
||||||
buffdata += 24;
|
|
||||||
highmark += 24;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_WRITE_UINT32_LE (hdrl_size, (guint32) (buffdata - hdrl_size) - 4);
|
/* end hdrl */
|
||||||
|
gst_avi_mux_end_chunk (&bw, hdrl);
|
||||||
|
|
||||||
/* tags */
|
/* tags */
|
||||||
if (tags) {
|
if (tags) {
|
||||||
guint8 *ptr;
|
guint info;
|
||||||
guint startsize;
|
|
||||||
GstMarkedBuffer data = { &highmark, buffer };
|
|
||||||
|
|
||||||
memcpy (buffdata + 0, "LIST", 4);
|
gst_avi_mux_start_chunk (&bw, "LIST", 0);
|
||||||
ptr = buffdata + 4; /* fill in later */
|
info = gst_byte_writer_put_data (&bw, (guint8 *) "INFO", 4);
|
||||||
startsize = highmark + 4;
|
|
||||||
memcpy (buffdata + 8, "INFO", 4);
|
|
||||||
buffdata += 12;
|
|
||||||
highmark += 12;
|
|
||||||
|
|
||||||
/* 12 bytes is needed for data header */
|
gst_tag_list_foreach (tags, gst_avi_mux_write_tag, &bw);
|
||||||
GST_BUFFER_SIZE (buffer) -= 12;
|
if (info == gst_byte_writer_get_size (&bw)) {
|
||||||
gst_tag_list_foreach (tags, gst_avi_mux_write_tag, &data);
|
|
||||||
GST_BUFFER_SIZE (buffer) += 12;
|
|
||||||
buffdata = GST_BUFFER_DATA (buffer) + highmark;
|
|
||||||
|
|
||||||
if (highmark - startsize - 4 == 4) {
|
|
||||||
/* no tags writen, remove the empty INFO LIST as it is useless
|
/* no tags writen, remove the empty INFO LIST as it is useless
|
||||||
* and prevents playback in vlc */
|
* and prevents playback in vlc */
|
||||||
highmark -= 12;
|
gst_byte_writer_set_pos (&bw, info - 8);
|
||||||
buffdata = GST_BUFFER_DATA (buffer) + highmark;
|
|
||||||
/* no need to erase the writen data, it will be overwriten anyway */
|
|
||||||
} else {
|
} else {
|
||||||
/* update list size */
|
gst_avi_mux_end_chunk (&bw, info);
|
||||||
GST_WRITE_UINT32_LE (ptr, highmark - startsize - 4);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* pop RIFF */
|
||||||
|
gst_avi_mux_end_chunk (&bw, riff);
|
||||||
|
|
||||||
/* avi data header */
|
/* avi data header */
|
||||||
memcpy (buffdata + 0, "LIST", 4);
|
gst_byte_writer_put_data (&bw, (guint8 *) "LIST", 4);
|
||||||
GST_WRITE_UINT32_LE (buffdata + 4, avimux->data_size);
|
gst_byte_writer_put_uint32_le (&bw, avimux->data_size);
|
||||||
memcpy (buffdata + 8, "movi", 4);
|
gst_byte_writer_put_data (&bw, (guint8 *) "movi", 4);
|
||||||
buffdata += 12;
|
|
||||||
highmark += 12;
|
|
||||||
|
|
||||||
/* finally we can fill in the RIFF size */
|
/* now get the data */
|
||||||
/* note that riff only counts the first avi chunk */
|
buffer = gst_byte_writer_free_and_get_buffer (&bw);
|
||||||
GST_WRITE_UINT32_LE (riff_size, (guint32) (buffdata - riff_size - 4) /* header and movi tags */
|
|
||||||
+avimux->idx_size + avimux->data_size - 4); /* movi data and index */
|
|
||||||
|
|
||||||
{ /* only the part that is filled in actually makes up the header
|
/* ... but RIFF includes more than just header */
|
||||||
* unref the parent as we only need this part from now on */
|
size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buffer) + 4);
|
||||||
GstBuffer *subbuffer = gst_buffer_create_sub (buffer, 0, highmark);
|
size += 8 + avimux->data_size + avimux->idx_size;
|
||||||
|
GST_WRITE_UINT32_LE (GST_BUFFER_DATA (buffer) + 4, size);
|
||||||
|
|
||||||
gst_buffer_unref (buffer);
|
GST_MEMDUMP_OBJECT (avimux, "avi header", GST_BUFFER_DATA (buffer),
|
||||||
return subbuffer;
|
GST_BUFFER_SIZE (buffer));
|
||||||
}
|
|
||||||
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstBuffer *
|
static GstBuffer *
|
||||||
|
|
Loading…
Reference in a new issue