diff --git a/ext/flac/gstflacdec.c b/ext/flac/gstflacdec.c index 5132dcf22a..ac0553346a 100644 --- a/ext/flac/gstflacdec.c +++ b/ext/flac/gstflacdec.c @@ -147,7 +147,8 @@ static void gst_flac_dec_metadata_cb (const FLAC__StreamDecoder * static void gst_flac_dec_error_cb (const FLAC__StreamDecoder * 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 * handle the conversions instead of doing it ourself. @@ -173,22 +174,6 @@ GST_STATIC_PAD_TEMPLATE ("sink", 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 "); - - GST_DEBUG_CATEGORY_INIT (flacdec_debug, "flacdec", 0, "flac decoder"); -} - static void gst_flac_dec_class_init (GstFlacDecClass * klass) { @@ -198,14 +183,25 @@ gst_flac_dec_class_init (GstFlacDecClass * klass) gstelement_class = (GstElementClass *) klass; gobject_class = (GObjectClass *) klass; + GST_DEBUG_CATEGORY_INIT (flacdec_debug, "flacdec", 0, "flac decoder"); + gobject_class->finalize = gst_flac_dec_finalize; gstelement_class->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 "); } static void -gst_flac_dec_init (GstFlacDec * flacdec, GstFlacDecClass * klass) +gst_flac_dec_init (GstFlacDec * flacdec) { flacdec->sinkpad = 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)) { GstFlowReturn flow; GstBuffer *buf = NULL; - guint8 *data; - guint size; + guint8 *data, *ptr; + gsize size, left; /* divide by 2 = not very sophisticated way to deal with overlapping */ offset -= SCANBLOCK_SIZE / 2; @@ -515,20 +511,24 @@ gst_flac_dec_scan_for_last_block (GstFlacDec * flacdec, gint64 * samples) return; } - size = GST_BUFFER_SIZE (buf); - data = GST_BUFFER_DATA (buf); + data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ); - while (size > 16) { - if (gst_flac_dec_scan_got_frame (flacdec, data, size, samples)) { + ptr = data; + 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, - offset + GST_BUFFER_SIZE (buf) - size); + offset + size - left); + gst_buffer_unmap (buf, data, size); gst_buffer_unref (buf); return; } - ++data; - --size; + ++ptr; + --left; } + gst_buffer_unmap (buf, data, size); gst_buffer_unref (buf); } } @@ -777,10 +777,11 @@ gst_flac_dec_read_seekable (const FLAC__StreamDecoder * decoder, 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_BUFFER_SIZE (buf), flacdec->offset); - memcpy (buffer, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); - *bytes = GST_BUFFER_SIZE (buf); + *bytes, flacdec->offset); + + gst_buffer_extract (buf, 0, buffer, *bytes); gst_buffer_unref (buf); flacdec->offset += *bytes; @@ -824,6 +825,8 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame, guint samples = frame->header.blocksize; guint j, i; GstClockTime next; + gpointer data; + gsize size; 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 */ ret = gst_pad_alloc_buffer_and_set_caps (flacdec->srcpad, GST_BUFFER_OFFSET (flacdec->pending), - GST_BUFFER_SIZE (flacdec->pending), + gst_buffer_get_size (flacdec->pending), GST_BUFFER_CAPS (flacdec->pending), &outbuf); if (ret == GST_FLOW_OK) { 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); + data = gst_buffer_map (outbuf, &size, NULL, GST_MAP_WRITE); if (width == 8) { - gint8 *outbuffer = (gint8 *) GST_BUFFER_DATA (outbuf); + gint8 *outbuffer = (gint8 *) data; for (i = 0; i < samples; i++) { for (j = 0; j < channels; j++) { @@ -998,7 +1002,7 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame, } } } else if (width == 16) { - gint16 *outbuffer = (gint16 *) GST_BUFFER_DATA (outbuf); + gint16 *outbuffer = (gint16 *) data; for (i = 0; i < samples; i++) { for (j = 0; j < channels; j++) { @@ -1006,7 +1010,7 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame, } } } else if (width == 32) { - gint32 *outbuffer = (gint32 *) GST_BUFFER_DATA (outbuf); + gint32 *outbuffer = (gint32 *) data; for (i = 0; i < samples; i++) { for (j = 0; j < channels; j++) { @@ -1016,6 +1020,7 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame, } else { g_assert_not_reached (); } + gst_buffer_unmap (outbuf, data, size); if (!flacdec->seeking) { 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) { 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); 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=%" 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) { GST_DEBUG_OBJECT (dec, "initializing decoder"); @@ -1384,10 +1389,13 @@ gst_flac_dec_chain (GstPad * pad, GstBuffer * buf) if (dec->framed) { gint64 unused; + guint8 *data; + gsize size; /* 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), - GST_BUFFER_SIZE (buf), &unused); + data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ); + 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 */ if (G_LIKELY (got_audio_frame)) { diff --git a/ext/flac/gstflacenc.c b/ext/flac/gstflacenc.c index a07fcdc0ae..e72ce6ba09 100644 --- a/ext/flac/gstflacenc.c +++ b/ext/flac/gstflacenc.c @@ -149,27 +149,10 @@ enum GST_DEBUG_CATEGORY_STATIC (flacenc_debug); #define GST_CAT_DEFAULT flacenc_debug - -#define _do_init(type) \ - G_STMT_START{ \ - static const GInterfaceInfo tag_setter_info = { \ - 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); +#define gst_flac_enc_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstFlacEnc, gst_flac_enc, GST_TYPE_ELEMENT, + G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL); + G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL)); static void gst_flac_enc_finalize (GObject * object); @@ -257,25 +240,6 @@ gst_flac_enc_quality_get_type (void) 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 "); - - GST_DEBUG_CATEGORY_INIT (flacenc_debug, "flacenc", 0, - "Flac encoding element"); -} - static void gst_flac_enc_class_init (GstFlacEncClass * klass) { @@ -285,6 +249,9 @@ gst_flac_enc_class_init (GstFlacEncClass * klass) gobject_class = (GObjectClass *) 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->get_property = gst_flac_enc_get_property; 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)); 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 "); } 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"); gst_pad_set_chain_function (flacenc->sinkpad, @@ -505,6 +482,8 @@ gst_flac_enc_set_metadata (GstFlacEnc * flacenc, guint64 total_samples) GstStructure *structure; GstTagImageType image_type = GST_TAG_IMAGE_TYPE_NONE; gint i; + guint8 *data; + gsize size; for (i = 0; i < n_images + n_preview_images; i++) { if (i < n_images) { @@ -530,8 +509,11 @@ gst_flac_enc_set_metadata (GstFlacEnc * flacenc, guint64 total_samples) else image_type = image_type + 2; + data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ); 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 */ flacenc->meta[entries]->data.picture.type = image_type; 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); for (l = enc->headers; l != NULL; l = l->next) { - const guint8 *data; - guint size; + GstBuffer *buf; + guint8 *data; + gsize size; /* mark buffers so oggmux will ignore them if it already muxed the * header buffers from the streamheaders field in the caps */ - l->data = gst_buffer_make_metadata_writable (GST_BUFFER (l->data)); - GST_BUFFER_FLAG_SET (GST_BUFFER (l->data), GST_BUFFER_FLAG_IN_CAPS); + l->data = gst_buffer_make_writable (GST_BUFFER_CAST (l->data)); - data = GST_BUFFER_DATA (GST_BUFFER_CAST (l->data)); - size = GST_BUFFER_SIZE (GST_BUFFER_CAST (l->data)); + buf = 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 */ 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) { - streaminfo = GST_BUFFER_CAST (l->data); + streaminfo = buf; } 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) { @@ -948,20 +934,26 @@ gst_flac_enc_process_stream_headers (GstFlacEnc * enc) { GstBuffer *buf; guint16 num; + guint8 *bdata; + gsize bsize, slen; /* minus one for the marker that is merged with streaminfo here */ num = g_list_length (enc->headers) - 1; - buf = gst_buffer_new_and_alloc (13 + GST_BUFFER_SIZE (streaminfo)); - GST_BUFFER_DATA (buf)[0] = 0x7f; - memcpy (GST_BUFFER_DATA (buf) + 1, "FLAC", 4); - GST_BUFFER_DATA (buf)[5] = 0x01; /* mapping version major */ - GST_BUFFER_DATA (buf)[6] = 0x00; /* mapping version minor */ - GST_BUFFER_DATA (buf)[7] = (num & 0xFF00) >> 8; - GST_BUFFER_DATA (buf)[8] = (num & 0x00FF) >> 0; - memcpy (GST_BUFFER_DATA (buf) + 9, "fLaC", 4); - memcpy (GST_BUFFER_DATA (buf) + 13, GST_BUFFER_DATA (streaminfo), - GST_BUFFER_SIZE (streaminfo)); + slen = gst_buffer_get_size (streaminfo); + buf = gst_buffer_new_and_alloc (13 + slen); + + bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_WRITE); + bdata[0] = 0x7f; + memcpy (bdata + 1, "FLAC", 4); + bdata[5] = 0x01; /* mapping version major */ + bdata[6] = 0x00; /* mapping version minor */ + bdata[7] = (num & 0xFF00) >> 8; + 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); gst_buffer_unref (buf); } @@ -971,10 +963,10 @@ gst_flac_enc_process_stream_headers (GstFlacEnc * enc) /* add other headers, if there are any */ for (l = enc->headers; l != NULL; l = l->next) { - if (GST_BUFFER_CAST (l->data) != marker && - GST_BUFFER_CAST (l->data) != streaminfo && - GST_BUFFER_CAST (l->data) != vorbiscomment) { - notgst_value_array_append_buffer (&array, GST_BUFFER_CAST (l->data)); + GstBuffer *buf = GST_BUFFER_CAST (l->data); + + if (buf != marker && buf != streaminfo && buf != vorbiscomment) { + notgst_value_array_append_buffer (&array, buf); } } @@ -994,9 +986,11 @@ push_headers: buf = GST_BUFFER (l->data); gst_buffer_set_caps (buf, caps); 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_BUFFER_SIZE (buf)); +#endif (void) gst_pad_push (enc->srcpad, buf); l->data = NULL; } @@ -1021,7 +1015,7 @@ gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder, return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; 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) { guint64 granulepos; @@ -1064,8 +1058,10 @@ gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder, } else if (flacenc->got_headers && samples == 0) { GST_DEBUG_OBJECT (flacenc, "Fixing up headers at pos=%" G_GUINT64_FORMAT ", size=%u", flacenc->offset, (guint) bytes); +#if 0 GST_MEMDUMP_OBJECT (flacenc, "Presumed header fragment", GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf)); +#endif } else { GST_LOG ("Pushing buffer: ts=%" GST_TIME_FORMAT ", samples=%u, size=%u, " "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; FLAC__int32 *data; - gulong insize; + gsize bsize; gint samples, width; gulong i; FLAC__bool res; + gpointer bdata; flacenc = GST_FLAC_ENC (GST_PAD_PARENT (pad)); @@ -1238,30 +1235,30 @@ gst_flac_enc_chain (GstPad * pad, GstBuffer * buffer) else flacenc->next_ts = GST_CLOCK_TIME_NONE; - insize = GST_BUFFER_SIZE (buffer); - samples = insize / (width >> 3); + bdata = gst_buffer_map (buffer, &bsize, NULL, GST_MAP_READ); + samples = bsize / (width >> 3); data = g_malloc (samples * sizeof (FLAC__int32)); if (width == 8) { - gint8 *indata = (gint8 *) GST_BUFFER_DATA (buffer); + gint8 *indata = (gint8 *) bdata; for (i = 0; i < samples; i++) data[i] = (FLAC__int32) indata[i]; } else if (width == 16) { - gint16 *indata = (gint16 *) GST_BUFFER_DATA (buffer); + gint16 *indata = (gint16 *) bdata; for (i = 0; i < samples; i++) data[i] = (FLAC__int32) indata[i]; } else if (width == 32) { - gint32 *indata = (gint32 *) GST_BUFFER_DATA (buffer); + gint32 *indata = (gint32 *) bdata; for (i = 0; i < samples; i++) data[i] = (FLAC__int32) indata[i]; } else { g_assert_not_reached (); } - + gst_buffer_unmap (buffer, bdata, bsize); gst_buffer_unref (buffer); res = FLAC__stream_encoder_process_interleaved (flacenc->encoder, diff --git a/ext/flac/gstflactag.c b/ext/flac/gstflactag.c index 682ceb8890..3382999fc4 100644 --- a/ext/flac/gstflactag.c +++ b/ext/flac/gstflactag.c @@ -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 void -gst_flac_tag_setup_interfaces (GType flac_tag_type) -{ - static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL }; +#define gst_flac_tag_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstFlacTag, gst_flac_tag, GST_TYPE_ELEMENT, + G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, 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 "); - - 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 gst_flac_tag_class_init (GstFlacTagClass * klass) @@ -131,13 +107,23 @@ gst_flac_tag_class_init (GstFlacTagClass * klass) GstElementClass *gstelement_class; GObjectClass *gobject_class; + GST_DEBUG_CATEGORY_INIT (flactag_debug, "flactag", 0, "flac tag rewriter"); + gstelement_class = (GstElementClass *) klass; gobject_class = (GObjectClass *) klass; - parent_class = g_type_class_peek_parent (klass); - gobject_class->dispose = gst_flac_tag_dispose; 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 "); + + 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 @@ -163,7 +149,7 @@ gst_flac_tag_dispose (GObject * object) static void -gst_flac_tag_init (GstFlacTag * tag, GstFlacTagClass * klass) +gst_flac_tag_init (GstFlacTag * tag) { /* create the sink and src pads */ tag->sinkpad = @@ -197,6 +183,8 @@ gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer) { GstFlacTag *tag; GstFlowReturn ret; + guint8 *data; + gsize size; ret = GST_FLOW_OK; 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); 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_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 */ if (tag->state == GST_FLAC_TAG_STATE_METADATA_BLOCKS) { - guint size; guint type; gboolean is_last; const guint8 *block_header; @@ -250,13 +237,14 @@ gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer) if (gst_adapter_available (tag->adapter) < 4) 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); type = block_header[0] & 0x7F; size = (block_header[1] << 16) | (block_header[2] << 8) | block_header[3]; + gst_adapter_unmap (tag->adapter, 0); /* The 4 bytes long header isn't included in the metadata size */ 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 * 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) { 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 */ if (tag->vorbiscomment != NULL) { + guint8 id_data[4]; /* We found some tags, try to parse them and notify the other elements * that we encountered some 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, - GST_BUFFER_DATA (tag->vorbiscomment), 4, NULL); + id_data, 4, NULL); if (tag->tags != NULL) { gst_element_found_tags (GST_ELEMENT (tag), 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) { GstBuffer *buffer; - gint size; const GstTagList *user_tags; GstTagList *merged_tags; @@ -361,68 +352,54 @@ gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer) */ GST_WARNING_OBJECT (tag, "No tags found"); buffer = gst_buffer_new_and_alloc (12); - if (buffer == NULL) { - GST_ELEMENT_ERROR (tag, CORE, TOO_LAZY, (NULL), - ("Error creating 12-byte buffer for padding block")); - ret = GST_FLOW_ERROR; - goto cleanup; - } - memset (GST_BUFFER_DATA (buffer), 0, GST_BUFFER_SIZE (buffer)); - GST_BUFFER_DATA (buffer)[0] = 0x81; /* 0x80 = Last metadata block, - * 0x01 = padding block - */ + if (buffer == NULL) + goto no_buffer; + + data = gst_buffer_map (buffer, &size, NULL, GST_MAP_WRITE); + memset (data, 0, size); + data[0] = 0x81; /* 0x80 = Last metadata block, + * 0x01 = padding block */ + gst_buffer_unmap (buffer, data, size); } else { guchar header[4]; + guint8 fbit[1]; memset (header, 0, sizeof (header)); header[0] = 0x84; /* 0x80 = Last metadata block, - * 0x04 = vorbiscomment block - */ + * 0x04 = vorbiscomment block */ buffer = gst_tag_list_to_vorbiscomment_buffer (merged_tags, header, sizeof (header), NULL); GST_DEBUG_OBJECT (tag, "Writing tags %" GST_PTR_FORMAT, merged_tags); gst_tag_list_free (merged_tags); - if (buffer == NULL) { - GST_ELEMENT_ERROR (tag, CORE, TAG, (NULL), - ("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; - } + if (buffer == NULL) + goto no_comment; + 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 * if it exists since libFLAC seems to lose sync because of this * bit in gstflacdec */ - if (GST_BUFFER_DATA (buffer)[GST_BUFFER_SIZE (buffer) - 1] == 1) { - GstBuffer *sub; - - sub = gst_buffer_create_sub (buffer, 0, GST_BUFFER_SIZE (buffer) - 1); - gst_buffer_unref (buffer); - buffer = sub; + if (gst_buffer_memcmp (buffer, size - 1, fbit, 1) == 0) { + buffer = gst_buffer_make_writable (buffer); + gst_buffer_resize (buffer, 0, size - 1); } } /* The 4 byte metadata block header isn't accounted for in the total * 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)); ret = gst_pad_push (tag->srcpad, buffer); if (ret != GST_FLOW_OK) { @@ -448,8 +425,34 @@ cleanup: gst_object_unref (tag); 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 gst_flac_tag_change_state (GstElement * element, GstStateChange transition) @@ -486,5 +489,5 @@ gst_flac_tag_change_state (GstElement * element, GstStateChange transition) break; } - return parent_class->change_state (element, transition); + return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); }