aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Nauwelaerts2011-09-26 07:44:01 -0500
committerNikhil Devshatwar2013-05-17 04:40:40 -0500
commitf0b17b90d209ba54cbcbe4af5491b5e1ec35919f (patch)
tree4e33298b9878bd99f86a139588ee2aa288d49e34
parent83104b62efdb5152c7bb9d5e40dc48ed7b1360f4 (diff)
downloadgst-plugins-ugly0-10-f0b17b90d209ba54cbcbe4af5491b5e1ec35919f.tar.gz
gst-plugins-ugly0-10-f0b17b90d209ba54cbcbe4af5491b5e1ec35919f.tar.xz
gst-plugins-ugly0-10-f0b17b90d209ba54cbcbe4af5491b5e1ec35919f.zip
lamemp3enc: port to audioencoder
-rw-r--r--ext/lame/Makefile.am6
-rw-r--r--ext/lame/gstlamemp3enc.c514
-rw-r--r--ext/lame/gstlamemp3enc.h19
3 files changed, 119 insertions, 420 deletions
diff --git a/ext/lame/Makefile.am b/ext/lame/Makefile.am
index 4d83abaf..439a621d 100644
--- a/ext/lame/Makefile.am
+++ b/ext/lame/Makefile.am
@@ -1,8 +1,10 @@
1plugin_LTLIBRARIES = libgstlame.la 1plugin_LTLIBRARIES = libgstlame.la
2 2
3libgstlame_la_SOURCES = gstlame.c gstlamemp3enc.c plugin.c 3libgstlame_la_SOURCES = gstlame.c gstlamemp3enc.c plugin.c
4libgstlame_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(LAME_CFLAGS) 4libgstlame_la_CFLAGS = -DGST_USE_UNSTABLE_API \
5libgstlame_la_LIBADD = $(LAME_LIBS) $(GST_PLUGINS_BASE_LIBS) -lgstpbutils-@GST_MAJORMINOR@ $(GST_LIBS) 5 $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(LAME_CFLAGS)
6libgstlame_la_LIBADD = $(LAME_LIBS) $(GST_PLUGINS_BASE_LIBS) \
7 -lgstaudio-$(GST_MAJORMINOR) $(GST_LIBS)
6libgstlame_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) 8libgstlame_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
7libgstlame_la_LIBTOOLFLAGS = --tag=disable-static 9libgstlame_la_LIBTOOLFLAGS = --tag=disable-static
8 10
diff --git a/ext/lame/gstlamemp3enc.c b/ext/lame/gstlamemp3enc.c
index c80ec8bc..6b1a0d1d 100644
--- a/ext/lame/gstlamemp3enc.c
+++ b/ext/lame/gstlamemp3enc.c
@@ -68,8 +68,6 @@
68#include "gstlamemp3enc.h" 68#include "gstlamemp3enc.h"
69#include <gst/gst-i18n-plugin.h> 69#include <gst/gst-i18n-plugin.h>
70 70
71#include <gst/pbutils/descriptions.h>
72
73/* lame < 3.98 */ 71/* lame < 3.98 */
74#ifndef HAVE_LAME_SET_VBR_QUALITY 72#ifndef HAVE_LAME_SET_VBR_QUALITY
75#define lame_set_VBR_quality(flags,q) lame_set_VBR_q((flags),(int)(q)) 73#define lame_set_VBR_quality(flags,q) lame_set_VBR_q((flags),(int)(q))
@@ -182,15 +180,19 @@ static void gst_lamemp3enc_base_init (gpointer g_class);
182static void gst_lamemp3enc_class_init (GstLameMP3EncClass * klass); 180static void gst_lamemp3enc_class_init (GstLameMP3EncClass * klass);
183static void gst_lamemp3enc_init (GstLameMP3Enc * gst_lame); 181static void gst_lamemp3enc_init (GstLameMP3Enc * gst_lame);
184 182
183static gboolean gst_lamemp3enc_start (GstAudioEncoder * enc);
184static gboolean gst_lamemp3enc_stop (GstAudioEncoder * enc);
185static gboolean gst_lamemp3enc_set_format (GstAudioEncoder * enc,
186 GstAudioInfo * info);
187static GstFlowReturn gst_lamemp3enc_handle_frame (GstAudioEncoder * enc,
188 GstBuffer * in_buf);
189static void gst_lamemp3enc_flush (GstAudioEncoder * enc);
190
185static void gst_lamemp3enc_set_property (GObject * object, guint prop_id, 191static void gst_lamemp3enc_set_property (GObject * object, guint prop_id,
186 const GValue * value, GParamSpec * pspec); 192 const GValue * value, GParamSpec * pspec);
187static void gst_lamemp3enc_get_property (GObject * object, guint prop_id, 193static void gst_lamemp3enc_get_property (GObject * object, guint prop_id,
188 GValue * value, GParamSpec * pspec); 194 GValue * value, GParamSpec * pspec);
189static gboolean gst_lamemp3enc_sink_event (GstPad * pad, GstEvent * event);
190static GstFlowReturn gst_lamemp3enc_chain (GstPad * pad, GstBuffer * buf);
191static gboolean gst_lamemp3enc_setup (GstLameMP3Enc * lame, GstTagList ** tags); 195static gboolean gst_lamemp3enc_setup (GstLameMP3Enc * lame, GstTagList ** tags);
192static GstStateChangeReturn gst_lamemp3enc_change_state (GstElement * element,
193 GstStateChange transition);
194 196
195static GstElementClass *parent_class = NULL; 197static GstElementClass *parent_class = NULL;
196 198
@@ -211,17 +213,10 @@ gst_lamemp3enc_get_type (void)
211 0, 213 0,
212 (GInstanceInitFunc) gst_lamemp3enc_init, 214 (GInstanceInitFunc) gst_lamemp3enc_init,
213 }; 215 };
214 static const GInterfaceInfo preset_info = {
215 NULL,
216 NULL,
217 NULL
218 };
219 216
220 gst_lamemp3enc_type = 217 gst_lamemp3enc_type =
221 g_type_register_static (GST_TYPE_ELEMENT, "GstLameMP3Enc", 218 g_type_register_static (GST_TYPE_AUDIO_ENCODER, "GstLameMP3Enc",
222 &gst_lamemp3enc_info, 0); 219 &gst_lamemp3enc_info, 0);
223 g_type_add_interface_static (gst_lamemp3enc_type, GST_TYPE_PRESET,
224 &preset_info);
225 } 220 }
226 return gst_lamemp3enc_type; 221 return gst_lamemp3enc_type;
227} 222}
@@ -263,9 +258,11 @@ gst_lamemp3enc_class_init (GstLameMP3EncClass * klass)
263{ 258{
264 GObjectClass *gobject_class; 259 GObjectClass *gobject_class;
265 GstElementClass *gstelement_class; 260 GstElementClass *gstelement_class;
261 GstAudioEncoderClass *base_class;
266 262
267 gobject_class = (GObjectClass *) klass; 263 gobject_class = (GObjectClass *) klass;
268 gstelement_class = (GstElementClass *) klass; 264 gstelement_class = (GstElementClass *) klass;
265 base_class = (GstAudioEncoderClass *) klass;
269 266
270 parent_class = g_type_class_peek_parent (klass); 267 parent_class = g_type_class_peek_parent (klass);
271 268
@@ -273,64 +270,89 @@ gst_lamemp3enc_class_init (GstLameMP3EncClass * klass)
273 gobject_class->get_property = gst_lamemp3enc_get_property; 270 gobject_class->get_property = gst_lamemp3enc_get_property;
274 gobject_class->finalize = gst_lamemp3enc_finalize; 271 gobject_class->finalize = gst_lamemp3enc_finalize;
275 272
273 base_class->start = GST_DEBUG_FUNCPTR (gst_lamemp3enc_start);
274 base_class->stop = GST_DEBUG_FUNCPTR (gst_lamemp3enc_stop);
275 base_class->set_format = GST_DEBUG_FUNCPTR (gst_lamemp3enc_set_format);
276 base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_lamemp3enc_handle_frame);
277 base_class->flush = GST_DEBUG_FUNCPTR (gst_lamemp3enc_flush);
278
276 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TARGET, 279 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TARGET,
277 g_param_spec_enum ("target", "Target", 280 g_param_spec_enum ("target", "Target",
278 "Optimize for quality or bitrate", GST_TYPE_LAMEMP3ENC_TARGET, 281 "Optimize for quality or bitrate", GST_TYPE_LAMEMP3ENC_TARGET,
279 DEFAULT_TARGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 282 DEFAULT_TARGET,
283 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
280 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE, 284 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
281 g_param_spec_int ("bitrate", "Bitrate (kb/s)", 285 g_param_spec_int ("bitrate", "Bitrate (kb/s)",
282 "Bitrate in kbit/sec (Only valid if target is bitrate, for CBR one " 286 "Bitrate in kbit/sec (Only valid if target is bitrate, for CBR one "
283 "of 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, " 287 "of 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, "
284 "256 or 320)", 8, 320, DEFAULT_BITRATE, 288 "256 or 320)", 8, 320, DEFAULT_BITRATE,
285 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 289 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
286 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CBR, 290 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CBR,
287 g_param_spec_boolean ("cbr", "CBR", "Enforce constant bitrate encoding " 291 g_param_spec_boolean ("cbr", "CBR", "Enforce constant bitrate encoding "
288 "(Only valid if target is bitrate)", DEFAULT_CBR, 292 "(Only valid if target is bitrate)", DEFAULT_CBR,
289 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 293 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
290 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY, 294 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
291 g_param_spec_float ("quality", "Quality", 295 g_param_spec_float ("quality", "Quality",
292 "VBR Quality from 0 to 10, 0 being the best " 296 "VBR Quality from 0 to 10, 0 being the best "
293 "(Only valid if target is quality)", 0.0, 9.999, 297 "(Only valid if target is quality)", 0.0, 9.999,
294 DEFAULT_QUALITY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 298 DEFAULT_QUALITY,
299 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
295 g_object_class_install_property (G_OBJECT_CLASS (klass), 300 g_object_class_install_property (G_OBJECT_CLASS (klass),
296 ARG_ENCODING_ENGINE_QUALITY, g_param_spec_enum ("encoding-engine-quality", 301 ARG_ENCODING_ENGINE_QUALITY, g_param_spec_enum ("encoding-engine-quality",
297 "Encoding Engine Quality", "Quality/speed of the encoding engine, " 302 "Encoding Engine Quality", "Quality/speed of the encoding engine, "
298 "this does not affect the bitrate!", 303 "this does not affect the bitrate!",
299 GST_TYPE_LAMEMP3ENC_ENCODING_ENGINE_QUALITY, 304 GST_TYPE_LAMEMP3ENC_ENCODING_ENGINE_QUALITY,
300 DEFAULT_ENCODING_ENGINE_QUALITY, 305 DEFAULT_ENCODING_ENGINE_QUALITY,
301 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 306 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
302 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MONO, 307 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MONO,
303 g_param_spec_boolean ("mono", "Mono", "Enforce mono encoding", 308 g_param_spec_boolean ("mono", "Mono", "Enforce mono encoding",
304 DEFAULT_MONO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 309 DEFAULT_MONO,
310 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
311}
312
313static void
314gst_lamemp3enc_init (GstLameMP3Enc * lame)
315{
316}
305 317
306 gstelement_class->change_state = 318static gboolean
307 GST_DEBUG_FUNCPTR (gst_lamemp3enc_change_state); 319gst_lamemp3enc_start (GstAudioEncoder * enc)
320{
321 GstLameMP3Enc *lame = GST_LAMEMP3ENC (enc);
322
323 GST_DEBUG_OBJECT (lame, "start");
324 return TRUE;
308} 325}
309 326
310static gboolean 327static gboolean
311gst_lamemp3enc_src_setcaps (GstPad * pad, GstCaps * caps) 328gst_lamemp3enc_stop (GstAudioEncoder * enc)
312{ 329{
313 GST_DEBUG_OBJECT (pad, "caps: %" GST_PTR_FORMAT, caps); 330 GstLameMP3Enc *lame = GST_LAMEMP3ENC (enc);
331
332 GST_DEBUG_OBJECT (lame, "stop");
333
334 gst_lamemp3enc_release_memory (lame);
314 return TRUE; 335 return TRUE;
315} 336}
316 337
317static gboolean 338static gboolean
318gst_lamemp3enc_sink_setcaps (GstPad * pad, GstCaps * caps) 339gst_lamemp3enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
319{ 340{
320 GstLameMP3Enc *lame; 341 GstLameMP3Enc *lame;
321 gint out_samplerate; 342 gint out_samplerate;
322 gint version; 343 gint version;
323 GstStructure *structure;
324 GstCaps *othercaps; 344 GstCaps *othercaps;
345 GstClockTime latency;
325 GstTagList *tags = NULL; 346 GstTagList *tags = NULL;
326 347
327 lame = GST_LAMEMP3ENC (GST_PAD_PARENT (pad)); 348 lame = GST_LAMEMP3ENC (enc);
328 structure = gst_caps_get_structure (caps, 0);
329 349
330 if (!gst_structure_get_int (structure, "rate", &lame->samplerate)) 350 /* parameters already parsed for us */
331 goto no_rate; 351 lame->samplerate = GST_AUDIO_INFO_RATE (info);
332 if (!gst_structure_get_int (structure, "channels", &lame->num_channels)) 352 lame->num_channels = GST_AUDIO_INFO_CHANNELS (info);
333 goto no_channels; 353
354 /* but we might be asked to reconfigure, so reset */
355 gst_lamemp3enc_release_memory (lame);
334 356
335 GST_DEBUG_OBJECT (lame, "setting up lame"); 357 GST_DEBUG_OBJECT (lame, "setting up lame");
336 if (!gst_lamemp3enc_setup (lame, &tags)) 358 if (!gst_lamemp3enc_setup (lame, &tags))
@@ -362,39 +384,27 @@ gst_lamemp3enc_sink_setcaps (GstPad * pad, GstCaps * caps)
362 "rate", G_TYPE_INT, out_samplerate, NULL); 384 "rate", G_TYPE_INT, out_samplerate, NULL);
363 385
364 /* and use these caps */ 386 /* and use these caps */
365 gst_pad_set_caps (lame->srcpad, othercaps); 387 gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), othercaps);
366
367 if (tags) {
368 gst_pb_utils_add_codec_description_to_tag_list (tags, GST_TAG_CODEC,
369 othercaps);
370 gst_pb_utils_add_codec_description_to_tag_list (tags, GST_TAG_AUDIO_CODEC,
371 othercaps);
372 }
373
374 gst_caps_unref (othercaps); 388 gst_caps_unref (othercaps);
375 389
390 /* base class feedback:
391 * - we will handle buffers, just hand us all available
392 * - report latency */
393 latency = gst_util_uint64_scale_int (lame_get_framesize (lame->lgf),
394 GST_SECOND, lame->samplerate);
395 gst_audio_encoder_set_latency (enc, latency, latency);
396
376 if (tags) 397 if (tags)
377 gst_element_found_tags_for_pad (GST_ELEMENT_CAST (lame), lame->srcpad, 398 gst_audio_encoder_merge_tags (enc, tags, GST_TAG_MERGE_REPLACE);
378 tags);
379 399
380 return TRUE; 400 return TRUE;
381 401
382no_rate:
383 {
384 GST_ERROR_OBJECT (lame, "input caps have no sample rate field");
385 return FALSE;
386 }
387no_channels:
388 {
389 GST_ERROR_OBJECT (lame, "input caps have no channels field");
390 return FALSE;
391 }
392zero_output_rate: 402zero_output_rate:
393 { 403 {
394 GST_ELEMENT_ERROR (lame, LIBRARY, SETTINGS, (NULL),
395 ("LAMEMP3ENC decided on a zero sample rate"));
396 if (tags) 404 if (tags)
397 gst_tag_list_free (tags); 405 gst_tag_list_free (tags);
406 GST_ELEMENT_ERROR (lame, LIBRARY, SETTINGS, (NULL),
407 ("LAMEMP3ENC decided on a zero sample rate"));
398 return FALSE; 408 return FALSE;
399 } 409 }
400setup_failed: 410setup_failed:
@@ -405,152 +415,6 @@ setup_failed:
405 } 415 }
406} 416}
407 417
408static GstCaps *
409gst_lamemp3enc_sink_getcaps (GstPad * pad)
410{
411 const GstCaps *templ_caps;
412 GstLameMP3Enc *lame;
413 GstCaps *allowed = NULL;
414 GstCaps *caps, *filter_caps;
415 gint i, j;
416
417 lame = GST_LAMEMP3ENC (gst_pad_get_parent (pad));
418
419 /* we want to be able to communicate to upstream elements like audioconvert
420 * and audioresample any rate/channel restrictions downstream (e.g. muxer
421 * only accepting certain sample rates) */
422 templ_caps = gst_pad_get_pad_template_caps (pad);
423 allowed = gst_pad_get_allowed_caps (lame->srcpad);
424 if (!allowed || gst_caps_is_empty (allowed) || gst_caps_is_any (allowed)) {
425 caps = gst_caps_copy (templ_caps);
426 goto done;
427 }
428
429 filter_caps = gst_caps_new_empty ();
430
431 for (i = 0; i < gst_caps_get_size (templ_caps); i++) {
432 GQuark q_name;
433
434 q_name = gst_structure_get_name_id (gst_caps_get_structure (templ_caps, i));
435
436 /* pick rate + channel fields from allowed caps */
437 for (j = 0; j < gst_caps_get_size (allowed); j++) {
438 const GstStructure *allowed_s = gst_caps_get_structure (allowed, j);
439 const GValue *val;
440 GstStructure *s;
441
442 s = gst_structure_id_empty_new (q_name);
443 if ((val = gst_structure_get_value (allowed_s, "rate")))
444 gst_structure_set_value (s, "rate", val);
445 if ((val = gst_structure_get_value (allowed_s, "channels")))
446 gst_structure_set_value (s, "channels", val);
447
448 gst_caps_merge_structure (filter_caps, s);
449 }
450 }
451
452 caps = gst_caps_intersect (filter_caps, templ_caps);
453 gst_caps_unref (filter_caps);
454
455done:
456
457 gst_caps_replace (&allowed, NULL);
458 gst_object_unref (lame);
459
460 return caps;
461}
462
463static gint64
464gst_lamemp3enc_get_latency (GstLameMP3Enc * lame)
465{
466 return gst_util_uint64_scale_int (lame_get_framesize (lame->lgf),
467 GST_SECOND, lame->samplerate);
468}
469
470static gboolean
471gst_lamemp3enc_src_query (GstPad * pad, GstQuery * query)
472{
473 gboolean res = TRUE;
474 GstLameMP3Enc *lame;
475 GstPad *peerpad;
476
477 lame = GST_LAMEMP3ENC (gst_pad_get_parent (pad));
478 peerpad = gst_pad_get_peer (GST_PAD (lame->sinkpad));
479
480 switch (GST_QUERY_TYPE (query)) {
481 case GST_QUERY_LATENCY:
482 {
483 if ((res = gst_pad_query (peerpad, query))) {
484 gboolean live;
485 GstClockTime min_latency, max_latency;
486 gint64 latency;
487
488 if (lame->lgf == NULL)
489 break;
490
491 gst_query_parse_latency (query, &live, &min_latency, &max_latency);
492
493 latency = gst_lamemp3enc_get_latency (lame);
494
495 /* add our latency */
496 min_latency += latency;
497 if (max_latency != -1)
498 max_latency += latency;
499
500 gst_query_set_latency (query, live, min_latency, max_latency);
501 }
502 break;
503 }
504 default:
505 res = gst_pad_query (peerpad, query);
506 break;
507 }
508
509 gst_object_unref (peerpad);
510 gst_object_unref (lame);
511 return res;
512}
513
514static void
515gst_lamemp3enc_init (GstLameMP3Enc * lame)
516{
517 GST_DEBUG_OBJECT (lame, "starting initialization");
518
519 lame->sinkpad =
520 gst_pad_new_from_static_template (&gst_lamemp3enc_sink_template, "sink");
521 gst_pad_set_event_function (lame->sinkpad,
522 GST_DEBUG_FUNCPTR (gst_lamemp3enc_sink_event));
523 gst_pad_set_chain_function (lame->sinkpad,
524 GST_DEBUG_FUNCPTR (gst_lamemp3enc_chain));
525 gst_pad_set_setcaps_function (lame->sinkpad,
526 GST_DEBUG_FUNCPTR (gst_lamemp3enc_sink_setcaps));
527 gst_pad_set_getcaps_function (lame->sinkpad,
528 GST_DEBUG_FUNCPTR (gst_lamemp3enc_sink_getcaps));
529 gst_element_add_pad (GST_ELEMENT (lame), lame->sinkpad);
530
531 lame->srcpad =
532 gst_pad_new_from_static_template (&gst_lamemp3enc_src_template, "src");
533 gst_pad_set_query_function (lame->srcpad,
534 GST_DEBUG_FUNCPTR (gst_lamemp3enc_src_query));
535 gst_pad_set_setcaps_function (lame->srcpad,
536 GST_DEBUG_FUNCPTR (gst_lamemp3enc_src_setcaps));
537 gst_element_add_pad (GST_ELEMENT (lame), lame->srcpad);
538
539 lame->samplerate = 44100;
540 lame->num_channels = 2;
541 lame->setup = FALSE;
542
543 /* Set default settings */
544 lame->target = DEFAULT_TARGET;
545 lame->bitrate = DEFAULT_BITRATE;
546 lame->cbr = DEFAULT_CBR;
547 lame->quality = DEFAULT_QUALITY;
548 lame->encoding_engine_quality = DEFAULT_ENCODING_ENGINE_QUALITY;
549 lame->mono = DEFAULT_MONO;
550
551 GST_DEBUG_OBJECT (lame, "done initializing");
552}
553
554/* <php-emulation-mode>three underscores for ___rate is really really really 418/* <php-emulation-mode>three underscores for ___rate is really really really
555 * private as opposed to one underscore<php-emulation-mode> */ 419 * private as opposed to one underscore<php-emulation-mode> */
556/* call this MACRO outside of the NULL state so that we have a higher chance 420/* call this MACRO outside of the NULL state so that we have a higher chance
@@ -654,128 +518,64 @@ gst_lamemp3enc_get_property (GObject * object, guint prop_id, GValue * value,
654 } 518 }
655} 519}
656 520
657static gboolean 521static GstFlowReturn
658gst_lamemp3enc_sink_event (GstPad * pad, GstEvent * event) 522gst_lamemp3enc_flush_full (GstLameMP3Enc * lame, gboolean push)
659{ 523{
660 gboolean ret; 524 GstBuffer *buf;
661 GstLameMP3Enc *lame; 525 gint size;
662 526 GstFlowReturn result = GST_FLOW_OK;
663 lame = GST_LAMEMP3ENC (gst_pad_get_parent (pad));
664
665 switch (GST_EVENT_TYPE (event)) {
666 case GST_EVENT_EOS:{
667 GST_DEBUG_OBJECT (lame, "handling EOS event");
668
669 if (lame->lgf != NULL) {
670 GstBuffer *buf;
671 gint size;
672
673 buf = gst_buffer_new_and_alloc (7200);
674 size = lame_encode_flush (lame->lgf, GST_BUFFER_DATA (buf), 7200);
675
676 if (size > 0 && lame->last_flow == GST_FLOW_OK) {
677 gint64 duration;
678
679 duration = gst_util_uint64_scale (size, 8 * GST_SECOND,
680 1000 * lame->bitrate);
681
682 if (lame->last_ts == GST_CLOCK_TIME_NONE) {
683 lame->last_ts = lame->eos_ts;
684 lame->last_duration = duration;
685 } else {
686 lame->last_duration += duration;
687 }
688
689 GST_BUFFER_TIMESTAMP (buf) = lame->last_ts;
690 GST_BUFFER_DURATION (buf) = lame->last_duration;
691 lame->last_ts = GST_CLOCK_TIME_NONE;
692 GST_BUFFER_SIZE (buf) = size;
693 GST_DEBUG_OBJECT (lame, "pushing final packet of %u bytes", size);
694 gst_buffer_set_caps (buf, GST_PAD_CAPS (lame->srcpad));
695 gst_pad_push (lame->srcpad, buf);
696 } else {
697 GST_DEBUG_OBJECT (lame, "no final packet (size=%d, last_flow=%s)",
698 size, gst_flow_get_name (lame->last_flow));
699 gst_buffer_unref (buf);
700 }
701 }
702
703 ret = gst_pad_event_default (pad, event);
704 break;
705 }
706 case GST_EVENT_FLUSH_START:
707 GST_DEBUG_OBJECT (lame, "handling FLUSH start event");
708 /* forward event */
709 ret = gst_pad_push_event (lame->srcpad, event);
710 break;
711 case GST_EVENT_FLUSH_STOP:
712 {
713 guchar *mp3_data = NULL;
714 gint mp3_buffer_size;
715
716 GST_DEBUG_OBJECT (lame, "handling FLUSH stop event");
717
718 if (lame->lgf) {
719 /* clear buffers if we already have lame set up */
720 mp3_buffer_size = 7200;
721 mp3_data = g_malloc (mp3_buffer_size);
722 lame_encode_flush (lame->lgf, mp3_data, mp3_buffer_size);
723 g_free (mp3_data);
724 }
725
726 ret = gst_pad_push_event (lame->srcpad, event);
727 break;
728 }
729 case GST_EVENT_TAG:{
730 GstTagList *tags;
731 527
732 gst_event_parse_tag (event, &tags); 528 if (!lame->lgf)
529 return GST_FLOW_OK;
733 530
734 tags = gst_tag_list_copy (tags); 531 buf = gst_buffer_new_and_alloc (7200);
735 gst_event_unref (event); 532 size = lame_encode_flush (lame->lgf, GST_BUFFER_DATA (buf), 7200);
736 533
737 gst_tag_list_remove_tag (tags, GST_TAG_CODEC); 534 if (size > 0 && push) {
738 gst_tag_list_remove_tag (tags, GST_TAG_AUDIO_CODEC); 535 GST_BUFFER_SIZE (buf) = size;
739 event = gst_event_new_tag (tags); 536 GST_DEBUG_OBJECT (lame, "pushing final packet of %u bytes", size);
740 537 result = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (lame), buf, -1);
741 ret = gst_pad_push_event (lame->srcpad, event); 538 } else {
742 break; 539 GST_DEBUG_OBJECT (lame, "no final packet (size=%d, push=%d)", size, push);
743 } 540 gst_buffer_unref (buf);
744 default: 541 result = GST_FLOW_OK;
745 ret = gst_pad_event_default (pad, event);
746 break;
747 } 542 }
748 gst_object_unref (lame); 543 return result;
749 return ret; 544}
545
546static void
547gst_lamemp3enc_flush (GstAudioEncoder * enc)
548{
549 gst_lamemp3enc_flush_full (GST_LAMEMP3ENC (enc), FALSE);
750} 550}
751 551
752static GstFlowReturn 552static GstFlowReturn
753gst_lamemp3enc_chain (GstPad * pad, GstBuffer * buf) 553gst_lamemp3enc_handle_frame (GstAudioEncoder * enc, GstBuffer * in_buf)
754{ 554{
755 GstLameMP3Enc *lame; 555 GstLameMP3Enc *lame;
756 guchar *mp3_data; 556 guchar *mp3_data;
757 gint mp3_buffer_size, mp3_size; 557 gint mp3_buffer_size, mp3_size;
758 gint64 duration; 558 GstBuffer *mp3_buf;
759 GstFlowReturn result; 559 GstFlowReturn result;
760 gint num_samples; 560 gint num_samples;
761 guint8 *data; 561 guint8 *data;
762 guint size; 562 guint size;
763 563
764 lame = GST_LAMEMP3ENC (GST_PAD_PARENT (pad)); 564 lame = GST_LAMEMP3ENC (enc);
765 565
766 GST_LOG_OBJECT (lame, "entered chain"); 566 /* squeeze remaining and push */
567 if (G_UNLIKELY (in_buf == NULL))
568 return gst_lamemp3enc_flush_full (lame, TRUE);
767 569
768 if (!lame->setup) 570 data = GST_BUFFER_DATA (in_buf);
769 goto not_setup; 571 size = GST_BUFFER_SIZE (in_buf);
770
771 data = GST_BUFFER_DATA (buf);
772 size = GST_BUFFER_SIZE (buf);
773 572
774 num_samples = size / 2; 573 num_samples = size / 2;
775 574
776 /* allocate space for output */ 575 /* allocate space for output */
777 mp3_buffer_size = 1.25 * num_samples + 7200; 576 mp3_buffer_size = 1.25 * num_samples + 7200;
778 mp3_data = g_malloc (mp3_buffer_size); 577 mp3_buf = gst_buffer_new_and_alloc (mp3_buffer_size);
578 mp3_data = GST_BUFFER_DATA (mp3_buf);
779 579
780 /* lame seems to be too stupid to get mono interleaved going */ 580 /* lame seems to be too stupid to get mono interleaved going */
781 if (lame->num_channels == 1) { 581 if (lame->num_channels == 1) {
@@ -791,75 +591,26 @@ gst_lamemp3enc_chain (GstPad * pad, GstBuffer * buf)
791 GST_LOG_OBJECT (lame, "encoded %d bytes of audio to %d bytes of mp3", 591 GST_LOG_OBJECT (lame, "encoded %d bytes of audio to %d bytes of mp3",
792 size, mp3_size); 592 size, mp3_size);
793 593
794 duration = gst_util_uint64_scale_int (size, GST_SECOND, 594 if (G_LIKELY (mp3_size > 0)) {
795 2 * lame->samplerate * lame->num_channels); 595 GST_BUFFER_SIZE (mp3_buf) = mp3_size;
796 596 result = gst_audio_encoder_finish_frame (enc, mp3_buf, -1);
797 if (GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE &&
798 GST_BUFFER_DURATION (buf) != duration) {
799 GST_DEBUG_OBJECT (lame, "incoming buffer had incorrect duration %"
800 GST_TIME_FORMAT ", outgoing buffer will have correct duration %"
801 GST_TIME_FORMAT,
802 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_TIME_ARGS (duration));
803 }
804
805 if (lame->last_ts == GST_CLOCK_TIME_NONE) {
806 lame->last_ts = GST_BUFFER_TIMESTAMP (buf);
807 lame->last_offs = GST_BUFFER_OFFSET (buf);
808 lame->last_duration = duration;
809 } else { 597 } else {
810 lame->last_duration += duration; 598 if (mp3_size < 0) {
811 } 599 /* eat error ? */
812 600 g_warning ("error %d", mp3_size);
813 gst_buffer_unref (buf);
814
815 if (mp3_size < 0) {
816 g_warning ("error %d", mp3_size);
817 }
818
819 if (mp3_size > 0) {
820 GstBuffer *outbuf;
821
822 outbuf = gst_buffer_new ();
823 GST_BUFFER_DATA (outbuf) = mp3_data;
824 GST_BUFFER_MALLOCDATA (outbuf) = mp3_data;
825 GST_BUFFER_SIZE (outbuf) = mp3_size;
826 GST_BUFFER_TIMESTAMP (outbuf) = lame->last_ts;
827 GST_BUFFER_OFFSET (outbuf) = lame->last_offs;
828 GST_BUFFER_DURATION (outbuf) = lame->last_duration;
829 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (lame->srcpad));
830
831 result = gst_pad_push (lame->srcpad, outbuf);
832 lame->last_flow = result;
833 if (result != GST_FLOW_OK) {
834 GST_DEBUG_OBJECT (lame, "flow return: %s", gst_flow_get_name (result));
835 } 601 }
836
837 if (GST_CLOCK_TIME_IS_VALID (lame->last_ts))
838 lame->eos_ts = lame->last_ts + lame->last_duration;
839 else
840 lame->eos_ts = GST_CLOCK_TIME_NONE;
841 lame->last_ts = GST_CLOCK_TIME_NONE;
842 } else {
843 g_free (mp3_data);
844 result = GST_FLOW_OK; 602 result = GST_FLOW_OK;
603 gst_buffer_unref (mp3_buf);
845 } 604 }
846 605
847 return result; 606 return result;
848
849 /* ERRORS */
850not_setup:
851 {
852 gst_buffer_unref (buf);
853 GST_ELEMENT_ERROR (lame, CORE, NEGOTIATION, (NULL),
854 ("encoder not initialized (input is not audio?)"));
855 return GST_FLOW_ERROR;
856 }
857} 607}
858 608
859/* set up the encoder state */ 609/* set up the encoder state */
860static gboolean 610static gboolean
861gst_lamemp3enc_setup (GstLameMP3Enc * lame, GstTagList ** tags) 611gst_lamemp3enc_setup (GstLameMP3Enc * lame, GstTagList ** tags)
862{ 612{
613 gboolean res;
863 614
864#define CHECK_ERROR(command) G_STMT_START {\ 615#define CHECK_ERROR(command) G_STMT_START {\
865 if ((command) < 0) { \ 616 if ((command) < 0) { \
@@ -877,14 +628,6 @@ gst_lamemp3enc_setup (GstLameMP3Enc * lame, GstTagList ** tags)
877 628
878 GST_DEBUG_OBJECT (lame, "starting setup"); 629 GST_DEBUG_OBJECT (lame, "starting setup");
879 630
880 /* check if we're already setup; if we are, we might want to check
881 * if this initialization is compatible with the previous one */
882 /* FIXME: do this */
883 if (lame->setup) {
884 GST_WARNING_OBJECT (lame, "already setup");
885 lame->setup = FALSE;
886 }
887
888 lame->lgf = lame_init (); 631 lame->lgf = lame_init ();
889 632
890 if (lame->lgf == NULL) 633 if (lame->lgf == NULL)
@@ -892,15 +635,11 @@ gst_lamemp3enc_setup (GstLameMP3Enc * lame, GstTagList ** tags)
892 635
893 *tags = gst_tag_list_new (); 636 *tags = gst_tag_list_new ();
894 637
895 /* post latency message on the bus */
896 gst_element_post_message (GST_ELEMENT (lame),
897 gst_message_new_latency (GST_OBJECT (lame)));
898
899 /* copy the parameters over */ 638 /* copy the parameters over */
900 lame_set_in_samplerate (lame->lgf, lame->samplerate); 639 lame_set_in_samplerate (lame->lgf, lame->samplerate);
901 640
902 /* let lame choose default samplerate unless outgoing sample rate is fixed */ 641 /* let lame choose default samplerate unless outgoing sample rate is fixed */
903 allowed_caps = gst_pad_get_allowed_caps (lame->srcpad); 642 allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (lame));
904 643
905 if (allowed_caps != NULL) { 644 if (allowed_caps != NULL) {
906 GstStructure *structure; 645 GstStructure *structure;
@@ -954,53 +693,22 @@ gst_lamemp3enc_setup (GstLameMP3Enc * lame, GstTagList ** tags)
954 693
955 /* initialize the lame encoder */ 694 /* initialize the lame encoder */
956 if ((retval = lame_init_params (lame->lgf)) >= 0) { 695 if ((retval = lame_init_params (lame->lgf)) >= 0) {
957 lame->setup = TRUE;
958 /* FIXME: it would be nice to print out the mode here */ 696 /* FIXME: it would be nice to print out the mode here */
959 GST_INFO 697 GST_INFO
960 ("lame encoder setup (target %s, quality %f, bitrate %d, %d Hz, %d channels)", 698 ("lame encoder setup (target %s, quality %f, bitrate %d, %d Hz, %d channels)",
961 (lame->target == LAMEMP3ENC_TARGET_QUALITY) ? "quality" : "bitrate", 699 (lame->target == LAMEMP3ENC_TARGET_QUALITY) ? "quality" : "bitrate",
962 lame->quality, lame->bitrate, lame->samplerate, lame->num_channels); 700 lame->quality, lame->bitrate, lame->samplerate, lame->num_channels);
701 res = TRUE;
963 } else { 702 } else {
964 GST_ERROR_OBJECT (lame, "lame_init_params returned %d", retval); 703 GST_ERROR_OBJECT (lame, "lame_init_params returned %d", retval);
704 res = FALSE;
965 } 705 }
966 706
967 GST_DEBUG_OBJECT (lame, "done with setup"); 707 GST_DEBUG_OBJECT (lame, "done with setup");
968 708 return res;
969 return lame->setup;
970#undef CHECK_ERROR 709#undef CHECK_ERROR
971} 710}
972 711
973static GstStateChangeReturn
974gst_lamemp3enc_change_state (GstElement * element, GstStateChange transition)
975{
976 GstLameMP3Enc *lame;
977 GstStateChangeReturn result;
978
979 lame = GST_LAMEMP3ENC (element);
980
981 switch (transition) {
982 case GST_STATE_CHANGE_READY_TO_PAUSED:
983 lame->last_flow = GST_FLOW_OK;
984 lame->last_ts = GST_CLOCK_TIME_NONE;
985 lame->eos_ts = GST_CLOCK_TIME_NONE;
986 break;
987 default:
988 break;
989 }
990
991 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
992
993 switch (transition) {
994 case GST_STATE_CHANGE_READY_TO_NULL:
995 gst_lamemp3enc_release_memory (lame);
996 break;
997 default:
998 break;
999 }
1000
1001 return result;
1002}
1003
1004gboolean 712gboolean
1005gst_lamemp3enc_register (GstPlugin * plugin) 713gst_lamemp3enc_register (GstPlugin * plugin)
1006{ 714{
diff --git a/ext/lame/gstlamemp3enc.h b/ext/lame/gstlamemp3enc.h
index 2ee83489..9bf12254 100644
--- a/ext/lame/gstlamemp3enc.h
+++ b/ext/lame/gstlamemp3enc.h
@@ -24,6 +24,7 @@
24 24
25 25
26#include <gst/gst.h> 26#include <gst/gst.h>
27#include <gst/audio/gstaudioencoder.h>
27 28
28G_BEGIN_DECLS 29G_BEGIN_DECLS
29 30
@@ -49,37 +50,25 @@ typedef struct _GstLameMP3EncClass GstLameMP3EncClass;
49 * Opaque data structure. 50 * Opaque data structure.
50 */ 51 */
51struct _GstLameMP3Enc { 52struct _GstLameMP3Enc {
52 GstElement element; 53 GstAudioEncoder element;
53 54
54 /*< private >*/ 55 /*< private >*/
55 GstPad *srcpad, *sinkpad;
56
57 gint samplerate; 56 gint samplerate;
58 gint num_channels; 57 gint num_channels;
59 gboolean setup;
60 58
59 /* properties */
61 gint target; 60 gint target;
62
63 gint bitrate; 61 gint bitrate;
64 gboolean cbr; 62 gboolean cbr;
65
66 gfloat quality; 63 gfloat quality;
67
68 gint encoding_engine_quality; 64 gint encoding_engine_quality;
69
70 gboolean mono; 65 gboolean mono;
71 66
72 /* track this so we don't send a last buffer in eos handler after error */
73 GstFlowReturn last_flow;
74
75 lame_global_flags *lgf; 67 lame_global_flags *lgf;
76
77 /* time tracker */
78 guint64 last_ts, last_offs, last_duration, eos_ts;
79}; 68};
80 69
81struct _GstLameMP3EncClass { 70struct _GstLameMP3EncClass {
82 GstElementClass parent_class; 71 GstAudioEncoderClass parent_class;
83}; 72};
84 73
85GType gst_lamemp3enc_get_type(void); 74GType gst_lamemp3enc_get_type(void);