soundfile_t * soundfile_open_write(const char *path, int n_channels, double sampling_rate) { dp(30, "path=%s n_channels=%d sampling_rate=%g\n", path, n_channels, sampling_rate); soundfile_t *s = salloc(sizeof *s); s->m = sft_write; s->channels = n_channels; s->samplerate = sampling_rate; if (g_regex_match_simple ("\\.wv$", path, 0, 0)) { s->t = sft_wavpack; s->file = fopen(path, "w+b"); if (!s->file) die("can not open output file '%s'", path); WavpackContext *wpc = s->p = WavpackOpenFileOutput(write_block, s, NULL); if (!s->p) die("can not open input file '%s'", path); WavpackConfig config = {0}; config.bytes_per_sample = 2; s->bits_per_sample = config.bits_per_sample = 16; config.channel_mask = n_channels == 1 ? 4 : 3; // Microsoft standard: 4 == mono, 3 == stereo config.num_channels = n_channels; config.sample_rate = sampling_rate; if (!WavpackSetConfiguration(wpc, &config, -1)) die("WavpackSetConfiguration failed: %s\n", WavpackGetErrorMessage(wpc)); if (!WavpackPackInit(wpc)) die("WavpackPackInit failed: %s\n", WavpackGetErrorMessage(wpc)); } else { SF_INFO outfile_info = {0}; outfile_info.samplerate = sampling_rate; outfile_info.channels = n_channels; outfile_info.format = SF_FORMAT_PCM_16; if (g_regex_match_simple ("\\.flac$", path, 0, 0)) outfile_info.format |= SF_FORMAT_FLAC; else outfile_info.format |= SF_FORMAT_WAV; if (strcmp(path, "-")) s->p = sf_open(path, SFM_WRITE, &outfile_info); else s->p = sf_open_fd(1, SFM_WRITE, &outfile_info, 0); // write to stdout if name is "-" if (!s->p) die("can not open output file '%s'", path); s->t = sft_libsndfile; } return s; }
static GstFlowReturn gst_wavpack_enc_chain (GstPad * pad, GstBuffer * buf) { GstWavpackEnc *enc = GST_WAVPACK_ENC (gst_pad_get_parent (pad)); uint32_t sample_count = GST_BUFFER_SIZE (buf) / 4; GstFlowReturn ret; /* reset the last returns to GST_FLOW_OK. This is only set to something else * while WavpackPackSamples() or more specific gst_wavpack_enc_push_block() * so not valid anymore */ enc->srcpad_last_return = enc->wvcsrcpad_last_return = GST_FLOW_OK; GST_DEBUG ("got %u raw samples", sample_count); /* check if we already have a valid WavpackContext, otherwise make one */ if (!enc->wp_context) { /* create raw context */ enc->wp_context = WavpackOpenFileOutput (gst_wavpack_enc_push_block, &enc->wv_id, (enc->correction_mode > 0) ? &enc->wvc_id : NULL); if (!enc->wp_context) { GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL), ("error creating Wavpack context")); gst_object_unref (enc); gst_buffer_unref (buf); return GST_FLOW_ERROR; } /* set the WavpackConfig according to our parameters */ gst_wavpack_enc_set_wp_config (enc); /* set the configuration to the context now that we know everything * and initialize the encoder */ if (!WavpackSetConfiguration (enc->wp_context, enc->wp_config, (uint32_t) (-1)) || !WavpackPackInit (enc->wp_context)) { GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), ("error setting up wavpack encoding context")); WavpackCloseFile (enc->wp_context); gst_object_unref (enc); gst_buffer_unref (buf); return GST_FLOW_ERROR; } GST_DEBUG ("setup of encoding context successfull"); } /* Save the timestamp of the first buffer. This will be later * used as offset for all following buffers */ if (enc->timestamp_offset == GST_CLOCK_TIME_NONE) { if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { enc->timestamp_offset = GST_BUFFER_TIMESTAMP (buf); enc->next_ts = GST_BUFFER_TIMESTAMP (buf); } else { enc->timestamp_offset = 0; enc->next_ts = 0; } } /* Check if we have a continous stream, if not drop some samples or the buffer or * insert some silence samples */ if (enc->next_ts != GST_CLOCK_TIME_NONE && GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) { guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf); guint64 diff_bytes; GST_WARNING_OBJECT (enc, "Buffer is older than previous " "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT "), cannot handle. Clipping buffer.", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (enc->next_ts)); diff_bytes = GST_CLOCK_TIME_TO_FRAMES (diff, enc->samplerate) * enc->channels * 2; if (diff_bytes >= GST_BUFFER_SIZE (buf)) { gst_buffer_unref (buf); return GST_FLOW_OK; } buf = gst_buffer_make_metadata_writable (buf); GST_BUFFER_DATA (buf) += diff_bytes; GST_BUFFER_SIZE (buf) -= diff_bytes; GST_BUFFER_TIMESTAMP (buf) += diff; if (GST_BUFFER_DURATION_IS_VALID (buf)) GST_BUFFER_DURATION (buf) -= diff; } /* Allow a diff of at most 5 ms */ if (enc->next_ts != GST_CLOCK_TIME_NONE && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts && GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > 5 * GST_MSECOND) { GST_WARNING_OBJECT (enc, "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT, GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, 5 * GST_MSECOND); WavpackFlushSamples (enc->wp_context); enc->timestamp_offset += (GST_BUFFER_TIMESTAMP (buf) - enc->next_ts); } } if (GST_BUFFER_TIMESTAMP_IS_VALID (buf) && GST_BUFFER_DURATION_IS_VALID (buf)) enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf); else enc->next_ts = GST_CLOCK_TIME_NONE; if (enc->need_channel_remap) { buf = gst_buffer_make_writable (buf); gst_wavpack_enc_fix_channel_order (enc, (gint32 *) GST_BUFFER_DATA (buf), sample_count); } /* if we want to append the MD5 sum to the stream update it here * with the current raw samples */ if (enc->md5) { g_checksum_update (enc->md5_context, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); } /* encode and handle return values from encoding */ if (WavpackPackSamples (enc->wp_context, (int32_t *) GST_BUFFER_DATA (buf), sample_count / enc->channels)) { GST_DEBUG ("encoding samples successful"); ret = GST_FLOW_OK; } else { if ((enc->srcpad_last_return == GST_FLOW_RESEND) || (enc->wvcsrcpad_last_return == GST_FLOW_RESEND)) { ret = GST_FLOW_RESEND; } else if ((enc->srcpad_last_return == GST_FLOW_OK) || (enc->wvcsrcpad_last_return == GST_FLOW_OK)) { ret = GST_FLOW_OK; } else if ((enc->srcpad_last_return == GST_FLOW_NOT_LINKED) && (enc->wvcsrcpad_last_return == GST_FLOW_NOT_LINKED)) { ret = GST_FLOW_NOT_LINKED; } else if ((enc->srcpad_last_return == GST_FLOW_WRONG_STATE) && (enc->wvcsrcpad_last_return == GST_FLOW_WRONG_STATE)) { ret = GST_FLOW_WRONG_STATE; } else { GST_ELEMENT_ERROR (enc, LIBRARY, ENCODE, (NULL), ("encoding samples failed")); ret = GST_FLOW_ERROR; } } gst_buffer_unref (buf); gst_object_unref (enc); return ret; }
static GstFlowReturn gst_wavpack_enc_chain (GstPad * pad, GstBuffer * buf) { GstWavpackEnc *enc = GST_WAVPACK_ENC (gst_pad_get_parent (pad)); uint32_t sample_count = GST_BUFFER_SIZE (buf) / 4; GstFlowReturn ret; /* reset the last returns to GST_FLOW_OK. This is only set to something else * while WavpackPackSamples() or more specific gst_wavpack_enc_push_block() * so not valid anymore */ enc->srcpad_last_return = enc->wvcsrcpad_last_return = GST_FLOW_OK; GST_DEBUG ("got %u raw samples", sample_count); /* check if we already have a valid WavpackContext, otherwise make one */ if (!enc->wp_context) { /* create raw context */ enc->wp_context = WavpackOpenFileOutput (gst_wavpack_enc_push_block, &enc->wv_id, (enc->correction_mode > 0) ? &enc->wvc_id : NULL); if (!enc->wp_context) { GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL), ("error creating Wavpack context")); gst_object_unref (enc); gst_buffer_unref (buf); return GST_FLOW_ERROR; } /* set the WavpackConfig according to our parameters */ gst_wavpack_enc_set_wp_config (enc); /* set the configuration to the context now that we know everything * and initialize the encoder */ if (!WavpackSetConfiguration (enc->wp_context, enc->wp_config, (uint32_t) (-1)) || !WavpackPackInit (enc->wp_context)) { GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), ("error setting up wavpack encoding context")); WavpackCloseFile (enc->wp_context); gst_object_unref (enc); gst_buffer_unref (buf); return GST_FLOW_ERROR; } GST_DEBUG ("setup of encoding context successfull"); } if (enc->need_channel_remap) { buf = gst_buffer_make_writable (buf); gst_wavpack_enc_fix_channel_order (enc, (gint32 *) GST_BUFFER_DATA (buf), sample_count); } /* if we want to append the MD5 sum to the stream update it here * with the current raw samples */ if (enc->md5) { MD5Update (enc->md5_context, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); } /* encode and handle return values from encoding */ if (WavpackPackSamples (enc->wp_context, (int32_t *) GST_BUFFER_DATA (buf), sample_count / enc->channels)) { GST_DEBUG ("encoding samples successful"); ret = GST_FLOW_OK; } else { if ((enc->srcpad_last_return == GST_FLOW_RESEND) || (enc->wvcsrcpad_last_return == GST_FLOW_RESEND)) { ret = GST_FLOW_RESEND; } else if ((enc->srcpad_last_return == GST_FLOW_OK) || (enc->wvcsrcpad_last_return == GST_FLOW_OK)) { ret = GST_FLOW_OK; } else if ((enc->srcpad_last_return == GST_FLOW_NOT_LINKED) && (enc->wvcsrcpad_last_return == GST_FLOW_NOT_LINKED)) { ret = GST_FLOW_NOT_LINKED; } else if ((enc->srcpad_last_return == GST_FLOW_WRONG_STATE) && (enc->wvcsrcpad_last_return == GST_FLOW_WRONG_STATE)) { ret = GST_FLOW_WRONG_STATE; } else { GST_ELEMENT_ERROR (enc, LIBRARY, ENCODE, (NULL), ("encoding samples failed")); ret = GST_FLOW_ERROR; } } gst_buffer_unref (buf); gst_object_unref (enc); return ret; }