static GstStateChangeReturn gst_wavenc_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstWavEnc *wavenc = GST_WAVENC (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: wavenc->channels = 0; wavenc->depth = 0; wavenc->width = 0; wavenc->rate = 0; wavenc->length = 0; wavenc->sent_header = FALSE; break; default: break; } ret = parent_class->change_state (element, transition); if (ret != GST_STATE_CHANGE_SUCCESS) return ret; return ret; }
static GstStateChangeReturn gst_wavenc_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstWavEnc *wavenc = GST_WAVENC (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: wavenc->format = 0; wavenc->channels = 0; wavenc->width = 0; wavenc->rate = 0; /* use bogus size initially, we'll write the real * header when we get EOS and know the exact length */ wavenc->audio_length = 0x7FFF0000; wavenc->meta_length = 0; wavenc->sent_header = FALSE; /* its true because we haven't writen anything */ wavenc->finished_properly = TRUE; break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); if (ret != GST_STATE_CHANGE_SUCCESS) return ret; switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: if (!wavenc->finished_properly) { GST_ELEMENT_WARNING (wavenc, STREAM, MUX, ("Wav stream not finished properly"), ("Wav stream not finished properly, no EOS received " "before shutdown")); } break; case GST_STATE_CHANGE_READY_TO_NULL: GST_DEBUG_OBJECT (wavenc, "tags: %p", wavenc->tags); if (wavenc->tags) { gst_tag_list_unref (wavenc->tags); wavenc->tags = NULL; } GST_DEBUG_OBJECT (wavenc, "toc: %p", wavenc->toc); if (wavenc->toc) { gst_toc_unref (wavenc->toc); wavenc->toc = NULL; } gst_tag_setter_reset_tags (GST_TAG_SETTER (wavenc)); gst_toc_setter_reset (GST_TOC_SETTER (wavenc)); break; default: break; } return ret; }
static GstFlowReturn gst_wavenc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstWavEnc *wavenc = GST_WAVENC (parent); GstFlowReturn flow = GST_FLOW_OK; if (wavenc->channels <= 0) { GST_ERROR_OBJECT (wavenc, "Got data without caps"); return GST_FLOW_NOT_NEGOTIATED; } if (G_UNLIKELY (!wavenc->sent_header)) { gst_pad_set_caps (wavenc->srcpad, gst_static_pad_template_get_caps (&src_factory)); /* starting a file, means we have to finish it properly */ wavenc->finished_properly = FALSE; /* push initial bogus header, it will be updated on EOS */ flow = gst_wavenc_push_header (wavenc); if (flow != GST_FLOW_OK) { GST_WARNING_OBJECT (wavenc, "error pushing header: %s", gst_flow_get_name (flow)); return flow; } GST_DEBUG_OBJECT (wavenc, "wrote dummy header"); wavenc->audio_length = 0; wavenc->sent_header = TRUE; } GST_LOG_OBJECT (wavenc, "pushing %" G_GSIZE_FORMAT " bytes raw audio, ts=%" GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); buf = gst_buffer_make_writable (buf); GST_BUFFER_OFFSET (buf) = WAV_HEADER_LEN + wavenc->audio_length; GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE; wavenc->audio_length += gst_buffer_get_size (buf); flow = gst_pad_push (wavenc->srcpad, buf); return flow; }
static gboolean gst_wavenc_event (GstPad * pad, GstEvent * event) { gboolean res = TRUE; GstWavEnc *wavenc; wavenc = GST_WAVENC (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS:{ GST_DEBUG_OBJECT (wavenc, "got EOS"); #if 0 /* Write our metadata if we have any */ if (wavenc->metadata) { write_metadata (wavenc); write_cues (wavenc); write_labels (wavenc); } #endif /* write header with correct length values */ gst_wavenc_push_header (wavenc, wavenc->length); /* we're done with this file */ wavenc->finished_properly = TRUE; /* and forward the EOS event */ res = gst_pad_event_default (pad, event); break; } case GST_EVENT_NEWSEGMENT: /* Just drop it, it's probably in TIME format * anyway. We'll send our own newsegment event */ gst_event_unref (event); break; default: res = gst_pad_event_default (pad, event); break; } gst_object_unref (wavenc); return res; }
static GstStateChangeReturn gst_wavenc_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstWavEnc *wavenc = GST_WAVENC (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: wavenc->format = 0; wavenc->channels = 0; wavenc->width = 0; wavenc->rate = 0; wavenc->length = 0; wavenc->sent_header = FALSE; /* its true because we haven't writen anything */ wavenc->finished_properly = TRUE; break; default: break; } ret = parent_class->change_state (element, transition); if (ret != GST_STATE_CHANGE_SUCCESS) return ret; switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: if (!wavenc->finished_properly) { GST_ELEMENT_WARNING (wavenc, STREAM, MUX, ("Wav stream not finished properly"), ("Wav stream not finished properly, no EOS received " "before shutdown")); } break; default: break; } return ret; }
static GstFlowReturn gst_wavenc_chain (GstPad * pad, GstBuffer * buf) { GstWavEnc *wavenc = GST_WAVENC (GST_PAD_PARENT (pad)); GstFlowReturn flow = GST_FLOW_OK; g_return_val_if_fail (wavenc->channels > 0, GST_FLOW_WRONG_STATE); if (!wavenc->sent_header) { /* use bogus size initially, we'll write the real * header when we get EOS and know the exact length */ flow = gst_wavenc_push_header (wavenc, 0x7FFF0000); if (flow != GST_FLOW_OK) return flow; GST_DEBUG_OBJECT (wavenc, "wrote dummy header"); wavenc->sent_header = TRUE; } wavenc->length += GST_BUFFER_SIZE (buf); GST_LOG_OBJECT (wavenc, "pushing %u bytes raw audio, ts=%" GST_TIME_FORMAT, GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); if (wavenc->width != wavenc->depth) { buf = gst_buffer_make_writable (buf); gst_wavenc_format_samples (buf, wavenc->width, wavenc->depth); } else { buf = gst_buffer_make_metadata_writable (buf); } gst_buffer_set_caps (buf, GST_PAD_CAPS (wavenc->srcpad)); GST_BUFFER_OFFSET (buf) = WAV_HEADER_LEN + wavenc->length; GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE; flow = gst_pad_push (wavenc->srcpad, buf); return flow; }
static gboolean gst_wavenc_sink_setcaps (GstPad * pad, GstCaps * caps) { GstWavEnc *wavenc; GstStructure *structure; gint chans, rate, width, depth; wavenc = GST_WAVENC (gst_pad_get_parent (pad)); if (wavenc->sent_header) { GST_WARNING_OBJECT (wavenc, "cannot change format in middle of stream"); goto fail; } GST_DEBUG_OBJECT (wavenc, "got caps: %" GST_PTR_FORMAT, caps); structure = gst_caps_get_structure (caps, 0); if (!gst_structure_get_int (structure, "channels", &chans) || !gst_structure_get_int (structure, "rate", &rate) || !gst_structure_get_int (structure, "width", &width) || !gst_structure_get_int (structure, "depth", &depth)) { GST_WARNING_OBJECT (wavenc, "caps incomplete"); goto fail; } wavenc->channels = chans; wavenc->depth = depth; wavenc->width = width; wavenc->rate = rate; GST_LOG_OBJECT (wavenc, "accepted caps: chans=%u width=%u depth=%u rate=%u", wavenc->channels, wavenc->width, wavenc->depth, wavenc->rate); gst_object_unref (wavenc); return TRUE; fail: gst_object_unref (wavenc); return FALSE; }
static GstFlowReturn gst_wavenc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstWavEnc *wavenc = GST_WAVENC (parent); GstFlowReturn flow = GST_FLOW_OK; g_return_val_if_fail (wavenc->channels > 0, GST_FLOW_FLUSHING); if (G_UNLIKELY (!wavenc->sent_header)) { /* starting a file, means we have to finish it properly */ wavenc->finished_properly = FALSE; /* use bogus size initially, we'll write the real * header when we get EOS and know the exact length */ flow = gst_wavenc_push_header (wavenc); if (flow != GST_FLOW_OK) { GST_WARNING_OBJECT (wavenc, "error pushing header: %s", gst_flow_get_name (flow)); return flow; } GST_DEBUG_OBJECT (wavenc, "wrote dummy header"); wavenc->sent_header = TRUE; } GST_LOG_OBJECT (wavenc, "pushing %" G_GSIZE_FORMAT " bytes raw audio, ts=%" GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); buf = gst_buffer_make_writable (buf); GST_BUFFER_OFFSET (buf) = WAV_HEADER_LEN + wavenc->audio_length; GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE; wavenc->audio_length += gst_buffer_get_size (buf); flow = gst_pad_push (wavenc->srcpad, buf); return flow; }
static gboolean gst_wavenc_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean res = TRUE; GstWavEnc *wavenc; GstTagList *tags; GstToc *toc; wavenc = GST_WAVENC (parent); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; gst_event_parse_caps (event, &caps); gst_wavenc_sink_setcaps (pad, caps); /* have our own src caps */ gst_event_unref (event); break; } case GST_EVENT_EOS: { GstFlowReturn flow; GST_DEBUG_OBJECT (wavenc, "got EOS"); flow = gst_wavenc_write_toc (wavenc); if (flow != GST_FLOW_OK) { GST_WARNING_OBJECT (wavenc, "error pushing toc: %s", gst_flow_get_name (flow)); } flow = gst_wavenc_write_tags (wavenc); if (flow != GST_FLOW_OK) { GST_WARNING_OBJECT (wavenc, "error pushing tags: %s", gst_flow_get_name (flow)); } /* write header with correct length values */ gst_wavenc_push_header (wavenc); /* we're done with this file */ wavenc->finished_properly = TRUE; /* and forward the EOS event */ res = gst_pad_event_default (pad, parent, event); break; } case GST_EVENT_SEGMENT: /* Just drop it, it's probably in TIME format * anyway. We'll send our own newsegment event */ gst_event_unref (event); break; case GST_EVENT_TOC: gst_event_parse_toc (event, &toc, NULL); if (toc) { if (wavenc->toc != toc) { if (wavenc->toc) gst_toc_unref (wavenc->toc); wavenc->toc = toc; } else { gst_toc_unref (toc); } } res = gst_pad_event_default (pad, parent, event); break; case GST_EVENT_TAG: gst_event_parse_tag (event, &tags); if (tags) { if (wavenc->tags != tags) { if (wavenc->tags) gst_tag_list_unref (wavenc->tags); wavenc->tags = gst_tag_list_ref (tags); } } res = gst_pad_event_default (pad, parent, event); break; default: res = gst_pad_event_default (pad, parent, event); break; } return res; }
static gboolean gst_wavenc_sink_setcaps (GstPad * pad, GstCaps * caps) { GstWavEnc *wavenc; GstStructure *structure; const gchar *name; gint chans, rate; GstCaps *ccaps; wavenc = GST_WAVENC (gst_pad_get_parent (pad)); ccaps = gst_pad_get_current_caps (pad); if (wavenc->sent_header && ccaps && !gst_caps_can_intersect (caps, ccaps)) { gst_caps_unref (ccaps); GST_WARNING_OBJECT (wavenc, "cannot change format in middle of stream"); goto fail; } if (ccaps) gst_caps_unref (ccaps); GST_DEBUG_OBJECT (wavenc, "got caps: %" GST_PTR_FORMAT, caps); structure = gst_caps_get_structure (caps, 0); name = gst_structure_get_name (structure); if (!gst_structure_get_int (structure, "channels", &chans) || !gst_structure_get_int (structure, "rate", &rate)) { GST_WARNING_OBJECT (wavenc, "caps incomplete"); goto fail; } if (strcmp (name, "audio/x-raw") == 0) { GstAudioInfo info; if (!gst_audio_info_from_caps (&info, caps)) goto fail; if (GST_AUDIO_INFO_IS_INTEGER (&info)) wavenc->format = GST_RIFF_WAVE_FORMAT_PCM; else if (GST_AUDIO_INFO_IS_FLOAT (&info)) wavenc->format = GST_RIFF_WAVE_FORMAT_IEEE_FLOAT; else goto fail; wavenc->width = GST_AUDIO_INFO_WIDTH (&info); } else if (strcmp (name, "audio/x-alaw") == 0) { wavenc->format = GST_RIFF_WAVE_FORMAT_ALAW; wavenc->width = 8; } else if (strcmp (name, "audio/x-mulaw") == 0) { wavenc->format = GST_RIFF_WAVE_FORMAT_MULAW; wavenc->width = 8; } else { GST_WARNING_OBJECT (wavenc, "Unsupported format %s", name); goto fail; } wavenc->channels = chans; wavenc->rate = rate; GST_LOG_OBJECT (wavenc, "accepted caps: format=0x%04x chans=%u width=%u rate=%u", wavenc->format, wavenc->channels, wavenc->width, wavenc->rate); gst_object_unref (wavenc); return TRUE; fail: gst_object_unref (wavenc); return FALSE; }
static gboolean gst_wavenc_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean res = TRUE; GstWavEnc *wavenc; GstToc *toc; wavenc = GST_WAVENC (parent); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; gst_event_parse_caps (event, &caps); gst_wavenc_sink_setcaps (pad, caps); /* have our own src caps */ gst_event_unref (event); break; } case GST_EVENT_EOS:{ GST_DEBUG_OBJECT (wavenc, "got EOS"); if (!wavenc->toc) { GST_DEBUG_OBJECT (wavenc, "have no toc, checking toc_setter"); wavenc->toc = gst_toc_setter_get_toc (GST_TOC_SETTER (wavenc)); } if (wavenc->toc) { GST_DEBUG_OBJECT (wavenc, "have toc"); gst_wavenc_write_toc (wavenc); } #if 0 /* Write our metadata if we have any */ if (wavenc->metadata) { write_metadata (wavenc); write_cues (wavenc); write_labels (wavenc); } #endif /* write header with correct length values */ gst_wavenc_push_header (wavenc, wavenc->length); /* we're done with this file */ wavenc->finished_properly = TRUE; /* and forward the EOS event */ res = gst_pad_event_default (pad, parent, event); break; } case GST_EVENT_SEGMENT: /* Just drop it, it's probably in TIME format * anyway. We'll send our own newsegment event */ gst_event_unref (event); break; case GST_EVENT_TOC: gst_event_parse_toc (event, &toc, NULL); if (toc) { if (wavenc->toc != toc) { if (wavenc->toc) gst_toc_unref (wavenc->toc); wavenc->toc = toc; } else { gst_toc_unref (toc); } } res = gst_pad_event_default (pad, parent, event); break; default: res = gst_pad_event_default (pad, parent, event); break; } return res; }
static gboolean gst_wavenc_sink_setcaps (GstPad * pad, GstCaps * caps) { GstWavEnc *wavenc; GstStructure *structure; const gchar *name; gint chans, rate, width; wavenc = GST_WAVENC (gst_pad_get_parent (pad)); if (wavenc->sent_header && !gst_caps_can_intersect (caps, GST_PAD_CAPS (pad))) { GST_WARNING_OBJECT (wavenc, "cannot change format in middle of stream"); goto fail; } GST_DEBUG_OBJECT (wavenc, "got caps: %" GST_PTR_FORMAT, caps); structure = gst_caps_get_structure (caps, 0); name = gst_structure_get_name (structure); if (!gst_structure_get_int (structure, "channels", &chans) || !gst_structure_get_int (structure, "rate", &rate)) { GST_WARNING_OBJECT (wavenc, "caps incomplete"); goto fail; } if (strcmp (name, "audio/x-raw-int") == 0) { if (!gst_structure_get_int (structure, "width", &width)) { GST_WARNING_OBJECT (wavenc, "caps incomplete"); goto fail; } wavenc->format = GST_RIFF_WAVE_FORMAT_PCM; wavenc->width = width; } else if (strcmp (name, "audio/x-raw-float") == 0) { if (!gst_structure_get_int (structure, "width", &width)) { GST_WARNING_OBJECT (wavenc, "caps incomplete"); goto fail; } wavenc->format = GST_RIFF_WAVE_FORMAT_IEEE_FLOAT; wavenc->width = width; } else if (strcmp (name, "audio/x-alaw") == 0) { wavenc->format = GST_RIFF_WAVE_FORMAT_ALAW; wavenc->width = 8; } else if (strcmp (name, "audio/x-mulaw") == 0) { wavenc->format = GST_RIFF_WAVE_FORMAT_MULAW; wavenc->width = 8; } else { GST_WARNING_OBJECT (wavenc, "Unsupported format %s", name); goto fail; } wavenc->channels = chans; wavenc->rate = rate; GST_LOG_OBJECT (wavenc, "accepted caps: format=0x%04x chans=%u width=%u rate=%u", wavenc->format, wavenc->channels, wavenc->width, wavenc->rate); gst_object_unref (wavenc); return TRUE; fail: gst_object_unref (wavenc); return FALSE; }