mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-20 08:41:07 +00:00
wavenc: add tags & toc support
Write tags as LIST INFO chunk. Format the toc as cue + LIST adtl chunk. Remove old #ifdef'ed code.
This commit is contained in:
parent
1f0600ee6f
commit
db29522a43
2 changed files with 154 additions and 308 deletions
|
@ -44,6 +44,7 @@
|
||||||
|
|
||||||
#include <gst/audio/audio.h>
|
#include <gst/audio/audio.h>
|
||||||
#include <gst/riff/riff-media.h>
|
#include <gst/riff/riff-media.h>
|
||||||
|
#include <gst/base/gstbytewriter.h>
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_STATIC (wavenc_debug);
|
GST_DEBUG_CATEGORY_STATIC (wavenc_debug);
|
||||||
#define GST_CAT_DEFAULT wavenc_debug
|
#define GST_CAT_DEFAULT wavenc_debug
|
||||||
|
@ -156,6 +157,7 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
|
|
||||||
#define gst_wavenc_parent_class parent_class
|
#define gst_wavenc_parent_class parent_class
|
||||||
G_DEFINE_TYPE_WITH_CODE (GstWavEnc, gst_wavenc, GST_TYPE_ELEMENT,
|
G_DEFINE_TYPE_WITH_CODE (GstWavEnc, gst_wavenc, GST_TYPE_ELEMENT,
|
||||||
|
G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL)
|
||||||
G_IMPLEMENT_INTERFACE (GST_TYPE_TOC_SETTER, NULL)
|
G_IMPLEMENT_INTERFACE (GST_TYPE_TOC_SETTER, NULL)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -209,7 +211,7 @@ gst_wavenc_init (GstWavEnc * wavenc)
|
||||||
#define WAV_HEADER_LEN 44
|
#define WAV_HEADER_LEN 44
|
||||||
|
|
||||||
static GstBuffer *
|
static GstBuffer *
|
||||||
gst_wavenc_create_header_buf (GstWavEnc * wavenc, guint audio_data_size)
|
gst_wavenc_create_header_buf (GstWavEnc * wavenc)
|
||||||
{
|
{
|
||||||
struct wave_header wave;
|
struct wave_header wave;
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
|
@ -221,25 +223,24 @@ gst_wavenc_create_header_buf (GstWavEnc * wavenc, guint audio_data_size)
|
||||||
header = map.data;
|
header = map.data;
|
||||||
memset (header, 0, WAV_HEADER_LEN);
|
memset (header, 0, WAV_HEADER_LEN);
|
||||||
|
|
||||||
wave.common.wChannels = wavenc->channels;
|
|
||||||
wave.common.wBitsPerSample = wavenc->width;
|
|
||||||
wave.common.dwSamplesPerSec = wavenc->rate;
|
|
||||||
|
|
||||||
/* Fill out our wav-header with some information */
|
|
||||||
memcpy (wave.riff.id, "RIFF", 4);
|
memcpy (wave.riff.id, "RIFF", 4);
|
||||||
wave.riff.len = audio_data_size + WAV_HEADER_LEN - 8;
|
wave.riff.len =
|
||||||
|
wavenc->meta_length + wavenc->audio_length + WAV_HEADER_LEN - 8;
|
||||||
memcpy (wave.riff.wav_id, "WAVE", 4);
|
memcpy (wave.riff.wav_id, "WAVE", 4);
|
||||||
|
|
||||||
memcpy (wave.format.id, "fmt ", 4);
|
memcpy (wave.format.id, "fmt ", 4);
|
||||||
wave.format.len = 16;
|
wave.format.len = 16;
|
||||||
|
|
||||||
|
wave.common.wChannels = wavenc->channels;
|
||||||
|
wave.common.wBitsPerSample = wavenc->width;
|
||||||
|
wave.common.dwSamplesPerSec = wavenc->rate;
|
||||||
wave.common.wFormatTag = wavenc->format;
|
wave.common.wFormatTag = wavenc->format;
|
||||||
wave.common.wBlockAlign = (wavenc->width / 8) * wave.common.wChannels;
|
wave.common.wBlockAlign = (wavenc->width / 8) * wave.common.wChannels;
|
||||||
wave.common.dwAvgBytesPerSec =
|
wave.common.dwAvgBytesPerSec =
|
||||||
wave.common.wBlockAlign * wave.common.dwSamplesPerSec;
|
wave.common.wBlockAlign * wave.common.dwSamplesPerSec;
|
||||||
|
|
||||||
memcpy (wave.data.id, "data", 4);
|
memcpy (wave.data.id, "data", 4);
|
||||||
wave.data.len = audio_data_size;
|
wave.data.len = wavenc->audio_length;
|
||||||
|
|
||||||
memcpy (header, (char *) wave.riff.id, 4);
|
memcpy (header, (char *) wave.riff.id, 4);
|
||||||
GST_WRITE_UINT32_LE (header + 4, wave.riff.len);
|
GST_WRITE_UINT32_LE (header + 4, wave.riff.len);
|
||||||
|
@ -261,7 +262,7 @@ gst_wavenc_create_header_buf (GstWavEnc * wavenc, guint audio_data_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_wavenc_push_header (GstWavEnc * wavenc, guint audio_data_size)
|
gst_wavenc_push_header (GstWavEnc * wavenc)
|
||||||
{
|
{
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
GstBuffer *outbuf;
|
GstBuffer *outbuf;
|
||||||
|
@ -271,9 +272,10 @@ gst_wavenc_push_header (GstWavEnc * wavenc, guint audio_data_size)
|
||||||
gst_segment_init (&segment, GST_FORMAT_BYTES);
|
gst_segment_init (&segment, GST_FORMAT_BYTES);
|
||||||
gst_pad_push_event (wavenc->srcpad, gst_event_new_segment (&segment));
|
gst_pad_push_event (wavenc->srcpad, gst_event_new_segment (&segment));
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (wavenc, "writing header with datasize=%u", audio_data_size);
|
GST_DEBUG_OBJECT (wavenc, "writing header, meta_size=%u, audio_size=%u",
|
||||||
|
wavenc->meta_length, wavenc->audio_length);
|
||||||
|
|
||||||
outbuf = gst_wavenc_create_header_buf (wavenc, audio_data_size);
|
outbuf = gst_wavenc_create_header_buf (wavenc);
|
||||||
GST_BUFFER_OFFSET (outbuf) = 0;
|
GST_BUFFER_OFFSET (outbuf) = 0;
|
||||||
|
|
||||||
ret = gst_pad_push (wavenc->srcpad, outbuf);
|
ret = gst_pad_push (wavenc->srcpad, outbuf);
|
||||||
|
@ -357,286 +359,104 @@ fail:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
static void
|
||||||
static struct _maps
|
gst_wavparse_tags_foreach (const GstTagList * tags, const gchar * tag,
|
||||||
|
gpointer data)
|
||||||
{
|
{
|
||||||
const guint32 id;
|
const struct
|
||||||
const gchar *name;
|
|
||||||
} maps[] = {
|
|
||||||
{
|
{
|
||||||
GST_RIFF_INFO_IARL, "Location"}, {
|
guint32 fcc;
|
||||||
GST_RIFF_INFO_IART, "Artist"}, {
|
const gchar *tag;
|
||||||
GST_RIFF_INFO_ICMS, "Commissioner"}, {
|
} rifftags[] = {
|
||||||
GST_RIFF_INFO_ICMT, "Comment"}, {
|
{
|
||||||
GST_RIFF_INFO_ICOP, "Copyright"}, {
|
GST_RIFF_INFO_IARL, GST_TAG_LOCATION}, {
|
||||||
GST_RIFF_INFO_ICRD, "Creation Date"}, {
|
GST_RIFF_INFO_IART, GST_TAG_ARTIST}, {
|
||||||
GST_RIFF_INFO_IENG, "Engineer"}, {
|
GST_RIFF_INFO_ICMT, GST_TAG_COMMENT}, {
|
||||||
GST_RIFF_INFO_IGNR, "Genre"}, {
|
GST_RIFF_INFO_ICOP, GST_TAG_COPYRIGHT}, {
|
||||||
GST_RIFF_INFO_IKEY, "Keywords"}, {
|
GST_RIFF_INFO_ICRD, GST_TAG_DATE}, {
|
||||||
GST_RIFF_INFO_INAM, "Title"}, {
|
GST_RIFF_INFO_IGNR, GST_TAG_GENRE}, {
|
||||||
GST_RIFF_INFO_IPRD, "Product"}, {
|
GST_RIFF_INFO_IKEY, GST_TAG_KEYWORDS}, {
|
||||||
GST_RIFF_INFO_ISBJ, "Subject"}, {
|
GST_RIFF_INFO_INAM, GST_TAG_TITLE}, {
|
||||||
GST_RIFF_INFO_ISFT, "Software"}, {
|
GST_RIFF_INFO_IPRD, GST_TAG_ALBUM}, {
|
||||||
GST_RIFF_INFO_ITCH, "Technician"}
|
GST_RIFF_INFO_ISBJ, GST_TAG_ALBUM_ARTIST}, {
|
||||||
};
|
GST_RIFF_INFO_ISFT, GST_TAG_ENCODER}, {
|
||||||
|
GST_RIFF_INFO_ISRC, GST_TAG_ISRC}, {
|
||||||
static guint32
|
0, NULL}
|
||||||
get_id_from_name (const char *name)
|
};
|
||||||
{
|
gint n;
|
||||||
int i;
|
gchar *str = NULL;
|
||||||
|
GstByteWriter *bw = data;
|
||||||
for (i = 0; i < G_N_ELEMENTS (maps); i++) {
|
for (n = 0; rifftags[n].fcc != 0; n++) {
|
||||||
if (strcasecmp (maps[i].name, name) == 0) {
|
if (!strcmp (rifftags[n].tag, tag)) {
|
||||||
return maps[i].id;
|
if (rifftags[n].fcc == GST_RIFF_INFO_ICRD) {
|
||||||
}
|
GDate *date;
|
||||||
}
|
/* special case for the date tag */
|
||||||
|
if (gst_tag_list_get_date (tags, tag, &date)) {
|
||||||
return 0;
|
str =
|
||||||
}
|
g_strdup_printf ("%04d:%02d:%02d", g_date_get_year (date),
|
||||||
|
g_date_get_month (date), g_date_get_day (date));
|
||||||
static void
|
g_date_free (date);
|
||||||
write_metadata (GstWavEnc * wavenc)
|
}
|
||||||
{
|
} else {
|
||||||
GString *info_str;
|
gst_tag_list_get_string (tags, tag, &str);
|
||||||
GList *props;
|
}
|
||||||
int total = 4;
|
if (str) {
|
||||||
gboolean need_to_write = FALSE;
|
gst_byte_writer_put_uint32_le (bw, rifftags[n].fcc);
|
||||||
|
gst_byte_writer_put_uint32_le (bw, GST_ROUND_UP_2 (strlen (str)));
|
||||||
info_str = g_string_new ("LIST INFO");
|
gst_byte_writer_put_string (bw, str);
|
||||||
|
g_free (str);
|
||||||
for (props = wavenc->metadata->properties->properties; props;
|
str = NULL;
|
||||||
props = props->next) {
|
break;
|
||||||
GstPropsEntry *entry = props->data;
|
|
||||||
const char *name;
|
|
||||||
guint32 id;
|
|
||||||
|
|
||||||
name = gst_props_entry_get_name (entry);
|
|
||||||
id = get_id_from_name (name);
|
|
||||||
if (id != 0) {
|
|
||||||
const char *text;
|
|
||||||
char *tmp;
|
|
||||||
int len, req, i;
|
|
||||||
|
|
||||||
need_to_write = TRUE; /* We've got at least one entry */
|
|
||||||
|
|
||||||
gst_props_entry_get_string (entry, &text);
|
|
||||||
len = strlen (text) + 1; /* The length in the file includes the \0 */
|
|
||||||
|
|
||||||
tmp = g_strdup_printf ("%" GST_FOURCC_FORMAT "%d%s", GST_FOURCC_ARGS (id),
|
|
||||||
GUINT32_TO_LE (len), text);
|
|
||||||
g_string_append (info_str, tmp);
|
|
||||||
g_free (tmp);
|
|
||||||
|
|
||||||
/* Check that we end on an even boundary */
|
|
||||||
req = ((len + 8) + 1) & ~1;
|
|
||||||
for (i = 0; i < req - len; i++) {
|
|
||||||
g_string_append_printf (info_str, "%c", 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
total += req;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (need_to_write) {
|
|
||||||
GstBuffer *buf;
|
|
||||||
|
|
||||||
/* Now we've got all the strings together, we can write our length in */
|
|
||||||
info_str->str[4] = GUINT32_TO_LE (total);
|
|
||||||
|
|
||||||
buf = gst_buffer_new ();
|
|
||||||
gst_buffer_set_data (buf, info_str->str, info_str->len);
|
|
||||||
|
|
||||||
gst_pad_push (wavenc->srcpad, GST_DATA (buf));
|
|
||||||
g_string_free (info_str, FALSE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static GstFlowReturn
|
||||||
write_cues (GstWavEnc * wavenc)
|
gst_wavenc_write_tags (GstWavEnc * wavenc)
|
||||||
{
|
{
|
||||||
GString *cue_string, *point_string;
|
const GstTagList *user_tags;
|
||||||
|
GstTagList *tags;
|
||||||
|
guint size;
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
GList *cue_list, *c;
|
GstByteWriter bw;
|
||||||
int num_cues, total = 4;
|
|
||||||
|
|
||||||
if (gst_props_get (wavenc->metadata->properties,
|
g_return_val_if_fail (wavenc != NULL, GST_FLOW_OK);
|
||||||
"cues", &cue_list, NULL) == FALSE) {
|
|
||||||
/* No cues, move along please, nothing to see here */
|
user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (wavenc));
|
||||||
return;
|
if ((!wavenc->tags) && (!user_tags)) {
|
||||||
|
GST_DEBUG_OBJECT (wavenc, "have no tags");
|
||||||
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
tags =
|
||||||
|
gst_tag_list_merge (user_tags, wavenc->tags,
|
||||||
|
gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (wavenc)));
|
||||||
|
|
||||||
/* Space for 'cue ', chunk size and number of cuepoints */
|
GST_DEBUG_OBJECT (wavenc, "writing tags");
|
||||||
cue_string = g_string_new ("cue ");
|
|
||||||
#define CUEPOINT_SIZE 24
|
|
||||||
point_string = g_string_sized_new (CUEPOINT_SIZE);
|
|
||||||
|
|
||||||
for (c = cue_list, num_cues = 0; c; c = c->next, num_cues++) {
|
gst_byte_writer_init_with_size (&bw, 1024, FALSE);
|
||||||
GstCaps *cue_caps = c->data;
|
|
||||||
guint32 pos;
|
|
||||||
|
|
||||||
gst_props_get (cue_caps->properties, "position", &pos, NULL);
|
/* add LIST INFO chunk */
|
||||||
|
gst_byte_writer_put_data (&bw, (const guint8 *) "LIST", 4);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, 0);
|
||||||
|
gst_byte_writer_put_data (&bw, (const guint8 *) "INFO", 4);
|
||||||
|
|
||||||
point_string->str[0] = GUINT32_TO_LE (num_cues + 1);
|
/* add tags */
|
||||||
point_string->str[4] = GUINT32_TO_LE (0);
|
gst_tag_list_foreach (tags, gst_wavparse_tags_foreach, &bw);
|
||||||
/* Fixme: There is probably a macro for this */
|
|
||||||
point_string->str[8] = 'd';
|
|
||||||
point_string->str[9] = 'a';
|
|
||||||
point_string->str[10] = 't';
|
|
||||||
point_string->str[11] = 'a';
|
|
||||||
point_string->str[12] = GUINT32_TO_LE (0);
|
|
||||||
point_string->str[16] = GUINT32_TO_LE (0);
|
|
||||||
point_string->str[20] = GUINT32_TO_LE (pos);
|
|
||||||
|
|
||||||
total += CUEPOINT_SIZE;
|
/* sets real size of LIST INFO chunk */
|
||||||
}
|
size = gst_byte_writer_get_pos (&bw);
|
||||||
|
gst_byte_writer_set_pos (&bw, 4);
|
||||||
|
gst_byte_writer_put_uint32_le (&bw, size - 8);
|
||||||
|
|
||||||
/* Set the length and chunk size */
|
gst_tag_list_unref (tags);
|
||||||
cue_string->str[4] = GUINT32_TO_LE (total);
|
|
||||||
cue_string->str[8] = GUINT32_TO_LE (num_cues);
|
|
||||||
/* Stick the cue points on the end */
|
|
||||||
g_string_append (cue_string, point_string->str);
|
|
||||||
g_string_free (point_string, TRUE);
|
|
||||||
|
|
||||||
buf = gst_buffer_new ();
|
buf = gst_byte_writer_reset_and_get_buffer (&bw);
|
||||||
gst_buffer_set_data (buf, cue_string->str, cue_string->len);
|
wavenc->meta_length += gst_buffer_get_size (buf);
|
||||||
|
return gst_pad_push (wavenc->srcpad, buf);
|
||||||
gst_pad_push (wavenc->srcpad, GST_DATA (buf));
|
|
||||||
g_string_free (cue_string, FALSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
write_labels (GstWavEnc * wavenc)
|
|
||||||
{
|
|
||||||
GstBuffer *buf;
|
|
||||||
GString *info_str;
|
|
||||||
int total = 4;
|
|
||||||
GList *caps;
|
|
||||||
|
|
||||||
info_str = g_string_new ("LIST adtl");
|
|
||||||
if (gst_props_get (wavenc->metadata->properties, "ltxts", &caps, NULL)) {
|
|
||||||
GList *p;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (p = caps, i = 1; p; p = p->next, i++) {
|
|
||||||
GstCaps *ltxt_caps = p->data;
|
|
||||||
GString *ltxt;
|
|
||||||
char *label = NULL;
|
|
||||||
int len, req, j;
|
|
||||||
|
|
||||||
gst_props_get (ltxt_caps->properties, "name", &label, NULL);
|
|
||||||
len = strlen (label);
|
|
||||||
|
|
||||||
#define LTXT_SIZE 28
|
|
||||||
ltxt = g_string_new ("ltxt ");
|
|
||||||
ltxt->str[8] = GUINT32_TO_LE (i); /* Identifier */
|
|
||||||
ltxt->str[12] = GUINT32_TO_LE (0); /* Sample Length */
|
|
||||||
ltxt->str[16] = GUINT32_TO_LE (0); /* FIXME: Don't save the purpose yet */
|
|
||||||
ltxt->str[20] = GUINT16_TO_LE (0); /* Country */
|
|
||||||
ltxt->str[22] = GUINT16_TO_LE (0); /* Language */
|
|
||||||
ltxt->str[24] = GUINT16_TO_LE (0); /* Dialect */
|
|
||||||
ltxt->str[26] = GUINT16_TO_LE (0); /* Code Page */
|
|
||||||
g_string_append (ltxt, label);
|
|
||||||
g_free (label);
|
|
||||||
|
|
||||||
len += LTXT_SIZE;
|
|
||||||
|
|
||||||
ltxt->str[4] = GUINT32_TO_LE (len);
|
|
||||||
|
|
||||||
/* Check that we end on an even boundary */
|
|
||||||
req = ((len + 8) + 1) & ~1;
|
|
||||||
for (j = 0; j < req - len; j++) {
|
|
||||||
g_string_append_printf (ltxt, "%c", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
total += req;
|
|
||||||
|
|
||||||
g_string_append (info_str, ltxt->str);
|
|
||||||
g_string_free (ltxt, TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gst_props_get (wavenc->metadata->properties, "labels", &caps, NULL)) {
|
|
||||||
GList *p;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (p = caps, i = 1; p; p = p->next, i++) {
|
|
||||||
GstCaps *labl_caps = p->data;
|
|
||||||
GString *labl;
|
|
||||||
char *label = NULL;
|
|
||||||
int len, req, j;
|
|
||||||
|
|
||||||
gst_props_get (labl_caps->properties, "name", &label, NULL);
|
|
||||||
len = strlen (label);
|
|
||||||
|
|
||||||
#define LABL_SIZE 4
|
|
||||||
labl = g_string_new ("labl ");
|
|
||||||
labl->str[8] = GUINT32_TO_LE (i);
|
|
||||||
g_string_append (labl, label);
|
|
||||||
g_free (label);
|
|
||||||
|
|
||||||
len += LABL_SIZE;
|
|
||||||
|
|
||||||
labl->str[4] = GUINT32_TO_LE (len);
|
|
||||||
|
|
||||||
/* Check our size */
|
|
||||||
req = ((len + 8) + 1) & ~1;
|
|
||||||
for (j = 0; j < req - len; j++) {
|
|
||||||
g_string_append_printf (labl, "%c", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
total += req;
|
|
||||||
|
|
||||||
g_string_append (info_str, labl->str);
|
|
||||||
g_string_free (labl, TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gst_props_get (wavenc->metadata->properties, "notes", &caps, NULL)) {
|
|
||||||
GList *p;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (p = caps, i = 1; p; p = p->next, i++) {
|
|
||||||
GstCaps *note_caps = p->data;
|
|
||||||
GString *note;
|
|
||||||
char *label = NULL;
|
|
||||||
int len, req, j;
|
|
||||||
|
|
||||||
gst_props_get (note_caps->properties, "name", &label, NULL);
|
|
||||||
len = strlen (label);
|
|
||||||
|
|
||||||
#define NOTE_SIZE 4
|
|
||||||
note = g_string_new ("note ");
|
|
||||||
note->str[8] = GUINT32_TO_LE (i);
|
|
||||||
g_string_append (note, label);
|
|
||||||
g_free (label);
|
|
||||||
|
|
||||||
len += NOTE_SIZE;
|
|
||||||
|
|
||||||
note->str[4] = GUINT32_TO_LE (len);
|
|
||||||
|
|
||||||
/* Size check */
|
|
||||||
req = ((len + 8) + 1) & ~1;
|
|
||||||
for (j = 0; j < req - len; j++) {
|
|
||||||
g_string_append_printf (note, "%c", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
total += req;
|
|
||||||
|
|
||||||
g_string_append (info_str, note->str);
|
|
||||||
g_string_free (note, TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
info_str->str[4] = GUINT32_TO_LE (total);
|
|
||||||
|
|
||||||
buf = gst_buffer_new ();
|
|
||||||
gst_buffer_set_data (buf, info_str->str, info_str->len);
|
|
||||||
|
|
||||||
gst_pad_push (wavenc->srcpad, GST_DATA (buf));
|
|
||||||
g_string_free (info_str, FALSE);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_wavenc_is_cue_id_unique (guint32 id, GList * list)
|
gst_wavenc_is_cue_id_unique (guint32 id, GList * list)
|
||||||
{
|
{
|
||||||
|
@ -793,7 +613,7 @@ gst_wavenc_write_notes (guint8 ** data, GList * list)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static GstFlowReturn
|
||||||
gst_wavenc_write_toc (GstWavEnc * wavenc)
|
gst_wavenc_write_toc (GstWavEnc * wavenc)
|
||||||
{
|
{
|
||||||
GList *list;
|
GList *list;
|
||||||
|
@ -804,18 +624,21 @@ gst_wavenc_write_toc (GstWavEnc * wavenc)
|
||||||
guint8 *data;
|
guint8 *data;
|
||||||
guint32 ncues, size, cues_size, labls_size, notes_size;
|
guint32 ncues, size, cues_size, labls_size, notes_size;
|
||||||
|
|
||||||
|
if (!wavenc->toc) {
|
||||||
|
GST_DEBUG_OBJECT (wavenc, "have no toc, checking toc_setter");
|
||||||
|
wavenc->toc = gst_toc_setter_get_toc (GST_TOC_SETTER (wavenc));
|
||||||
|
}
|
||||||
|
if (!wavenc->toc) {
|
||||||
|
GST_WARNING_OBJECT (wavenc, "have no toc");
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
toc = gst_toc_ref (wavenc->toc);
|
||||||
size = 0;
|
size = 0;
|
||||||
cues_size = 0;
|
cues_size = 0;
|
||||||
labls_size = 0;
|
labls_size = 0;
|
||||||
notes_size = 0;
|
notes_size = 0;
|
||||||
|
|
||||||
if (wavenc->toc) {
|
|
||||||
toc = gst_toc_ref (wavenc->toc);
|
|
||||||
} else {
|
|
||||||
GST_WARNING_OBJECT (wavenc, "TOC not found");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check if the TOC entries is valid */
|
/* check if the TOC entries is valid */
|
||||||
list = gst_toc_get_entries (toc);
|
list = gst_toc_get_entries (toc);
|
||||||
entry = list->data;
|
entry = list->data;
|
||||||
|
@ -935,10 +758,9 @@ gst_wavenc_write_toc (GstWavEnc * wavenc)
|
||||||
g_list_free_full (wavenc->notes, g_free);
|
g_list_free_full (wavenc->notes, g_free);
|
||||||
|
|
||||||
gst_buffer_unmap (buf, &map);
|
gst_buffer_unmap (buf, &map);
|
||||||
|
wavenc->meta_length += gst_buffer_get_size (buf);
|
||||||
|
|
||||||
gst_pad_push (wavenc->srcpad, buf);
|
return gst_pad_push (wavenc->srcpad, buf);
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -946,6 +768,7 @@ gst_wavenc_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
{
|
{
|
||||||
gboolean res = TRUE;
|
gboolean res = TRUE;
|
||||||
GstWavEnc *wavenc;
|
GstWavEnc *wavenc;
|
||||||
|
GstTagList *tags;
|
||||||
GstToc *toc;
|
GstToc *toc;
|
||||||
|
|
||||||
wavenc = GST_WAVENC (parent);
|
wavenc = GST_WAVENC (parent);
|
||||||
|
@ -962,26 +785,24 @@ gst_wavenc_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GST_EVENT_EOS:{
|
case GST_EVENT_EOS:
|
||||||
|
{
|
||||||
|
GstFlowReturn flow;
|
||||||
GST_DEBUG_OBJECT (wavenc, "got EOS");
|
GST_DEBUG_OBJECT (wavenc, "got EOS");
|
||||||
if (!wavenc->toc) {
|
|
||||||
GST_DEBUG_OBJECT (wavenc, "have no toc, checking toc_setter");
|
flow = gst_wavenc_write_toc (wavenc);
|
||||||
wavenc->toc = gst_toc_setter_get_toc (GST_TOC_SETTER (wavenc));
|
if (flow != GST_FLOW_OK) {
|
||||||
|
GST_WARNING_OBJECT (wavenc, "error pushing toc: %s",
|
||||||
|
gst_flow_get_name (flow));
|
||||||
}
|
}
|
||||||
if (wavenc->toc) {
|
flow = gst_wavenc_write_tags (wavenc);
|
||||||
GST_DEBUG_OBJECT (wavenc, "have toc");
|
if (flow != GST_FLOW_OK) {
|
||||||
gst_wavenc_write_toc (wavenc);
|
GST_WARNING_OBJECT (wavenc, "error pushing tags: %s",
|
||||||
|
gst_flow_get_name (flow));
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
/* Write our metadata if we have any */
|
|
||||||
if (wavenc->metadata) {
|
|
||||||
write_metadata (wavenc);
|
|
||||||
write_cues (wavenc);
|
|
||||||
write_labels (wavenc);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/* write header with correct length values */
|
/* write header with correct length values */
|
||||||
gst_wavenc_push_header (wavenc, wavenc->length);
|
gst_wavenc_push_header (wavenc);
|
||||||
|
|
||||||
/* we're done with this file */
|
/* we're done with this file */
|
||||||
wavenc->finished_properly = TRUE;
|
wavenc->finished_properly = TRUE;
|
||||||
|
@ -1008,6 +829,19 @@ gst_wavenc_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
}
|
}
|
||||||
res = gst_pad_event_default (pad, parent, event);
|
res = gst_pad_event_default (pad, parent, event);
|
||||||
break;
|
break;
|
||||||
|
case GST_EVENT_TAG:
|
||||||
|
gst_event_parse_tag (event, &tags);
|
||||||
|
if (tags) {
|
||||||
|
if (wavenc->tags != tags) {
|
||||||
|
if (wavenc->tags)
|
||||||
|
gst_tag_list_unref (wavenc->tags);
|
||||||
|
wavenc->tags = tags;
|
||||||
|
} else {
|
||||||
|
gst_toc_unref (tags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res = gst_pad_event_default (pad, parent, event);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
res = gst_pad_event_default (pad, parent, event);
|
res = gst_pad_event_default (pad, parent, event);
|
||||||
break;
|
break;
|
||||||
|
@ -1024,17 +858,18 @@ gst_wavenc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||||||
|
|
||||||
g_return_val_if_fail (wavenc->channels > 0, GST_FLOW_FLUSHING);
|
g_return_val_if_fail (wavenc->channels > 0, GST_FLOW_FLUSHING);
|
||||||
|
|
||||||
if (!wavenc->sent_header) {
|
if (G_UNLIKELY (!wavenc->sent_header)) {
|
||||||
/* use bogus size initially, we'll write the real
|
|
||||||
* header when we get EOS and know the exact length */
|
|
||||||
flow = gst_wavenc_push_header (wavenc, 0x7FFF0000);
|
|
||||||
|
|
||||||
/* starting a file, means we have to finish it properly */
|
/* starting a file, means we have to finish it properly */
|
||||||
wavenc->finished_properly = FALSE;
|
wavenc->finished_properly = FALSE;
|
||||||
|
|
||||||
if (flow != GST_FLOW_OK)
|
/* use bogus size initially, we'll write the real
|
||||||
|
* header when we get EOS and know the exact length */
|
||||||
|
flow = gst_wavenc_push_header (wavenc);
|
||||||
|
if (flow != GST_FLOW_OK) {
|
||||||
|
GST_WARNING_OBJECT (wavenc, "error pushing header: %s",
|
||||||
|
gst_flow_get_name (flow));
|
||||||
return flow;
|
return flow;
|
||||||
|
}
|
||||||
GST_DEBUG_OBJECT (wavenc, "wrote dummy header");
|
GST_DEBUG_OBJECT (wavenc, "wrote dummy header");
|
||||||
wavenc->sent_header = TRUE;
|
wavenc->sent_header = TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1045,10 +880,10 @@ gst_wavenc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||||||
|
|
||||||
buf = gst_buffer_make_writable (buf);
|
buf = gst_buffer_make_writable (buf);
|
||||||
|
|
||||||
GST_BUFFER_OFFSET (buf) = WAV_HEADER_LEN + wavenc->length;
|
GST_BUFFER_OFFSET (buf) = WAV_HEADER_LEN + wavenc->audio_length;
|
||||||
GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
|
GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
|
||||||
|
|
||||||
wavenc->length += gst_buffer_get_size (buf);
|
wavenc->audio_length += gst_buffer_get_size (buf);
|
||||||
|
|
||||||
flow = gst_pad_push (wavenc->srcpad, buf);
|
flow = gst_pad_push (wavenc->srcpad, buf);
|
||||||
|
|
||||||
|
@ -1067,7 +902,8 @@ gst_wavenc_change_state (GstElement * element, GstStateChange transition)
|
||||||
wavenc->channels = 0;
|
wavenc->channels = 0;
|
||||||
wavenc->width = 0;
|
wavenc->width = 0;
|
||||||
wavenc->rate = 0;
|
wavenc->rate = 0;
|
||||||
wavenc->length = 0;
|
wavenc->audio_length = 0;
|
||||||
|
wavenc->meta_length = 0;
|
||||||
wavenc->sent_header = FALSE;
|
wavenc->sent_header = FALSE;
|
||||||
/* its true because we haven't writen anything */
|
/* its true because we haven't writen anything */
|
||||||
wavenc->finished_properly = TRUE;
|
wavenc->finished_properly = TRUE;
|
||||||
|
@ -1090,11 +926,17 @@ gst_wavenc_change_state (GstElement * element, GstStateChange transition)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
|
GST_DEBUG_OBJECT (wavenc, "tags: %p", wavenc->tags);
|
||||||
|
if (wavenc->tags) {
|
||||||
|
gst_tag_list_unref (wavenc->tags);
|
||||||
|
wavenc->tags = NULL;
|
||||||
|
}
|
||||||
GST_DEBUG_OBJECT (wavenc, "toc: %p", wavenc->toc);
|
GST_DEBUG_OBJECT (wavenc, "toc: %p", wavenc->toc);
|
||||||
if (wavenc->toc) {
|
if (wavenc->toc) {
|
||||||
gst_toc_unref (wavenc->toc);
|
gst_toc_unref (wavenc->toc);
|
||||||
wavenc->toc = NULL;
|
wavenc->toc = NULL;
|
||||||
}
|
}
|
||||||
|
gst_tag_setter_reset_tags (GST_TAG_SETTER (wavenc));
|
||||||
gst_toc_setter_reset (GST_TOC_SETTER (wavenc));
|
gst_toc_setter_reset (GST_TOC_SETTER (wavenc));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -46,6 +46,7 @@ struct _GstWavEnc {
|
||||||
GstPad *sinkpad;
|
GstPad *sinkpad;
|
||||||
GstPad *srcpad;
|
GstPad *srcpad;
|
||||||
|
|
||||||
|
GstTagList *tags;
|
||||||
GstToc *toc;
|
GstToc *toc;
|
||||||
GList *cues;
|
GList *cues;
|
||||||
GList *labls;
|
GList *labls;
|
||||||
|
@ -56,7 +57,10 @@ struct _GstWavEnc {
|
||||||
guint width;
|
guint width;
|
||||||
guint rate;
|
guint rate;
|
||||||
guint channels;
|
guint channels;
|
||||||
guint32 length;
|
|
||||||
|
/* data sizes */
|
||||||
|
guint32 audio_length;
|
||||||
|
guint32 meta_length;
|
||||||
|
|
||||||
gboolean sent_header;
|
gboolean sent_header;
|
||||||
gboolean finished_properly;
|
gboolean finished_properly;
|
||||||
|
|
Loading…
Reference in a new issue