mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-24 10:41:04 +00:00
flac: port to 0.11
This commit is contained in:
parent
77acc618e1
commit
2f9a7b1a1b
3 changed files with 199 additions and 191 deletions
|
@ -147,7 +147,8 @@ static void gst_flac_dec_metadata_cb (const FLAC__StreamDecoder *
|
||||||
static void gst_flac_dec_error_cb (const FLAC__StreamDecoder *
|
static void gst_flac_dec_error_cb (const FLAC__StreamDecoder *
|
||||||
decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
|
decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
|
||||||
|
|
||||||
GST_BOILERPLATE (GstFlacDec, gst_flac_dec, GstElement, GST_TYPE_ELEMENT);
|
#define gst_flac_dec_parent_class parent_class
|
||||||
|
G_DEFINE_TYPE (GstFlacDec, gst_flac_dec, GST_TYPE_ELEMENT);
|
||||||
|
|
||||||
/* FIXME 0.11: Use width=32 for all depths and let audioconvert
|
/* FIXME 0.11: Use width=32 for all depths and let audioconvert
|
||||||
* handle the conversions instead of doing it ourself.
|
* handle the conversions instead of doing it ourself.
|
||||||
|
@ -173,22 +174,6 @@ GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_STATIC_CAPS ("audio/x-flac")
|
GST_STATIC_CAPS ("audio/x-flac")
|
||||||
);
|
);
|
||||||
|
|
||||||
static void
|
|
||||||
gst_flac_dec_base_init (gpointer g_class)
|
|
||||||
{
|
|
||||||
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
|
||||||
|
|
||||||
gst_element_class_add_pad_template (element_class,
|
|
||||||
gst_static_pad_template_get (&flac_dec_src_factory));
|
|
||||||
gst_element_class_add_pad_template (element_class,
|
|
||||||
gst_static_pad_template_get (&flac_dec_sink_factory));
|
|
||||||
gst_element_class_set_details_simple (element_class, "FLAC audio decoder",
|
|
||||||
"Codec/Decoder/Audio",
|
|
||||||
"Decodes FLAC lossless audio streams", "Wim Taymans <wim@fluendo.com>");
|
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (flacdec_debug, "flacdec", 0, "flac decoder");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_flac_dec_class_init (GstFlacDecClass * klass)
|
gst_flac_dec_class_init (GstFlacDecClass * klass)
|
||||||
{
|
{
|
||||||
|
@ -198,14 +183,25 @@ gst_flac_dec_class_init (GstFlacDecClass * klass)
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_INIT (flacdec_debug, "flacdec", 0, "flac decoder");
|
||||||
|
|
||||||
gobject_class->finalize = gst_flac_dec_finalize;
|
gobject_class->finalize = gst_flac_dec_finalize;
|
||||||
|
|
||||||
gstelement_class->change_state =
|
gstelement_class->change_state =
|
||||||
GST_DEBUG_FUNCPTR (gst_flac_dec_change_state);
|
GST_DEBUG_FUNCPTR (gst_flac_dec_change_state);
|
||||||
|
|
||||||
|
gst_element_class_add_pad_template (gstelement_class,
|
||||||
|
gst_static_pad_template_get (&flac_dec_src_factory));
|
||||||
|
gst_element_class_add_pad_template (gstelement_class,
|
||||||
|
gst_static_pad_template_get (&flac_dec_sink_factory));
|
||||||
|
|
||||||
|
gst_element_class_set_details_simple (gstelement_class, "FLAC audio decoder",
|
||||||
|
"Codec/Decoder/Audio",
|
||||||
|
"Decodes FLAC lossless audio streams", "Wim Taymans <wim@fluendo.com>");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_flac_dec_init (GstFlacDec * flacdec, GstFlacDecClass * klass)
|
gst_flac_dec_init (GstFlacDec * flacdec)
|
||||||
{
|
{
|
||||||
flacdec->sinkpad =
|
flacdec->sinkpad =
|
||||||
gst_pad_new_from_static_template (&flac_dec_sink_factory, "sink");
|
gst_pad_new_from_static_template (&flac_dec_sink_factory, "sink");
|
||||||
|
@ -501,8 +497,8 @@ gst_flac_dec_scan_for_last_block (GstFlacDec * flacdec, gint64 * samples)
|
||||||
while (offset >= MAX (SCANBLOCK_SIZE / 2, file_size / 2)) {
|
while (offset >= MAX (SCANBLOCK_SIZE / 2, file_size / 2)) {
|
||||||
GstFlowReturn flow;
|
GstFlowReturn flow;
|
||||||
GstBuffer *buf = NULL;
|
GstBuffer *buf = NULL;
|
||||||
guint8 *data;
|
guint8 *data, *ptr;
|
||||||
guint size;
|
gsize size, left;
|
||||||
|
|
||||||
/* divide by 2 = not very sophisticated way to deal with overlapping */
|
/* divide by 2 = not very sophisticated way to deal with overlapping */
|
||||||
offset -= SCANBLOCK_SIZE / 2;
|
offset -= SCANBLOCK_SIZE / 2;
|
||||||
|
@ -515,20 +511,24 @@ gst_flac_dec_scan_for_last_block (GstFlacDec * flacdec, gint64 * samples)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = GST_BUFFER_SIZE (buf);
|
data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
|
||||||
data = GST_BUFFER_DATA (buf);
|
|
||||||
|
|
||||||
while (size > 16) {
|
ptr = data;
|
||||||
if (gst_flac_dec_scan_got_frame (flacdec, data, size, samples)) {
|
left = size;
|
||||||
|
|
||||||
|
while (left > 16) {
|
||||||
|
if (gst_flac_dec_scan_got_frame (flacdec, ptr, left, samples)) {
|
||||||
GST_DEBUG_OBJECT (flacdec, "frame sync at offset %" G_GINT64_FORMAT,
|
GST_DEBUG_OBJECT (flacdec, "frame sync at offset %" G_GINT64_FORMAT,
|
||||||
offset + GST_BUFFER_SIZE (buf) - size);
|
offset + size - left);
|
||||||
|
gst_buffer_unmap (buf, data, size);
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
++data;
|
++ptr;
|
||||||
--size;
|
--left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_buffer_unmap (buf, data, size);
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -777,10 +777,11 @@ gst_flac_dec_read_seekable (const FLAC__StreamDecoder * decoder,
|
||||||
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
|
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*bytes = gst_buffer_get_size (buf);
|
||||||
GST_DEBUG_OBJECT (flacdec, "Read %d bytes at %" G_GUINT64_FORMAT,
|
GST_DEBUG_OBJECT (flacdec, "Read %d bytes at %" G_GUINT64_FORMAT,
|
||||||
GST_BUFFER_SIZE (buf), flacdec->offset);
|
*bytes, flacdec->offset);
|
||||||
memcpy (buffer, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
|
||||||
*bytes = GST_BUFFER_SIZE (buf);
|
gst_buffer_extract (buf, 0, buffer, *bytes);
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
flacdec->offset += *bytes;
|
flacdec->offset += *bytes;
|
||||||
|
|
||||||
|
@ -824,6 +825,8 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
|
||||||
guint samples = frame->header.blocksize;
|
guint samples = frame->header.blocksize;
|
||||||
guint j, i;
|
guint j, i;
|
||||||
GstClockTime next;
|
GstClockTime next;
|
||||||
|
gpointer data;
|
||||||
|
gsize size;
|
||||||
|
|
||||||
GST_LOG_OBJECT (flacdec, "samples in frame header: %d", samples);
|
GST_LOG_OBJECT (flacdec, "samples in frame header: %d", samples);
|
||||||
|
|
||||||
|
@ -942,7 +945,7 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
|
||||||
* downstream negotiation work on older basetransform */
|
* downstream negotiation work on older basetransform */
|
||||||
ret = gst_pad_alloc_buffer_and_set_caps (flacdec->srcpad,
|
ret = gst_pad_alloc_buffer_and_set_caps (flacdec->srcpad,
|
||||||
GST_BUFFER_OFFSET (flacdec->pending),
|
GST_BUFFER_OFFSET (flacdec->pending),
|
||||||
GST_BUFFER_SIZE (flacdec->pending),
|
gst_buffer_get_size (flacdec->pending),
|
||||||
GST_BUFFER_CAPS (flacdec->pending), &outbuf);
|
GST_BUFFER_CAPS (flacdec->pending), &outbuf);
|
||||||
if (ret == GST_FLOW_OK) {
|
if (ret == GST_FLOW_OK) {
|
||||||
gst_pad_push (flacdec->srcpad, flacdec->pending);
|
gst_pad_push (flacdec->srcpad, flacdec->pending);
|
||||||
|
@ -989,8 +992,9 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
|
||||||
|
|
||||||
GST_BUFFER_DURATION (outbuf) = next - GST_BUFFER_TIMESTAMP (outbuf);
|
GST_BUFFER_DURATION (outbuf) = next - GST_BUFFER_TIMESTAMP (outbuf);
|
||||||
|
|
||||||
|
data = gst_buffer_map (outbuf, &size, NULL, GST_MAP_WRITE);
|
||||||
if (width == 8) {
|
if (width == 8) {
|
||||||
gint8 *outbuffer = (gint8 *) GST_BUFFER_DATA (outbuf);
|
gint8 *outbuffer = (gint8 *) data;
|
||||||
|
|
||||||
for (i = 0; i < samples; i++) {
|
for (i = 0; i < samples; i++) {
|
||||||
for (j = 0; j < channels; j++) {
|
for (j = 0; j < channels; j++) {
|
||||||
|
@ -998,7 +1002,7 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (width == 16) {
|
} else if (width == 16) {
|
||||||
gint16 *outbuffer = (gint16 *) GST_BUFFER_DATA (outbuf);
|
gint16 *outbuffer = (gint16 *) data;
|
||||||
|
|
||||||
for (i = 0; i < samples; i++) {
|
for (i = 0; i < samples; i++) {
|
||||||
for (j = 0; j < channels; j++) {
|
for (j = 0; j < channels; j++) {
|
||||||
|
@ -1006,7 +1010,7 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (width == 32) {
|
} else if (width == 32) {
|
||||||
gint32 *outbuffer = (gint32 *) GST_BUFFER_DATA (outbuf);
|
gint32 *outbuffer = (gint32 *) data;
|
||||||
|
|
||||||
for (i = 0; i < samples; i++) {
|
for (i = 0; i < samples; i++) {
|
||||||
for (j = 0; j < channels; j++) {
|
for (j = 0; j < channels; j++) {
|
||||||
|
@ -1016,6 +1020,7 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
|
||||||
} else {
|
} else {
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
|
gst_buffer_unmap (outbuf, data, size);
|
||||||
|
|
||||||
if (!flacdec->seeking) {
|
if (!flacdec->seeking) {
|
||||||
GST_DEBUG_OBJECT (flacdec, "pushing %d samples at offset %" G_GINT64_FORMAT
|
GST_DEBUG_OBJECT (flacdec, "pushing %d samples at offset %" G_GINT64_FORMAT
|
||||||
|
@ -1026,7 +1031,7 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
|
||||||
|
|
||||||
if (flacdec->discont) {
|
if (flacdec->discont) {
|
||||||
GST_DEBUG_OBJECT (flacdec, "marking discont");
|
GST_DEBUG_OBJECT (flacdec, "marking discont");
|
||||||
outbuf = gst_buffer_make_metadata_writable (outbuf);
|
outbuf = gst_buffer_make_writable (outbuf);
|
||||||
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
|
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
|
||||||
flacdec->discont = FALSE;
|
flacdec->discont = FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1362,7 +1367,7 @@ gst_flac_dec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
|
|
||||||
GST_LOG_OBJECT (dec, "buffer with ts=%" GST_TIME_FORMAT ", end_offset=%"
|
GST_LOG_OBJECT (dec, "buffer with ts=%" GST_TIME_FORMAT ", end_offset=%"
|
||||||
G_GINT64_FORMAT ", size=%u", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
|
G_GINT64_FORMAT ", size=%u", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
|
||||||
GST_BUFFER_OFFSET_END (buf), GST_BUFFER_SIZE (buf));
|
GST_BUFFER_OFFSET_END (buf), gst_buffer_get_size (buf));
|
||||||
|
|
||||||
if (dec->init) {
|
if (dec->init) {
|
||||||
GST_DEBUG_OBJECT (dec, "initializing decoder");
|
GST_DEBUG_OBJECT (dec, "initializing decoder");
|
||||||
|
@ -1384,10 +1389,13 @@ gst_flac_dec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
|
|
||||||
if (dec->framed) {
|
if (dec->framed) {
|
||||||
gint64 unused;
|
gint64 unused;
|
||||||
|
guint8 *data;
|
||||||
|
gsize size;
|
||||||
|
|
||||||
/* check if this is a flac audio frame (rather than a header or junk) */
|
/* check if this is a flac audio frame (rather than a header or junk) */
|
||||||
got_audio_frame = gst_flac_dec_scan_got_frame (dec, GST_BUFFER_DATA (buf),
|
data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
|
||||||
GST_BUFFER_SIZE (buf), &unused);
|
got_audio_frame = gst_flac_dec_scan_got_frame (dec, data, size, &unused);
|
||||||
|
gst_buffer_unmap (buf, data, size);
|
||||||
|
|
||||||
/* oggdemux will set granulepos in OFFSET_END instead of timestamp */
|
/* oggdemux will set granulepos in OFFSET_END instead of timestamp */
|
||||||
if (G_LIKELY (got_audio_frame)) {
|
if (G_LIKELY (got_audio_frame)) {
|
||||||
|
|
|
@ -149,27 +149,10 @@ enum
|
||||||
GST_DEBUG_CATEGORY_STATIC (flacenc_debug);
|
GST_DEBUG_CATEGORY_STATIC (flacenc_debug);
|
||||||
#define GST_CAT_DEFAULT flacenc_debug
|
#define GST_CAT_DEFAULT flacenc_debug
|
||||||
|
|
||||||
|
#define gst_flac_enc_parent_class parent_class
|
||||||
#define _do_init(type) \
|
G_DEFINE_TYPE_WITH_CODE (GstFlacEnc, gst_flac_enc, GST_TYPE_ELEMENT,
|
||||||
G_STMT_START{ \
|
G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL);
|
||||||
static const GInterfaceInfo tag_setter_info = { \
|
G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
|
||||||
NULL, \
|
|
||||||
NULL, \
|
|
||||||
NULL \
|
|
||||||
}; \
|
|
||||||
static const GInterfaceInfo preset_info = { \
|
|
||||||
NULL, \
|
|
||||||
NULL, \
|
|
||||||
NULL \
|
|
||||||
}; \
|
|
||||||
g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, \
|
|
||||||
&tag_setter_info); \
|
|
||||||
g_type_add_interface_static (type, GST_TYPE_PRESET, \
|
|
||||||
&preset_info); \
|
|
||||||
}G_STMT_END
|
|
||||||
|
|
||||||
GST_BOILERPLATE_FULL (GstFlacEnc, gst_flac_enc, GstElement, GST_TYPE_ELEMENT,
|
|
||||||
_do_init);
|
|
||||||
|
|
||||||
static void gst_flac_enc_finalize (GObject * object);
|
static void gst_flac_enc_finalize (GObject * object);
|
||||||
|
|
||||||
|
@ -257,25 +240,6 @@ gst_flac_enc_quality_get_type (void)
|
||||||
return qtype;
|
return qtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gst_flac_enc_base_init (gpointer g_class)
|
|
||||||
{
|
|
||||||
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
|
||||||
|
|
||||||
gst_element_class_add_pad_template (element_class,
|
|
||||||
gst_static_pad_template_get (&src_factory));
|
|
||||||
gst_element_class_add_pad_template (element_class,
|
|
||||||
gst_static_pad_template_get (&sink_factory));
|
|
||||||
|
|
||||||
gst_element_class_set_details_simple (element_class, "FLAC audio encoder",
|
|
||||||
"Codec/Encoder/Audio",
|
|
||||||
"Encodes audio with the FLAC lossless audio encoder",
|
|
||||||
"Wim Taymans <wim.taymans@chello.be>");
|
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (flacenc_debug, "flacenc", 0,
|
|
||||||
"Flac encoding element");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_flac_enc_class_init (GstFlacEncClass * klass)
|
gst_flac_enc_class_init (GstFlacEncClass * klass)
|
||||||
{
|
{
|
||||||
|
@ -285,6 +249,9 @@ gst_flac_enc_class_init (GstFlacEncClass * klass)
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_INIT (flacenc_debug, "flacenc", 0,
|
||||||
|
"Flac encoding element");
|
||||||
|
|
||||||
gobject_class->set_property = gst_flac_enc_set_property;
|
gobject_class->set_property = gst_flac_enc_set_property;
|
||||||
gobject_class->get_property = gst_flac_enc_get_property;
|
gobject_class->get_property = gst_flac_enc_get_property;
|
||||||
gobject_class->finalize = gst_flac_enc_finalize;
|
gobject_class->finalize = gst_flac_enc_finalize;
|
||||||
|
@ -403,10 +370,20 @@ gst_flac_enc_class_init (GstFlacEncClass * klass)
|
||||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
gstelement_class->change_state = gst_flac_enc_change_state;
|
gstelement_class->change_state = gst_flac_enc_change_state;
|
||||||
|
|
||||||
|
gst_element_class_add_pad_template (gstelement_class,
|
||||||
|
gst_static_pad_template_get (&src_factory));
|
||||||
|
gst_element_class_add_pad_template (gstelement_class,
|
||||||
|
gst_static_pad_template_get (&sink_factory));
|
||||||
|
|
||||||
|
gst_element_class_set_details_simple (gstelement_class, "FLAC audio encoder",
|
||||||
|
"Codec/Encoder/Audio",
|
||||||
|
"Encodes audio with the FLAC lossless audio encoder",
|
||||||
|
"Wim Taymans <wim.taymans@chello.be>");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_flac_enc_init (GstFlacEnc * flacenc, GstFlacEncClass * klass)
|
gst_flac_enc_init (GstFlacEnc * flacenc)
|
||||||
{
|
{
|
||||||
flacenc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
|
flacenc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
|
||||||
gst_pad_set_chain_function (flacenc->sinkpad,
|
gst_pad_set_chain_function (flacenc->sinkpad,
|
||||||
|
@ -505,6 +482,8 @@ gst_flac_enc_set_metadata (GstFlacEnc * flacenc, guint64 total_samples)
|
||||||
GstStructure *structure;
|
GstStructure *structure;
|
||||||
GstTagImageType image_type = GST_TAG_IMAGE_TYPE_NONE;
|
GstTagImageType image_type = GST_TAG_IMAGE_TYPE_NONE;
|
||||||
gint i;
|
gint i;
|
||||||
|
guint8 *data;
|
||||||
|
gsize size;
|
||||||
|
|
||||||
for (i = 0; i < n_images + n_preview_images; i++) {
|
for (i = 0; i < n_images + n_preview_images; i++) {
|
||||||
if (i < n_images) {
|
if (i < n_images) {
|
||||||
|
@ -530,8 +509,11 @@ gst_flac_enc_set_metadata (GstFlacEnc * flacenc, guint64 total_samples)
|
||||||
else
|
else
|
||||||
image_type = image_type + 2;
|
image_type = image_type + 2;
|
||||||
|
|
||||||
|
data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
|
||||||
FLAC__metadata_object_picture_set_data (flacenc->meta[entries],
|
FLAC__metadata_object_picture_set_data (flacenc->meta[entries],
|
||||||
GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), TRUE);
|
data, size, TRUE);
|
||||||
|
gst_buffer_unmap (buffer, data, size);
|
||||||
|
|
||||||
/* FIXME: There's no way to set the picture type in libFLAC */
|
/* FIXME: There's no way to set the picture type in libFLAC */
|
||||||
flacenc->meta[entries]->data.picture.type = image_type;
|
flacenc->meta[entries]->data.picture.type = image_type;
|
||||||
FLAC__metadata_object_picture_set_mime_type (flacenc->meta[entries],
|
FLAC__metadata_object_picture_set_mime_type (flacenc->meta[entries],
|
||||||
|
@ -915,25 +897,29 @@ gst_flac_enc_process_stream_headers (GstFlacEnc * enc)
|
||||||
"rate", G_TYPE_INT, enc->sample_rate, NULL);
|
"rate", G_TYPE_INT, enc->sample_rate, NULL);
|
||||||
|
|
||||||
for (l = enc->headers; l != NULL; l = l->next) {
|
for (l = enc->headers; l != NULL; l = l->next) {
|
||||||
const guint8 *data;
|
GstBuffer *buf;
|
||||||
guint size;
|
guint8 *data;
|
||||||
|
gsize size;
|
||||||
|
|
||||||
/* mark buffers so oggmux will ignore them if it already muxed the
|
/* mark buffers so oggmux will ignore them if it already muxed the
|
||||||
* header buffers from the streamheaders field in the caps */
|
* header buffers from the streamheaders field in the caps */
|
||||||
l->data = gst_buffer_make_metadata_writable (GST_BUFFER (l->data));
|
l->data = gst_buffer_make_writable (GST_BUFFER_CAST (l->data));
|
||||||
GST_BUFFER_FLAG_SET (GST_BUFFER (l->data), GST_BUFFER_FLAG_IN_CAPS);
|
|
||||||
|
|
||||||
data = GST_BUFFER_DATA (GST_BUFFER_CAST (l->data));
|
buf = GST_BUFFER_CAST (l->data);
|
||||||
size = GST_BUFFER_SIZE (GST_BUFFER_CAST (l->data));
|
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
|
||||||
|
|
||||||
|
data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
|
||||||
|
|
||||||
/* find initial 4-byte marker which we need to skip later on */
|
/* find initial 4-byte marker which we need to skip later on */
|
||||||
if (size == 4 && memcmp (data, "fLaC", 4) == 0) {
|
if (size == 4 && memcmp (data, "fLaC", 4) == 0) {
|
||||||
marker = GST_BUFFER_CAST (l->data);
|
marker = buf;
|
||||||
} else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_STREAMINFO) {
|
} else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_STREAMINFO) {
|
||||||
streaminfo = GST_BUFFER_CAST (l->data);
|
streaminfo = buf;
|
||||||
} else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_VORBISCOMMENT) {
|
} else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_VORBISCOMMENT) {
|
||||||
vorbiscomment = GST_BUFFER_CAST (l->data);
|
vorbiscomment = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_buffer_unmap (buf, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (marker == NULL || streaminfo == NULL || vorbiscomment == NULL) {
|
if (marker == NULL || streaminfo == NULL || vorbiscomment == NULL) {
|
||||||
|
@ -948,20 +934,26 @@ gst_flac_enc_process_stream_headers (GstFlacEnc * enc)
|
||||||
{
|
{
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
guint16 num;
|
guint16 num;
|
||||||
|
guint8 *bdata;
|
||||||
|
gsize bsize, slen;
|
||||||
|
|
||||||
/* minus one for the marker that is merged with streaminfo here */
|
/* minus one for the marker that is merged with streaminfo here */
|
||||||
num = g_list_length (enc->headers) - 1;
|
num = g_list_length (enc->headers) - 1;
|
||||||
|
|
||||||
buf = gst_buffer_new_and_alloc (13 + GST_BUFFER_SIZE (streaminfo));
|
slen = gst_buffer_get_size (streaminfo);
|
||||||
GST_BUFFER_DATA (buf)[0] = 0x7f;
|
buf = gst_buffer_new_and_alloc (13 + slen);
|
||||||
memcpy (GST_BUFFER_DATA (buf) + 1, "FLAC", 4);
|
|
||||||
GST_BUFFER_DATA (buf)[5] = 0x01; /* mapping version major */
|
bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_WRITE);
|
||||||
GST_BUFFER_DATA (buf)[6] = 0x00; /* mapping version minor */
|
bdata[0] = 0x7f;
|
||||||
GST_BUFFER_DATA (buf)[7] = (num & 0xFF00) >> 8;
|
memcpy (bdata + 1, "FLAC", 4);
|
||||||
GST_BUFFER_DATA (buf)[8] = (num & 0x00FF) >> 0;
|
bdata[5] = 0x01; /* mapping version major */
|
||||||
memcpy (GST_BUFFER_DATA (buf) + 9, "fLaC", 4);
|
bdata[6] = 0x00; /* mapping version minor */
|
||||||
memcpy (GST_BUFFER_DATA (buf) + 13, GST_BUFFER_DATA (streaminfo),
|
bdata[7] = (num & 0xFF00) >> 8;
|
||||||
GST_BUFFER_SIZE (streaminfo));
|
bdata[8] = (num & 0x00FF) >> 0;
|
||||||
|
memcpy (bdata + 9, "fLaC", 4);
|
||||||
|
gst_buffer_extract (streaminfo, 0, bdata + 13, slen);
|
||||||
|
gst_buffer_unmap (buf, bdata, bsize);
|
||||||
|
|
||||||
notgst_value_array_append_buffer (&array, buf);
|
notgst_value_array_append_buffer (&array, buf);
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
}
|
}
|
||||||
|
@ -971,10 +963,10 @@ gst_flac_enc_process_stream_headers (GstFlacEnc * enc)
|
||||||
|
|
||||||
/* add other headers, if there are any */
|
/* add other headers, if there are any */
|
||||||
for (l = enc->headers; l != NULL; l = l->next) {
|
for (l = enc->headers; l != NULL; l = l->next) {
|
||||||
if (GST_BUFFER_CAST (l->data) != marker &&
|
GstBuffer *buf = GST_BUFFER_CAST (l->data);
|
||||||
GST_BUFFER_CAST (l->data) != streaminfo &&
|
|
||||||
GST_BUFFER_CAST (l->data) != vorbiscomment) {
|
if (buf != marker && buf != streaminfo && buf != vorbiscomment) {
|
||||||
notgst_value_array_append_buffer (&array, GST_BUFFER_CAST (l->data));
|
notgst_value_array_append_buffer (&array, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -994,9 +986,11 @@ push_headers:
|
||||||
buf = GST_BUFFER (l->data);
|
buf = GST_BUFFER (l->data);
|
||||||
gst_buffer_set_caps (buf, caps);
|
gst_buffer_set_caps (buf, caps);
|
||||||
GST_LOG_OBJECT (enc, "Pushing header buffer, size %u bytes",
|
GST_LOG_OBJECT (enc, "Pushing header buffer, size %u bytes",
|
||||||
GST_BUFFER_SIZE (buf));
|
gst_buffer_get_size (buf));
|
||||||
|
#if 0
|
||||||
GST_MEMDUMP_OBJECT (enc, "header buffer", GST_BUFFER_DATA (buf),
|
GST_MEMDUMP_OBJECT (enc, "header buffer", GST_BUFFER_DATA (buf),
|
||||||
GST_BUFFER_SIZE (buf));
|
GST_BUFFER_SIZE (buf));
|
||||||
|
#endif
|
||||||
(void) gst_pad_push (enc->srcpad, buf);
|
(void) gst_pad_push (enc->srcpad, buf);
|
||||||
l->data = NULL;
|
l->data = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1021,7 +1015,7 @@ gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder,
|
||||||
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
|
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
|
||||||
|
|
||||||
outbuf = gst_buffer_new_and_alloc (bytes);
|
outbuf = gst_buffer_new_and_alloc (bytes);
|
||||||
memcpy (GST_BUFFER_DATA (outbuf), buffer, bytes);
|
gst_buffer_fill (outbuf, 0, buffer, bytes);
|
||||||
|
|
||||||
if (samples > 0 && flacenc->samples_written != (guint64) - 1) {
|
if (samples > 0 && flacenc->samples_written != (guint64) - 1) {
|
||||||
guint64 granulepos;
|
guint64 granulepos;
|
||||||
|
@ -1064,8 +1058,10 @@ gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder,
|
||||||
} else if (flacenc->got_headers && samples == 0) {
|
} else if (flacenc->got_headers && samples == 0) {
|
||||||
GST_DEBUG_OBJECT (flacenc, "Fixing up headers at pos=%" G_GUINT64_FORMAT
|
GST_DEBUG_OBJECT (flacenc, "Fixing up headers at pos=%" G_GUINT64_FORMAT
|
||||||
", size=%u", flacenc->offset, (guint) bytes);
|
", size=%u", flacenc->offset, (guint) bytes);
|
||||||
|
#if 0
|
||||||
GST_MEMDUMP_OBJECT (flacenc, "Presumed header fragment",
|
GST_MEMDUMP_OBJECT (flacenc, "Presumed header fragment",
|
||||||
GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf));
|
GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf));
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
GST_LOG ("Pushing buffer: ts=%" GST_TIME_FORMAT ", samples=%u, size=%u, "
|
GST_LOG ("Pushing buffer: ts=%" GST_TIME_FORMAT ", samples=%u, size=%u, "
|
||||||
"pos=%" G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
|
"pos=%" G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
|
||||||
|
@ -1197,10 +1193,11 @@ gst_flac_enc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstFlacEnc *flacenc;
|
GstFlacEnc *flacenc;
|
||||||
FLAC__int32 *data;
|
FLAC__int32 *data;
|
||||||
gulong insize;
|
gsize bsize;
|
||||||
gint samples, width;
|
gint samples, width;
|
||||||
gulong i;
|
gulong i;
|
||||||
FLAC__bool res;
|
FLAC__bool res;
|
||||||
|
gpointer bdata;
|
||||||
|
|
||||||
flacenc = GST_FLAC_ENC (GST_PAD_PARENT (pad));
|
flacenc = GST_FLAC_ENC (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
|
@ -1238,30 +1235,30 @@ gst_flac_enc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
else
|
else
|
||||||
flacenc->next_ts = GST_CLOCK_TIME_NONE;
|
flacenc->next_ts = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
insize = GST_BUFFER_SIZE (buffer);
|
bdata = gst_buffer_map (buffer, &bsize, NULL, GST_MAP_READ);
|
||||||
samples = insize / (width >> 3);
|
samples = bsize / (width >> 3);
|
||||||
|
|
||||||
data = g_malloc (samples * sizeof (FLAC__int32));
|
data = g_malloc (samples * sizeof (FLAC__int32));
|
||||||
|
|
||||||
if (width == 8) {
|
if (width == 8) {
|
||||||
gint8 *indata = (gint8 *) GST_BUFFER_DATA (buffer);
|
gint8 *indata = (gint8 *) bdata;
|
||||||
|
|
||||||
for (i = 0; i < samples; i++)
|
for (i = 0; i < samples; i++)
|
||||||
data[i] = (FLAC__int32) indata[i];
|
data[i] = (FLAC__int32) indata[i];
|
||||||
} else if (width == 16) {
|
} else if (width == 16) {
|
||||||
gint16 *indata = (gint16 *) GST_BUFFER_DATA (buffer);
|
gint16 *indata = (gint16 *) bdata;
|
||||||
|
|
||||||
for (i = 0; i < samples; i++)
|
for (i = 0; i < samples; i++)
|
||||||
data[i] = (FLAC__int32) indata[i];
|
data[i] = (FLAC__int32) indata[i];
|
||||||
} else if (width == 32) {
|
} else if (width == 32) {
|
||||||
gint32 *indata = (gint32 *) GST_BUFFER_DATA (buffer);
|
gint32 *indata = (gint32 *) bdata;
|
||||||
|
|
||||||
for (i = 0; i < samples; i++)
|
for (i = 0; i < samples; i++)
|
||||||
data[i] = (FLAC__int32) indata[i];
|
data[i] = (FLAC__int32) indata[i];
|
||||||
} else {
|
} else {
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
|
gst_buffer_unmap (buffer, bdata, bsize);
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
|
|
||||||
res = FLAC__stream_encoder_process_interleaved (flacenc->encoder,
|
res = FLAC__stream_encoder_process_interleaved (flacenc->encoder,
|
||||||
|
|
|
@ -96,34 +96,10 @@ static GstStateChangeReturn gst_flac_tag_change_state (GstElement * element,
|
||||||
|
|
||||||
static gboolean gst_flac_tag_sink_setcaps (GstPad * pad, GstCaps * caps);
|
static gboolean gst_flac_tag_sink_setcaps (GstPad * pad, GstCaps * caps);
|
||||||
|
|
||||||
static void
|
#define gst_flac_tag_parent_class parent_class
|
||||||
gst_flac_tag_setup_interfaces (GType flac_tag_type)
|
G_DEFINE_TYPE_WITH_CODE (GstFlacTag, gst_flac_tag, GST_TYPE_ELEMENT,
|
||||||
{
|
G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
|
||||||
static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
|
|
||||||
|
|
||||||
g_type_add_interface_static (flac_tag_type, GST_TYPE_TAG_SETTER,
|
|
||||||
&tag_setter_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_BOILERPLATE_FULL (GstFlacTag, gst_flac_tag, GstElement, GST_TYPE_ELEMENT,
|
|
||||||
gst_flac_tag_setup_interfaces);
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_flac_tag_base_init (gpointer g_class)
|
|
||||||
{
|
|
||||||
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
|
||||||
|
|
||||||
gst_element_class_set_details_simple (element_class, "FLAC tagger",
|
|
||||||
"Formatter/Metadata",
|
|
||||||
"Rewrite tags in a FLAC file", "Christophe Fergeau <teuf@gnome.org>");
|
|
||||||
|
|
||||||
gst_element_class_add_pad_template (element_class,
|
|
||||||
gst_static_pad_template_get (&flac_tag_sink_template));
|
|
||||||
gst_element_class_add_pad_template (element_class,
|
|
||||||
gst_static_pad_template_get (&flac_tag_src_template));
|
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (flactag_debug, "flactag", 0, "flac tag rewriter");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_flac_tag_class_init (GstFlacTagClass * klass)
|
gst_flac_tag_class_init (GstFlacTagClass * klass)
|
||||||
|
@ -131,13 +107,23 @@ gst_flac_tag_class_init (GstFlacTagClass * klass)
|
||||||
GstElementClass *gstelement_class;
|
GstElementClass *gstelement_class;
|
||||||
GObjectClass *gobject_class;
|
GObjectClass *gobject_class;
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_INIT (flactag_debug, "flactag", 0, "flac tag rewriter");
|
||||||
|
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
|
|
||||||
parent_class = g_type_class_peek_parent (klass);
|
|
||||||
|
|
||||||
gobject_class->dispose = gst_flac_tag_dispose;
|
gobject_class->dispose = gst_flac_tag_dispose;
|
||||||
gstelement_class->change_state = gst_flac_tag_change_state;
|
gstelement_class->change_state = gst_flac_tag_change_state;
|
||||||
|
|
||||||
|
gst_element_class_set_details_simple (gstelement_class, "FLAC tagger",
|
||||||
|
"Formatter/Metadata",
|
||||||
|
"Rewrite tags in a FLAC file", "Christophe Fergeau <teuf@gnome.org>");
|
||||||
|
|
||||||
|
gst_element_class_add_pad_template (gstelement_class,
|
||||||
|
gst_static_pad_template_get (&flac_tag_sink_template));
|
||||||
|
|
||||||
|
gst_element_class_add_pad_template (gstelement_class,
|
||||||
|
gst_static_pad_template_get (&flac_tag_src_template));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -163,7 +149,7 @@ gst_flac_tag_dispose (GObject * object)
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_flac_tag_init (GstFlacTag * tag, GstFlacTagClass * klass)
|
gst_flac_tag_init (GstFlacTag * tag)
|
||||||
{
|
{
|
||||||
/* create the sink and src pads */
|
/* create the sink and src pads */
|
||||||
tag->sinkpad =
|
tag->sinkpad =
|
||||||
|
@ -197,6 +183,8 @@ gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstFlacTag *tag;
|
GstFlacTag *tag;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
|
guint8 *data;
|
||||||
|
gsize size;
|
||||||
|
|
||||||
ret = GST_FLOW_OK;
|
ret = GST_FLOW_OK;
|
||||||
tag = GST_FLAC_TAG (gst_pad_get_parent (pad));
|
tag = GST_FLAC_TAG (gst_pad_get_parent (pad));
|
||||||
|
@ -212,7 +200,7 @@ gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
|
||||||
id_buffer = gst_adapter_take_buffer (tag->adapter, FLAC_MAGIC_SIZE);
|
id_buffer = gst_adapter_take_buffer (tag->adapter, FLAC_MAGIC_SIZE);
|
||||||
GST_DEBUG_OBJECT (tag, "looking for " FLAC_MAGIC " identifier");
|
GST_DEBUG_OBJECT (tag, "looking for " FLAC_MAGIC " identifier");
|
||||||
if (memcmp (GST_BUFFER_DATA (id_buffer), FLAC_MAGIC, FLAC_MAGIC_SIZE) == 0) {
|
if (gst_buffer_memcmp (id_buffer, 0, FLAC_MAGIC, FLAC_MAGIC_SIZE) == 0) {
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (tag, "pushing " FLAC_MAGIC " identifier buffer");
|
GST_DEBUG_OBJECT (tag, "pushing " FLAC_MAGIC " identifier buffer");
|
||||||
gst_buffer_set_caps (id_buffer, GST_PAD_CAPS (tag->srcpad));
|
gst_buffer_set_caps (id_buffer, GST_PAD_CAPS (tag->srcpad));
|
||||||
|
@ -234,7 +222,6 @@ gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
* of a metadata block
|
* of a metadata block
|
||||||
*/
|
*/
|
||||||
if (tag->state == GST_FLAC_TAG_STATE_METADATA_BLOCKS) {
|
if (tag->state == GST_FLAC_TAG_STATE_METADATA_BLOCKS) {
|
||||||
guint size;
|
|
||||||
guint type;
|
guint type;
|
||||||
gboolean is_last;
|
gboolean is_last;
|
||||||
const guint8 *block_header;
|
const guint8 *block_header;
|
||||||
|
@ -250,13 +237,14 @@ gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
if (gst_adapter_available (tag->adapter) < 4)
|
if (gst_adapter_available (tag->adapter) < 4)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
block_header = gst_adapter_peek (tag->adapter, 4);
|
block_header = gst_adapter_map (tag->adapter, 4);
|
||||||
|
|
||||||
is_last = ((block_header[0] & 0x80) == 0x80);
|
is_last = ((block_header[0] & 0x80) == 0x80);
|
||||||
type = block_header[0] & 0x7F;
|
type = block_header[0] & 0x7F;
|
||||||
size = (block_header[1] << 16)
|
size = (block_header[1] << 16)
|
||||||
| (block_header[2] << 8)
|
| (block_header[2] << 8)
|
||||||
| block_header[3];
|
| block_header[3];
|
||||||
|
gst_adapter_unmap (tag->adapter, 0);
|
||||||
|
|
||||||
/* The 4 bytes long header isn't included in the metadata size */
|
/* The 4 bytes long header isn't included in the metadata size */
|
||||||
tag->metadata_block_size = size + 4;
|
tag->metadata_block_size = size + 4;
|
||||||
|
@ -288,7 +276,9 @@ gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
/* clear the is-last flag, as the last metadata block will
|
/* clear the is-last flag, as the last metadata block will
|
||||||
* be the vorbis comment block which we will build ourselves.
|
* be the vorbis comment block which we will build ourselves.
|
||||||
*/
|
*/
|
||||||
GST_BUFFER_DATA (metadata_buffer)[0] &= (~0x80);
|
data = gst_buffer_map (metadata_buffer, &size, NULL, GST_MAP_READWRITE);
|
||||||
|
data[0] &= (~0x80);
|
||||||
|
gst_buffer_unmap (metadata_buffer, data, size);
|
||||||
|
|
||||||
if (tag->state == GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK) {
|
if (tag->state == GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK) {
|
||||||
GST_DEBUG_OBJECT (tag, "pushing metadata block buffer");
|
GST_DEBUG_OBJECT (tag, "pushing metadata block buffer");
|
||||||
|
@ -312,12 +302,14 @@ gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
* block, and stop now if the user only wants to read tags
|
* block, and stop now if the user only wants to read tags
|
||||||
*/
|
*/
|
||||||
if (tag->vorbiscomment != NULL) {
|
if (tag->vorbiscomment != NULL) {
|
||||||
|
guint8 id_data[4];
|
||||||
/* We found some tags, try to parse them and notify the other elements
|
/* We found some tags, try to parse them and notify the other elements
|
||||||
* that we encountered some tags
|
* that we encountered some tags
|
||||||
*/
|
*/
|
||||||
GST_DEBUG_OBJECT (tag, "emitting vorbiscomment tags");
|
GST_DEBUG_OBJECT (tag, "emitting vorbiscomment tags");
|
||||||
|
gst_buffer_extract (tag->vorbiscomment, 0, id_data, 4);
|
||||||
tag->tags = gst_tag_list_from_vorbiscomment_buffer (tag->vorbiscomment,
|
tag->tags = gst_tag_list_from_vorbiscomment_buffer (tag->vorbiscomment,
|
||||||
GST_BUFFER_DATA (tag->vorbiscomment), 4, NULL);
|
id_data, 4, NULL);
|
||||||
if (tag->tags != NULL) {
|
if (tag->tags != NULL) {
|
||||||
gst_element_found_tags (GST_ELEMENT (tag),
|
gst_element_found_tags (GST_ELEMENT (tag),
|
||||||
gst_tag_list_copy (tag->tags));
|
gst_tag_list_copy (tag->tags));
|
||||||
|
@ -341,7 +333,6 @@ gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
*/
|
*/
|
||||||
if (tag->state == GST_FLAC_TAG_STATE_ADD_VORBIS_COMMENT) {
|
if (tag->state == GST_FLAC_TAG_STATE_ADD_VORBIS_COMMENT) {
|
||||||
GstBuffer *buffer;
|
GstBuffer *buffer;
|
||||||
gint size;
|
|
||||||
const GstTagList *user_tags;
|
const GstTagList *user_tags;
|
||||||
GstTagList *merged_tags;
|
GstTagList *merged_tags;
|
||||||
|
|
||||||
|
@ -361,68 +352,54 @@ gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
*/
|
*/
|
||||||
GST_WARNING_OBJECT (tag, "No tags found");
|
GST_WARNING_OBJECT (tag, "No tags found");
|
||||||
buffer = gst_buffer_new_and_alloc (12);
|
buffer = gst_buffer_new_and_alloc (12);
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL)
|
||||||
GST_ELEMENT_ERROR (tag, CORE, TOO_LAZY, (NULL),
|
goto no_buffer;
|
||||||
("Error creating 12-byte buffer for padding block"));
|
|
||||||
ret = GST_FLOW_ERROR;
|
data = gst_buffer_map (buffer, &size, NULL, GST_MAP_WRITE);
|
||||||
goto cleanup;
|
memset (data, 0, size);
|
||||||
}
|
data[0] = 0x81; /* 0x80 = Last metadata block,
|
||||||
memset (GST_BUFFER_DATA (buffer), 0, GST_BUFFER_SIZE (buffer));
|
* 0x01 = padding block */
|
||||||
GST_BUFFER_DATA (buffer)[0] = 0x81; /* 0x80 = Last metadata block,
|
gst_buffer_unmap (buffer, data, size);
|
||||||
* 0x01 = padding block
|
|
||||||
*/
|
|
||||||
} else {
|
} else {
|
||||||
guchar header[4];
|
guchar header[4];
|
||||||
|
guint8 fbit[1];
|
||||||
|
|
||||||
memset (header, 0, sizeof (header));
|
memset (header, 0, sizeof (header));
|
||||||
header[0] = 0x84; /* 0x80 = Last metadata block,
|
header[0] = 0x84; /* 0x80 = Last metadata block,
|
||||||
* 0x04 = vorbiscomment block
|
* 0x04 = vorbiscomment block */
|
||||||
*/
|
|
||||||
buffer = gst_tag_list_to_vorbiscomment_buffer (merged_tags, header,
|
buffer = gst_tag_list_to_vorbiscomment_buffer (merged_tags, header,
|
||||||
sizeof (header), NULL);
|
sizeof (header), NULL);
|
||||||
GST_DEBUG_OBJECT (tag, "Writing tags %" GST_PTR_FORMAT, merged_tags);
|
GST_DEBUG_OBJECT (tag, "Writing tags %" GST_PTR_FORMAT, merged_tags);
|
||||||
gst_tag_list_free (merged_tags);
|
gst_tag_list_free (merged_tags);
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL)
|
||||||
GST_ELEMENT_ERROR (tag, CORE, TAG, (NULL),
|
goto no_comment;
|
||||||
("Error converting tag list to vorbiscomment buffer"));
|
|
||||||
ret = GST_FLOW_ERROR;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
size = GST_BUFFER_SIZE (buffer) - 4;
|
|
||||||
if ((size > 0xFFFFFF) || (size < 0)) {
|
|
||||||
/* FLAC vorbis comment blocks are limited to 2^24 bytes,
|
|
||||||
* while the vorbis specs allow more than that. Shouldn't
|
|
||||||
* be a real world problem though
|
|
||||||
*/
|
|
||||||
GST_ELEMENT_ERROR (tag, CORE, TAG, (NULL),
|
|
||||||
("Vorbis comment of size %d too long", size));
|
|
||||||
ret = GST_FLOW_ERROR;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
size = gst_buffer_get_size (buffer);
|
||||||
|
if ((size < 4) || ((size - 4) > 0xFFFFFF))
|
||||||
|
goto comment_too_long;
|
||||||
|
|
||||||
|
fbit[0] = 1;
|
||||||
/* Get rid of the framing bit at the end of the vorbiscomment buffer
|
/* Get rid of the framing bit at the end of the vorbiscomment buffer
|
||||||
* if it exists since libFLAC seems to lose sync because of this
|
* if it exists since libFLAC seems to lose sync because of this
|
||||||
* bit in gstflacdec
|
* bit in gstflacdec
|
||||||
*/
|
*/
|
||||||
if (GST_BUFFER_DATA (buffer)[GST_BUFFER_SIZE (buffer) - 1] == 1) {
|
if (gst_buffer_memcmp (buffer, size - 1, fbit, 1) == 0) {
|
||||||
GstBuffer *sub;
|
buffer = gst_buffer_make_writable (buffer);
|
||||||
|
gst_buffer_resize (buffer, 0, size - 1);
|
||||||
sub = gst_buffer_create_sub (buffer, 0, GST_BUFFER_SIZE (buffer) - 1);
|
|
||||||
gst_buffer_unref (buffer);
|
|
||||||
buffer = sub;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The 4 byte metadata block header isn't accounted for in the total
|
/* The 4 byte metadata block header isn't accounted for in the total
|
||||||
* size of the metadata block
|
* size of the metadata block
|
||||||
*/
|
*/
|
||||||
size = GST_BUFFER_SIZE (buffer) - 4;
|
data = gst_buffer_map (buffer, &size, NULL, GST_MAP_WRITE);
|
||||||
|
data[1] = (((size - 4) & 0xFF0000) >> 16);
|
||||||
|
data[2] = (((size - 4) & 0x00FF00) >> 8);
|
||||||
|
data[3] = ((size - 4) & 0x0000FF);
|
||||||
|
gst_buffer_unmap (buffer, data, size);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (tag, "pushing %d byte vorbiscomment buffer", size);
|
||||||
|
|
||||||
GST_BUFFER_DATA (buffer)[1] = ((size & 0xFF0000) >> 16);
|
|
||||||
GST_BUFFER_DATA (buffer)[2] = ((size & 0x00FF00) >> 8);
|
|
||||||
GST_BUFFER_DATA (buffer)[3] = (size & 0x0000FF);
|
|
||||||
GST_DEBUG_OBJECT (tag, "pushing %d byte vorbiscomment buffer",
|
|
||||||
GST_BUFFER_SIZE (buffer));
|
|
||||||
gst_buffer_set_caps (buffer, GST_PAD_CAPS (tag->srcpad));
|
gst_buffer_set_caps (buffer, GST_PAD_CAPS (tag->srcpad));
|
||||||
ret = gst_pad_push (tag->srcpad, buffer);
|
ret = gst_pad_push (tag->srcpad, buffer);
|
||||||
if (ret != GST_FLOW_OK) {
|
if (ret != GST_FLOW_OK) {
|
||||||
|
@ -448,8 +425,34 @@ cleanup:
|
||||||
gst_object_unref (tag);
|
gst_object_unref (tag);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
no_buffer:
|
||||||
|
{
|
||||||
|
GST_ELEMENT_ERROR (tag, CORE, TOO_LAZY, (NULL),
|
||||||
|
("Error creating 12-byte buffer for padding block"));
|
||||||
|
ret = GST_FLOW_ERROR;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
no_comment:
|
||||||
|
{
|
||||||
|
GST_ELEMENT_ERROR (tag, CORE, TAG, (NULL),
|
||||||
|
("Error converting tag list to vorbiscomment buffer"));
|
||||||
|
ret = GST_FLOW_ERROR;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
comment_too_long:
|
||||||
|
{
|
||||||
|
/* FLAC vorbis comment blocks are limited to 2^24 bytes,
|
||||||
|
* while the vorbis specs allow more than that. Shouldn't
|
||||||
|
* be a real world problem though
|
||||||
|
*/
|
||||||
|
GST_ELEMENT_ERROR (tag, CORE, TAG, (NULL),
|
||||||
|
("Vorbis comment of size %d too long", size));
|
||||||
|
ret = GST_FLOW_ERROR;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static GstStateChangeReturn
|
static GstStateChangeReturn
|
||||||
gst_flac_tag_change_state (GstElement * element, GstStateChange transition)
|
gst_flac_tag_change_state (GstElement * element, GstStateChange transition)
|
||||||
|
@ -486,5 +489,5 @@ gst_flac_tag_change_state (GstElement * element, GstStateChange transition)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent_class->change_state (element, transition);
|
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue