static void gst_two_lame_finalize (GObject * obj) { gst_two_lame_release_memory (GST_TWO_LAME (obj)); G_OBJECT_CLASS (parent_class)->finalize (obj); }
static GstStateChangeReturn gst_two_lame_change_state (GstElement * element, GstStateChange transition) { GstTwoLame *twolame; GstStateChangeReturn result; twolame = GST_TWO_LAME (element); switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: twolame->last_flow = GST_FLOW_OK; twolame->last_ts = GST_CLOCK_TIME_NONE; twolame->eos_ts = GST_CLOCK_TIME_NONE; break; default: break; } result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_READY_TO_NULL: gst_two_lame_release_memory (twolame); break; default: break; } return result; }
static gboolean gst_two_lame_start (GstAudioEncoder * enc) { GstTwoLame *twolame = GST_TWO_LAME (enc); GST_DEBUG_OBJECT (twolame, "start"); return TRUE; }
static void gst_two_lame_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstTwoLame *twolame = GST_TWO_LAME (object); switch (prop_id) { case ARG_MODE: g_value_set_enum (value, twolame->mode); break; case ARG_PSYMODEL: g_value_set_int (value, twolame->psymodel); break; case ARG_BITRATE: g_value_set_int (value, twolame->bitrate); break; case ARG_PADDING: g_value_set_enum (value, twolame->padding); break; case ARG_ENERGY_LEVEL_EXTENSION: g_value_set_boolean (value, twolame->energy_level_extension); break; case ARG_EMPHASIS: g_value_set_enum (value, twolame->emphasis); break; case ARG_ERROR_PROTECTION: g_value_set_boolean (value, twolame->error_protection); break; case ARG_COPYRIGHT: g_value_set_boolean (value, twolame->copyright); break; case ARG_ORIGINAL: g_value_set_boolean (value, twolame->original); break; case ARG_VBR: g_value_set_boolean (value, twolame->vbr); break; case ARG_VBR_LEVEL: g_value_set_float (value, twolame->vbr_level); break; case ARG_ATH_LEVEL: g_value_set_float (value, twolame->ath_level); break; case ARG_VBR_MAX_BITRATE: g_value_set_int (value, twolame->vbr_max_bitrate); break; case ARG_QUICK_MODE: g_value_set_boolean (value, twolame->quick_mode); break; case ARG_QUICK_MODE_COUNT: g_value_set_int (value, twolame->quick_mode_count); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean gst_two_lame_stop (GstAudioEncoder * enc) { GstTwoLame *twolame = GST_TWO_LAME (enc); GST_DEBUG_OBJECT (twolame, "stop"); gst_two_lame_release_memory (twolame); return TRUE; }
static GstFlowReturn gst_two_lame_chain (GstPad * pad, GstBuffer * buf) { GstTwoLame *twolame; guchar *mp3_data; gint mp3_buffer_size, mp3_size; gint64 duration; GstFlowReturn result; gint num_samples; guint8 *data; guint size; twolame = GST_TWO_LAME (GST_PAD_PARENT (pad)); GST_LOG_OBJECT (twolame, "entered chain"); if (!twolame->setup) goto not_setup; data = GST_BUFFER_DATA (buf); size = GST_BUFFER_SIZE (buf); if (twolame->float_input) num_samples = size / 4; else num_samples = size / 2; /* allocate space for output */ mp3_buffer_size = 1.25 * num_samples + 16384; mp3_data = g_malloc (mp3_buffer_size); if (twolame->num_channels == 1) { if (twolame->float_input) mp3_size = twolame_encode_buffer_float32 (twolame->glopts, (float *) data, (float *) data, num_samples, mp3_data, mp3_buffer_size); else mp3_size = twolame_encode_buffer (twolame->glopts, (short int *) data, (short int *) data, num_samples, mp3_data, mp3_buffer_size); } else { if (twolame->float_input) mp3_size = twolame_encode_buffer_float32_interleaved (twolame->glopts, (float *) data, num_samples / twolame->num_channels, mp3_data, mp3_buffer_size); else mp3_size = twolame_encode_buffer_interleaved (twolame->glopts, (short int *) data, num_samples / twolame->num_channels, mp3_data, mp3_buffer_size); } GST_LOG_OBJECT (twolame, "encoded %d bytes of audio to %d bytes of mp3", size, mp3_size); if (twolame->float_input) duration = gst_util_uint64_scale_int (size, GST_SECOND, 4 * twolame->samplerate * twolame->num_channels); else duration = gst_util_uint64_scale_int (size, GST_SECOND, 2 * twolame->samplerate * twolame->num_channels); if (GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE && GST_BUFFER_DURATION (buf) != duration) { GST_DEBUG_OBJECT (twolame, "incoming buffer had incorrect duration %" GST_TIME_FORMAT ", outgoing buffer will have correct duration %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_TIME_ARGS (duration)); } if (twolame->last_ts == GST_CLOCK_TIME_NONE) { twolame->last_ts = GST_BUFFER_TIMESTAMP (buf); twolame->last_offs = GST_BUFFER_OFFSET (buf); twolame->last_duration = duration; } else { twolame->last_duration += duration; } gst_buffer_unref (buf); if (mp3_size < 0) { g_warning ("error %d", mp3_size); } if (mp3_size > 0) { GstBuffer *outbuf; outbuf = gst_buffer_new (); GST_BUFFER_DATA (outbuf) = mp3_data; GST_BUFFER_MALLOCDATA (outbuf) = mp3_data; GST_BUFFER_SIZE (outbuf) = mp3_size; GST_BUFFER_TIMESTAMP (outbuf) = twolame->last_ts; GST_BUFFER_OFFSET (outbuf) = twolame->last_offs; GST_BUFFER_DURATION (outbuf) = twolame->last_duration; gst_buffer_set_caps (outbuf, GST_PAD_CAPS (twolame->srcpad)); result = gst_pad_push (twolame->srcpad, outbuf); twolame->last_flow = result; if (result != GST_FLOW_OK) { GST_DEBUG_OBJECT (twolame, "flow return: %s", gst_flow_get_name (result)); } if (GST_CLOCK_TIME_IS_VALID (twolame->last_ts)) twolame->eos_ts = twolame->last_ts + twolame->last_duration; else twolame->eos_ts = GST_CLOCK_TIME_NONE; twolame->last_ts = GST_CLOCK_TIME_NONE; } else { g_free (mp3_data); result = GST_FLOW_OK; } return result; /* ERRORS */ not_setup: { gst_buffer_unref (buf); GST_ELEMENT_ERROR (twolame, CORE, NEGOTIATION, (NULL), ("encoder not initialized (input is not audio?)")); return GST_FLOW_ERROR; } }
static gboolean gst_two_lame_sink_event (GstPad * pad, GstEvent * event) { gboolean ret; GstTwoLame *twolame; twolame = GST_TWO_LAME (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: { GST_DEBUG_OBJECT (twolame, "handling EOS event"); if (twolame->glopts != NULL) { GstBuffer *buf; gint size; buf = gst_buffer_new_and_alloc (16384); size = twolame_encode_flush (twolame->glopts, GST_BUFFER_DATA (buf), 16394); if (size > 0 && twolame->last_flow == GST_FLOW_OK) { gint64 duration; duration = gst_util_uint64_scale (size, 8 * GST_SECOND, 1000 * twolame->bitrate); if (twolame->last_ts == GST_CLOCK_TIME_NONE) { twolame->last_ts = twolame->eos_ts; twolame->last_duration = duration; } else { twolame->last_duration += duration; } GST_BUFFER_TIMESTAMP (buf) = twolame->last_ts; GST_BUFFER_DURATION (buf) = twolame->last_duration; twolame->last_ts = GST_CLOCK_TIME_NONE; GST_BUFFER_SIZE (buf) = size; GST_DEBUG_OBJECT (twolame, "pushing final packet of %u bytes", size); gst_buffer_set_caps (buf, GST_PAD_CAPS (twolame->srcpad)); gst_pad_push (twolame->srcpad, buf); } else { GST_DEBUG_OBJECT (twolame, "no final packet (size=%d, last_flow=%s)", size, gst_flow_get_name (twolame->last_flow)); gst_buffer_unref (buf); } } ret = gst_pad_event_default (pad, event); break; } case GST_EVENT_FLUSH_START: GST_DEBUG_OBJECT (twolame, "handling FLUSH start event"); /* forward event */ ret = gst_pad_push_event (twolame->srcpad, event); break; case GST_EVENT_FLUSH_STOP: { guchar *mp3_data = NULL; gint mp3_buffer_size; GST_DEBUG_OBJECT (twolame, "handling FLUSH stop event"); /* clear buffers */ mp3_buffer_size = 16384; mp3_data = g_malloc (mp3_buffer_size); twolame_encode_flush (twolame->glopts, mp3_data, mp3_buffer_size); ret = gst_pad_push_event (twolame->srcpad, event); g_free (mp3_data); break; } default: ret = gst_pad_event_default (pad, event); break; } gst_object_unref (twolame); return ret; }
static gboolean gst_two_lame_sink_setcaps (GstPad * pad, GstCaps * caps) { GstTwoLame *twolame; gint out_samplerate; gint version; GstStructure *structure; GstCaps *othercaps; twolame = GST_TWO_LAME (GST_PAD_PARENT (pad)); structure = gst_caps_get_structure (caps, 0); if (strcmp (gst_structure_get_name (structure), "audio/x-raw-int") == 0) twolame->float_input = FALSE; else twolame->float_input = TRUE; if (!gst_structure_get_int (structure, "rate", &twolame->samplerate)) goto no_rate; if (!gst_structure_get_int (structure, "channels", &twolame->num_channels)) goto no_channels; GST_DEBUG_OBJECT (twolame, "setting up twolame"); if (!gst_two_lame_setup (twolame)) goto setup_failed; out_samplerate = twolame_get_out_samplerate (twolame->glopts); if (out_samplerate == 0) goto zero_output_rate; if (out_samplerate != twolame->samplerate) { GST_WARNING_OBJECT (twolame, "output samplerate %d is different from incoming samplerate %d", out_samplerate, twolame->samplerate); } version = twolame_get_version (twolame->glopts); if (version == TWOLAME_MPEG2) version = 2; else version = 1; othercaps = gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1, "mpegaudioversion", G_TYPE_INT, version, "layer", G_TYPE_INT, 2, "channels", G_TYPE_INT, twolame->mode == TWOLAME_MONO ? 1 : twolame->num_channels, "rate", G_TYPE_INT, out_samplerate, NULL); /* and use these caps */ gst_pad_set_caps (twolame->srcpad, othercaps); gst_caps_unref (othercaps); return TRUE; no_rate: { GST_ERROR_OBJECT (twolame, "input caps have no sample rate field"); return FALSE; } no_channels: { GST_ERROR_OBJECT (twolame, "input caps have no channels field"); return FALSE; } zero_output_rate: { GST_ELEMENT_ERROR (twolame, LIBRARY, SETTINGS, (NULL), ("TwoLAME decided on a zero sample rate")); return FALSE; } setup_failed: { GST_ELEMENT_ERROR (twolame, LIBRARY, SETTINGS, (_("Failed to configure TwoLAME encoder. Check your encoding parameters.")), (NULL)); return FALSE; } }
static GstFlowReturn gst_two_lame_handle_frame (GstAudioEncoder * enc, GstBuffer * buf) { GstTwoLame *twolame; gint mp3_buffer_size, mp3_size; GstBuffer *mp3_buf; GstFlowReturn result; gint num_samples; GstMapInfo map, mp3_map; twolame = GST_TWO_LAME (enc); /* squeeze remaining and push */ if (G_UNLIKELY (buf == NULL)) return gst_two_lame_flush_full (twolame, TRUE); gst_buffer_map (buf, &map, GST_MAP_READ); if (twolame->float_input) num_samples = map.size / 4; else num_samples = map.size / 2; /* allocate space for output */ mp3_buffer_size = 1.25 * num_samples + 16384; mp3_buf = gst_buffer_new_and_alloc (mp3_buffer_size); gst_buffer_map (mp3_buf, &mp3_map, GST_MAP_WRITE); if (twolame->num_channels == 1) { if (twolame->float_input) mp3_size = twolame_encode_buffer_float32 (twolame->glopts, (float *) map.data, (float *) map.data, num_samples, mp3_map.data, mp3_buffer_size); else mp3_size = twolame_encode_buffer (twolame->glopts, (short int *) map.data, (short int *) map.data, num_samples, mp3_map.data, mp3_buffer_size); } else { if (twolame->float_input) mp3_size = twolame_encode_buffer_float32_interleaved (twolame->glopts, (float *) map.data, num_samples / twolame->num_channels, mp3_map.data, mp3_buffer_size); else mp3_size = twolame_encode_buffer_interleaved (twolame->glopts, (short int *) map.data, num_samples / twolame->num_channels, mp3_map.data, mp3_buffer_size); } GST_LOG_OBJECT (twolame, "encoded %" G_GSIZE_FORMAT " bytes of audio " "to %d bytes of mp3", map.size, mp3_size); gst_buffer_unmap (buf, &map); gst_buffer_unmap (mp3_buf, &mp3_map); if (mp3_size > 0) { gst_buffer_set_size (mp3_buf, mp3_size); result = gst_audio_encoder_finish_frame (enc, mp3_buf, -1); } else { if (mp3_size < 0) { /* eat error ? */ g_warning ("error %d", mp3_size); } gst_buffer_unref (mp3_buf); result = GST_FLOW_OK; } return result; }
static void gst_two_lame_flush (GstAudioEncoder * enc) { gst_two_lame_flush_full (GST_TWO_LAME (enc), FALSE); }
static gboolean gst_two_lame_set_format (GstAudioEncoder * enc, GstAudioInfo * info) { GstTwoLame *twolame; gint out_samplerate; gint version; GstCaps *othercaps; twolame = GST_TWO_LAME (enc); /* parameters already parsed for us */ twolame->samplerate = GST_AUDIO_INFO_RATE (info); twolame->num_channels = GST_AUDIO_INFO_CHANNELS (info); twolame->float_input = !GST_AUDIO_INFO_IS_INTEGER (info); /* but we might be asked to reconfigure, so reset */ gst_two_lame_release_memory (twolame); GST_DEBUG_OBJECT (twolame, "setting up twolame"); if (!gst_two_lame_setup (twolame)) goto setup_failed; out_samplerate = twolame_get_out_samplerate (twolame->glopts); if (out_samplerate == 0) goto zero_output_rate; if (out_samplerate != twolame->samplerate) { GST_WARNING_OBJECT (twolame, "output samplerate %d is different from incoming samplerate %d", out_samplerate, twolame->samplerate); } version = twolame_get_version (twolame->glopts); if (version == TWOLAME_MPEG2) version = 2; else version = 1; othercaps = gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1, "mpegaudioversion", G_TYPE_INT, version, "layer", G_TYPE_INT, 2, "channels", G_TYPE_INT, twolame->mode == TWOLAME_MONO ? 1 : twolame->num_channels, "rate", G_TYPE_INT, out_samplerate, NULL); /* and use these caps */ gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (twolame), othercaps); gst_caps_unref (othercaps); /* report needs to base class: * hand one frame at a time, if we are pretty sure what a frame is */ if (out_samplerate == twolame->samplerate) { gst_audio_encoder_set_frame_samples_min (enc, 1152); gst_audio_encoder_set_frame_samples_max (enc, 1152); gst_audio_encoder_set_frame_max (enc, 1); } return TRUE; zero_output_rate: { GST_ELEMENT_ERROR (twolame, LIBRARY, SETTINGS, (NULL), ("TwoLAME decided on a zero sample rate")); return FALSE; } setup_failed: { GST_ELEMENT_ERROR (twolame, LIBRARY, SETTINGS, (_("Failed to configure TwoLAME encoder. Check your encoding parameters.")), (NULL)); return FALSE; } }