Branch data Line data Source code
1 : : /* GStreamer Wavpack encoder plugin
2 : : * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
3 : : *
4 : : * gstwavpackdec.c: Wavpack audio encoder
5 : : *
6 : : * This library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Library General Public
8 : : * License as published by the Free Software Foundation; either
9 : : * version 2 of the License, or (at your option) any later version.
10 : : *
11 : : * This library is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Library General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Library General Public
17 : : * License along with this library; if not, write to the
18 : : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 : : * Boston, MA 02111-1307, USA.
20 : : */
21 : :
22 : : /**
23 : : * SECTION:element-wavpackenc
24 : : *
25 : : * WavpackEnc encodes raw audio into a framed Wavpack stream.
26 : : * <ulink url="http://www.wavpack.com/">Wavpack</ulink> is an open-source
27 : : * audio codec that features both lossless and lossy encoding.
28 : : *
29 : : * <refsect2>
30 : : * <title>Example launch line</title>
31 : : * |[
32 : : * gst-launch audiotestsrc num-buffers=500 ! audioconvert ! wavpackenc ! filesink location=sinewave.wv
33 : : * ]| This pipeline encodes audio from audiotestsrc into a Wavpack file. The audioconvert element is needed
34 : : * as the Wavpack encoder only accepts input with 32 bit width (and every depth between 1 and 32 bits).
35 : : * |[
36 : : * gst-launch cdda://1 ! audioconvert ! wavpackenc ! filesink location=track1.wv
37 : : * ]| This pipeline encodes audio from an audio CD into a Wavpack file using
38 : : * lossless encoding (the file output will be fairly large).
39 : : * |[
40 : : * gst-launch cdda://1 ! audioconvert ! wavpackenc bitrate=128000 ! filesink location=track1.wv
41 : : * ]| This pipeline encodes audio from an audio CD into a Wavpack file using
42 : : * lossy encoding at a certain bitrate (the file will be fairly small).
43 : : * </refsect2>
44 : : */
45 : :
46 : : /*
47 : : * TODO: - add 32 bit float mode. CONFIG_FLOAT_DATA
48 : : */
49 : :
50 : : #include <string.h>
51 : : #include <gst/gst.h>
52 : : #include <glib/gprintf.h>
53 : :
54 : : #include <wavpack/wavpack.h>
55 : : #include "gstwavpackenc.h"
56 : : #include "gstwavpackcommon.h"
57 : :
58 : : static GstFlowReturn gst_wavpack_enc_chain (GstPad * pad, GstBuffer * buffer);
59 : : static gboolean gst_wavpack_enc_sink_set_caps (GstPad * pad, GstCaps * caps);
60 : : static int gst_wavpack_enc_push_block (void *id, void *data, int32_t count);
61 : : static gboolean gst_wavpack_enc_sink_event (GstPad * pad, GstEvent * event);
62 : : static GstStateChangeReturn gst_wavpack_enc_change_state (GstElement * element,
63 : : GstStateChange transition);
64 : : static void gst_wavpack_enc_set_property (GObject * object, guint prop_id,
65 : : const GValue * value, GParamSpec * pspec);
66 : : static void gst_wavpack_enc_get_property (GObject * object, guint prop_id,
67 : : GValue * value, GParamSpec * pspec);
68 : :
69 : : enum
70 : : {
71 : : ARG_0,
72 : : ARG_MODE,
73 : : ARG_BITRATE,
74 : : ARG_BITSPERSAMPLE,
75 : : ARG_CORRECTION_MODE,
76 : : ARG_MD5,
77 : : ARG_EXTRA_PROCESSING,
78 : : ARG_JOINT_STEREO_MODE
79 : : };
80 : :
81 : : GST_DEBUG_CATEGORY_STATIC (gst_wavpack_enc_debug);
82 : : #define GST_CAT_DEFAULT gst_wavpack_enc_debug
83 : :
84 : : static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
85 : : GST_PAD_SINK,
86 : : GST_PAD_ALWAYS,
87 : : GST_STATIC_CAPS ("audio/x-raw-int, "
88 : : "width = (int) 32, "
89 : : "depth = (int) [ 1, 32], "
90 : : "endianness = (int) BYTE_ORDER, "
91 : : "channels = (int) [ 1, 8 ], "
92 : : "rate = (int) [ 6000, 192000 ]," "signed = (boolean) TRUE")
93 : : );
94 : :
95 : : static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
96 : : GST_PAD_SRC,
97 : : GST_PAD_ALWAYS,
98 : : GST_STATIC_CAPS ("audio/x-wavpack, "
99 : : "width = (int) [ 1, 32 ], "
100 : : "channels = (int) [ 1, 2 ], "
101 : : "rate = (int) [ 6000, 192000 ], " "framed = (boolean) TRUE")
102 : : );
103 : :
104 : : static GstStaticPadTemplate wvcsrc_factory = GST_STATIC_PAD_TEMPLATE ("wvcsrc",
105 : : GST_PAD_SRC,
106 : : GST_PAD_SOMETIMES,
107 : : GST_STATIC_CAPS ("audio/x-wavpack-correction, " "framed = (boolean) TRUE")
108 : : );
109 : :
110 : : enum
111 : : {
112 : : GST_WAVPACK_ENC_MODE_VERY_FAST = 0,
113 : : GST_WAVPACK_ENC_MODE_FAST,
114 : : GST_WAVPACK_ENC_MODE_DEFAULT,
115 : : GST_WAVPACK_ENC_MODE_HIGH,
116 : : GST_WAVPACK_ENC_MODE_VERY_HIGH
117 : : };
118 : :
119 : : #define GST_TYPE_WAVPACK_ENC_MODE (gst_wavpack_enc_mode_get_type ())
120 : : static GType
121 : 6 : gst_wavpack_enc_mode_get_type (void)
122 : : {
123 : : static GType qtype = 0;
124 : :
125 [ + - ]: 6 : if (qtype == 0) {
126 : : static const GEnumValue values[] = {
127 : : #if 0
128 : : /* Very Fast Compression is not supported yet, but will be supported
129 : : * in future wavpack versions */
130 : : {GST_WAVPACK_ENC_MODE_VERY_FAST, "Very Fast Compression", "veryfast"},
131 : : #endif
132 : : {GST_WAVPACK_ENC_MODE_FAST, "Fast Compression", "fast"},
133 : : {GST_WAVPACK_ENC_MODE_DEFAULT, "Normal Compression", "normal"},
134 : : {GST_WAVPACK_ENC_MODE_HIGH, "High Compression", "high"},
135 : : #ifndef WAVPACK_OLD_API
136 : : {GST_WAVPACK_ENC_MODE_VERY_HIGH, "Very High Compression", "veryhigh"},
137 : : #endif
138 : : {0, NULL, NULL}
139 : : };
140 : :
141 : 6 : qtype = g_enum_register_static ("GstWavpackEncMode", values);
142 : : }
143 : 6 : return qtype;
144 : : }
145 : :
146 : : enum
147 : : {
148 : : GST_WAVPACK_CORRECTION_MODE_OFF = 0,
149 : : GST_WAVPACK_CORRECTION_MODE_ON,
150 : : GST_WAVPACK_CORRECTION_MODE_OPTIMIZED
151 : : };
152 : :
153 : : #define GST_TYPE_WAVPACK_ENC_CORRECTION_MODE (gst_wavpack_enc_correction_mode_get_type ())
154 : : static GType
155 : 6 : gst_wavpack_enc_correction_mode_get_type (void)
156 : : {
157 : : static GType qtype = 0;
158 : :
159 [ + - ]: 6 : if (qtype == 0) {
160 : : static const GEnumValue values[] = {
161 : : {GST_WAVPACK_CORRECTION_MODE_OFF, "Create no correction file", "off"},
162 : : {GST_WAVPACK_CORRECTION_MODE_ON, "Create correction file", "on"},
163 : : {GST_WAVPACK_CORRECTION_MODE_OPTIMIZED,
164 : : "Create optimized correction file", "optimized"},
165 : : {0, NULL, NULL}
166 : : };
167 : :
168 : 6 : qtype = g_enum_register_static ("GstWavpackEncCorrectionMode", values);
169 : : }
170 : 6 : return qtype;
171 : : }
172 : :
173 : : enum
174 : : {
175 : : GST_WAVPACK_JS_MODE_AUTO = 0,
176 : : GST_WAVPACK_JS_MODE_LEFT_RIGHT,
177 : : GST_WAVPACK_JS_MODE_MID_SIDE
178 : : };
179 : :
180 : : #define GST_TYPE_WAVPACK_ENC_JOINT_STEREO_MODE (gst_wavpack_enc_joint_stereo_mode_get_type ())
181 : : static GType
182 : 6 : gst_wavpack_enc_joint_stereo_mode_get_type (void)
183 : : {
184 : : static GType qtype = 0;
185 : :
186 [ + - ]: 6 : if (qtype == 0) {
187 : : static const GEnumValue values[] = {
188 : : {GST_WAVPACK_JS_MODE_AUTO, "auto", "auto"},
189 : : {GST_WAVPACK_JS_MODE_LEFT_RIGHT, "left/right", "leftright"},
190 : : {GST_WAVPACK_JS_MODE_MID_SIDE, "mid/side", "midside"},
191 : : {0, NULL, NULL}
192 : : };
193 : :
194 : 6 : qtype = g_enum_register_static ("GstWavpackEncJSMode", values);
195 : : }
196 : 6 : return qtype;
197 : : }
198 : :
199 : : static void
200 : 11 : _do_init (GType object_type)
201 : : {
202 : 11 : const GInterfaceInfo preset_interface_info = {
203 : : NULL, /* interface_init */
204 : : NULL, /* interface_finalize */
205 : : NULL /* interface_data */
206 : : };
207 : :
208 : 11 : g_type_add_interface_static (object_type, GST_TYPE_PRESET,
209 : : &preset_interface_info);
210 : 11 : }
211 : :
212 [ + + ]: 2121 : GST_BOILERPLATE_FULL (GstWavpackEnc, gst_wavpack_enc, GstElement,
213 : 2121 : GST_TYPE_ELEMENT, _do_init);
214 : :
215 : : static void
216 : 6 : gst_wavpack_enc_base_init (gpointer klass)
217 : : {
218 : 6 : GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
219 : :
220 : : /* add pad templates */
221 : 6 : gst_element_class_add_pad_template (element_class,
222 : : gst_static_pad_template_get (&sink_factory));
223 : 6 : gst_element_class_add_pad_template (element_class,
224 : : gst_static_pad_template_get (&src_factory));
225 : 6 : gst_element_class_add_pad_template (element_class,
226 : : gst_static_pad_template_get (&wvcsrc_factory));
227 : :
228 : : /* set element details */
229 : 6 : gst_element_class_set_details_simple (element_class, "Wavpack audio encoder",
230 : : "Codec/Encoder/Audio",
231 : : "Encodes audio with the Wavpack lossless/lossy audio codec",
232 : : "Sebastian Dröge <slomo@circular-chaos.org>");
233 : 6 : }
234 : :
235 : :
236 : : static void
237 : 6 : gst_wavpack_enc_class_init (GstWavpackEncClass * klass)
238 : : {
239 : 6 : GObjectClass *gobject_class = (GObjectClass *) klass;
240 : 6 : GstElementClass *gstelement_class = (GstElementClass *) klass;
241 : :
242 : 6 : parent_class = g_type_class_peek_parent (klass);
243 : :
244 : : /* set state change handler */
245 : 6 : gstelement_class->change_state =
246 : 6 : GST_DEBUG_FUNCPTR (gst_wavpack_enc_change_state);
247 : :
248 : : /* set property handlers */
249 : 6 : gobject_class->set_property = gst_wavpack_enc_set_property;
250 : 6 : gobject_class->get_property = gst_wavpack_enc_get_property;
251 : :
252 : : /* install all properties */
253 : 6 : g_object_class_install_property (gobject_class, ARG_MODE,
254 : : g_param_spec_enum ("mode", "Encoding mode",
255 : : "Speed versus compression tradeoff.",
256 : : GST_TYPE_WAVPACK_ENC_MODE, GST_WAVPACK_ENC_MODE_DEFAULT,
257 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
258 : 6 : g_object_class_install_property (gobject_class, ARG_BITRATE,
259 : : g_param_spec_uint ("bitrate", "Bitrate",
260 : : "Try to encode with this average bitrate (bits/sec). "
261 : : "This enables lossy encoding, values smaller than 24000 disable it again.",
262 : : 0, 9600000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
263 : 6 : g_object_class_install_property (gobject_class, ARG_BITSPERSAMPLE,
264 : : g_param_spec_double ("bits-per-sample", "Bits per sample",
265 : : "Try to encode with this amount of bits per sample. "
266 : : "This enables lossy encoding, values smaller than 2.0 disable it again.",
267 : : 0.0, 24.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
268 : 6 : g_object_class_install_property (gobject_class, ARG_CORRECTION_MODE,
269 : : g_param_spec_enum ("correction-mode", "Correction stream mode",
270 : : "Use this mode for the correction stream. Only works in lossy mode!",
271 : : GST_TYPE_WAVPACK_ENC_CORRECTION_MODE, GST_WAVPACK_CORRECTION_MODE_OFF,
272 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
273 : 6 : g_object_class_install_property (gobject_class, ARG_MD5,
274 : : g_param_spec_boolean ("md5", "MD5",
275 : : "Store MD5 hash of raw samples within the file.", FALSE,
276 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
277 : 6 : g_object_class_install_property (gobject_class, ARG_EXTRA_PROCESSING,
278 : : g_param_spec_uint ("extra-processing", "Extra processing",
279 : : "Use better but slower filters for better compression/quality.",
280 : : 0, 6, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
281 : 6 : g_object_class_install_property (gobject_class, ARG_JOINT_STEREO_MODE,
282 : : g_param_spec_enum ("joint-stereo-mode", "Joint-Stereo mode",
283 : : "Use this joint-stereo mode.", GST_TYPE_WAVPACK_ENC_JOINT_STEREO_MODE,
284 : : GST_WAVPACK_JS_MODE_AUTO,
285 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
286 : 6 : }
287 : :
288 : : static void
289 : 14 : gst_wavpack_enc_reset (GstWavpackEnc * enc)
290 : : {
291 : : /* close and free everything stream related if we already did something */
292 [ - + ]: 14 : if (enc->wp_context) {
293 : 0 : WavpackCloseFile (enc->wp_context);
294 : 0 : enc->wp_context = NULL;
295 : : }
296 [ + + ]: 14 : if (enc->wp_config) {
297 : 2 : g_free (enc->wp_config);
298 : 2 : enc->wp_config = NULL;
299 : : }
300 [ + + ]: 14 : if (enc->first_block) {
301 : 2 : g_free (enc->first_block);
302 : 2 : enc->first_block = NULL;
303 : : }
304 : 14 : enc->first_block_size = 0;
305 [ - + ]: 14 : if (enc->md5_context) {
306 : 0 : g_checksum_free (enc->md5_context);
307 : 0 : enc->md5_context = NULL;
308 : : }
309 : :
310 [ - + ]: 14 : if (enc->pending_buffer) {
311 : 0 : gst_buffer_unref (enc->pending_buffer);
312 : 0 : enc->pending_buffer = NULL;
313 : 0 : enc->pending_offset = 0;
314 : : }
315 : :
316 : : /* reset the last returns to GST_FLOW_OK. This is only set to something else
317 : : * while WavpackPackSamples() or more specific gst_wavpack_enc_push_block()
318 : : * so not valid anymore */
319 : 14 : enc->srcpad_last_return = enc->wvcsrcpad_last_return = GST_FLOW_OK;
320 : :
321 : : /* reset stream information */
322 : 14 : enc->samplerate = 0;
323 : 14 : enc->depth = 0;
324 : 14 : enc->channels = 0;
325 : 14 : enc->channel_mask = 0;
326 : 14 : enc->need_channel_remap = FALSE;
327 : :
328 : 14 : enc->timestamp_offset = GST_CLOCK_TIME_NONE;
329 : 14 : enc->next_ts = GST_CLOCK_TIME_NONE;
330 : 14 : }
331 : :
332 : : static void
333 : 5 : gst_wavpack_enc_init (GstWavpackEnc * enc, GstWavpackEncClass * gclass)
334 : : {
335 : 5 : enc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
336 : 5 : gst_pad_set_setcaps_function (enc->sinkpad,
337 : 5 : GST_DEBUG_FUNCPTR (gst_wavpack_enc_sink_set_caps));
338 : 5 : gst_pad_set_chain_function (enc->sinkpad,
339 : 5 : GST_DEBUG_FUNCPTR (gst_wavpack_enc_chain));
340 : 5 : gst_pad_set_event_function (enc->sinkpad,
341 : 5 : GST_DEBUG_FUNCPTR (gst_wavpack_enc_sink_event));
342 : 5 : gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
343 : :
344 : : /* setup src pad */
345 : 5 : enc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
346 : 5 : gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
347 : :
348 : : /* initialize object attributes */
349 : 5 : enc->wp_config = NULL;
350 : 5 : enc->wp_context = NULL;
351 : 5 : enc->first_block = NULL;
352 : 5 : enc->md5_context = NULL;
353 : 5 : gst_wavpack_enc_reset (enc);
354 : :
355 : 5 : enc->wv_id.correction = FALSE;
356 : 5 : enc->wv_id.wavpack_enc = enc;
357 : 5 : enc->wv_id.passthrough = FALSE;
358 : 5 : enc->wvc_id.correction = TRUE;
359 : 5 : enc->wvc_id.wavpack_enc = enc;
360 : 5 : enc->wvc_id.passthrough = FALSE;
361 : :
362 : : /* set default values of params */
363 : 5 : enc->mode = GST_WAVPACK_ENC_MODE_DEFAULT;
364 : 5 : enc->bitrate = 0;
365 : 5 : enc->bps = 0.0;
366 : 5 : enc->correction_mode = GST_WAVPACK_CORRECTION_MODE_OFF;
367 : 5 : enc->md5 = FALSE;
368 : 5 : enc->extra_processing = 0;
369 : 5 : enc->joint_stereo_mode = GST_WAVPACK_JS_MODE_AUTO;
370 : 5 : }
371 : :
372 : : static gboolean
373 : 2 : gst_wavpack_enc_sink_set_caps (GstPad * pad, GstCaps * caps)
374 : : {
375 : 2 : GstWavpackEnc *enc = GST_WAVPACK_ENC (gst_pad_get_parent (pad));
376 : 2 : GstStructure *structure = gst_caps_get_structure (caps, 0);
377 : : GstAudioChannelPosition *pos;
378 : :
379 [ + - + - ]: 4 : if (!gst_structure_get_int (structure, "channels", &enc->channels) ||
380 [ - + ]: 4 : !gst_structure_get_int (structure, "rate", &enc->samplerate) ||
381 : 2 : !gst_structure_get_int (structure, "depth", &enc->depth)) {
382 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL),
[ # # ][ # # ]
383 : : ("got invalid caps: %" GST_PTR_FORMAT, caps));
384 : 0 : gst_object_unref (enc);
385 : 0 : return FALSE;
386 : : }
387 : :
388 : 2 : pos = gst_audio_get_channel_positions (structure);
389 : : /* If one channel is NONE they'll be all undefined */
390 [ + - ][ - + ]: 2 : if (pos != NULL && pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE) {
391 : 0 : g_free (pos);
392 : 0 : pos = NULL;
393 : : }
394 : :
395 [ - + ]: 2 : if (pos == NULL) {
396 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (enc, STREAM, FORMAT, (NULL),
[ # # ][ # # ]
397 : : ("input has no valid channel layout"));
398 : :
399 : 0 : gst_object_unref (enc);
400 : 0 : return FALSE;
401 : : }
402 : :
403 : 2 : enc->channel_mask =
404 : 2 : gst_wavpack_get_channel_mask_from_positions (pos, enc->channels);
405 : 2 : enc->need_channel_remap =
406 : 2 : gst_wavpack_set_channel_mapping (pos, enc->channels,
407 : 2 : enc->channel_mapping);
408 : 2 : g_free (pos);
409 : :
410 : : /* set fixed src pad caps now that we know what we will get */
411 : 2 : caps = gst_caps_new_simple ("audio/x-wavpack",
412 : : "channels", G_TYPE_INT, enc->channels,
413 : : "rate", G_TYPE_INT, enc->samplerate,
414 : : "width", G_TYPE_INT, enc->depth, "framed", G_TYPE_BOOLEAN, TRUE, NULL);
415 : :
416 [ - + ]: 2 : if (!gst_wavpack_set_channel_layout (caps, enc->channel_mask))
417 [ # # ]: 0 : GST_WARNING_OBJECT (enc, "setting channel layout failed");
418 : :
419 [ - + ]: 2 : if (!gst_pad_set_caps (enc->srcpad, caps)) {
420 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL),
[ # # ][ # # ]
421 : : ("setting caps failed: %" GST_PTR_FORMAT, caps));
422 : 0 : gst_caps_unref (caps);
423 : 0 : gst_object_unref (enc);
424 : 0 : return FALSE;
425 : : }
426 : 2 : gst_pad_use_fixed_caps (enc->srcpad);
427 : :
428 : 2 : gst_caps_unref (caps);
429 : 2 : gst_object_unref (enc);
430 : 2 : return TRUE;
431 : : }
432 : :
433 : : static void
434 : 2 : gst_wavpack_enc_set_wp_config (GstWavpackEnc * enc)
435 : : {
436 : 2 : enc->wp_config = g_new0 (WavpackConfig, 1);
437 : : /* set general stream informations in the WavpackConfig */
438 : 2 : enc->wp_config->bytes_per_sample = GST_ROUND_UP_8 (enc->depth) / 8;
439 : 2 : enc->wp_config->bits_per_sample = enc->depth;
440 : 2 : enc->wp_config->num_channels = enc->channels;
441 : 2 : enc->wp_config->channel_mask = enc->channel_mask;
442 : 2 : enc->wp_config->sample_rate = enc->samplerate;
443 : :
444 : : /*
445 : : * Set parameters in WavpackConfig
446 : : */
447 : :
448 : : /* Encoding mode */
449 [ - + - - : 2 : switch (enc->mode) {
- ]
450 : : #if 0
451 : : case GST_WAVPACK_ENC_MODE_VERY_FAST:
452 : : enc->wp_config->flags |= CONFIG_VERY_FAST_FLAG;
453 : : enc->wp_config->flags |= CONFIG_FAST_FLAG;
454 : : break;
455 : : #endif
456 : : case GST_WAVPACK_ENC_MODE_FAST:
457 : 0 : enc->wp_config->flags |= CONFIG_FAST_FLAG;
458 : 0 : break;
459 : : case GST_WAVPACK_ENC_MODE_DEFAULT:
460 : 2 : break;
461 : : case GST_WAVPACK_ENC_MODE_HIGH:
462 : 0 : enc->wp_config->flags |= CONFIG_HIGH_FLAG;
463 : 0 : break;
464 : : #ifndef WAVPACK_OLD_API
465 : : case GST_WAVPACK_ENC_MODE_VERY_HIGH:
466 : 0 : enc->wp_config->flags |= CONFIG_HIGH_FLAG;
467 : 0 : enc->wp_config->flags |= CONFIG_VERY_HIGH_FLAG;
468 : 0 : break;
469 : : #endif
470 : : }
471 : :
472 : : /* Bitrate, enables lossy mode */
473 [ - + ]: 2 : if (enc->bitrate) {
474 : 0 : enc->wp_config->flags |= CONFIG_HYBRID_FLAG;
475 : 0 : enc->wp_config->flags |= CONFIG_BITRATE_KBPS;
476 : 0 : enc->wp_config->bitrate = enc->bitrate / 1000.0;
477 [ - + ]: 2 : } else if (enc->bps) {
478 : 0 : enc->wp_config->flags |= CONFIG_HYBRID_FLAG;
479 : 0 : enc->wp_config->bitrate = enc->bps;
480 : : }
481 : :
482 : : /* Correction Mode, only in lossy mode */
483 [ - + ]: 2 : if (enc->wp_config->flags & CONFIG_HYBRID_FLAG) {
484 [ # # ]: 0 : if (enc->correction_mode > GST_WAVPACK_CORRECTION_MODE_OFF) {
485 : 0 : GstCaps *caps = gst_caps_new_simple ("audio/x-wavpack-correction",
486 : : "framed", G_TYPE_BOOLEAN, TRUE, NULL);
487 : :
488 : 0 : enc->wvcsrcpad =
489 : 0 : gst_pad_new_from_static_template (&wvcsrc_factory, "wvcsrc");
490 : :
491 : : /* try to add correction src pad, don't set correction mode on failure */
492 [ # # ]: 0 : GST_DEBUG_OBJECT (enc, "Adding correction pad with caps %"
493 : : GST_PTR_FORMAT, caps);
494 [ # # ]: 0 : if (!gst_pad_set_caps (enc->wvcsrcpad, caps)) {
495 : 0 : enc->correction_mode = 0;
496 [ # # ]: 0 : GST_WARNING_OBJECT (enc, "setting correction caps failed");
497 : : } else {
498 : 0 : gst_pad_use_fixed_caps (enc->wvcsrcpad);
499 : 0 : gst_pad_set_active (enc->wvcsrcpad, TRUE);
500 : 0 : gst_element_add_pad (GST_ELEMENT (enc), enc->wvcsrcpad);
501 : 0 : enc->wp_config->flags |= CONFIG_CREATE_WVC;
502 [ # # ]: 0 : if (enc->correction_mode == GST_WAVPACK_CORRECTION_MODE_OPTIMIZED) {
503 : 0 : enc->wp_config->flags |= CONFIG_OPTIMIZE_WVC;
504 : : }
505 : : }
506 : 0 : gst_caps_unref (caps);
507 : : }
508 : : } else {
509 [ - + ]: 2 : if (enc->correction_mode > GST_WAVPACK_CORRECTION_MODE_OFF) {
510 : 0 : enc->correction_mode = 0;
511 [ # # ]: 0 : GST_WARNING_OBJECT (enc, "setting correction mode only has "
512 : : "any effect if a bitrate is provided.");
513 : : }
514 : : }
515 : 2 : gst_element_no_more_pads (GST_ELEMENT (enc));
516 : :
517 : : /* MD5, setup MD5 context */
518 [ - + ][ # # ]: 2 : if ((enc->md5) && !(enc->md5_context)) {
519 : 0 : enc->wp_config->flags |= CONFIG_MD5_CHECKSUM;
520 : 0 : enc->md5_context = g_checksum_new (G_CHECKSUM_MD5);
521 : : }
522 : :
523 : : /* Extra encode processing */
524 [ - + ]: 2 : if (enc->extra_processing) {
525 : 0 : enc->wp_config->flags |= CONFIG_EXTRA_MODE;
526 : 0 : enc->wp_config->xmode = enc->extra_processing;
527 : : }
528 : :
529 : : /* Joint stereo mode */
530 [ + - - - ]: 2 : switch (enc->joint_stereo_mode) {
531 : : case GST_WAVPACK_JS_MODE_AUTO:
532 : 2 : break;
533 : : case GST_WAVPACK_JS_MODE_LEFT_RIGHT:
534 : 0 : enc->wp_config->flags |= CONFIG_JOINT_OVERRIDE;
535 : 0 : enc->wp_config->flags &= ~CONFIG_JOINT_STEREO;
536 : 0 : break;
537 : : case GST_WAVPACK_JS_MODE_MID_SIDE:
538 : 0 : enc->wp_config->flags |= (CONFIG_JOINT_OVERRIDE | CONFIG_JOINT_STEREO);
539 : 0 : break;
540 : : }
541 : 2 : }
542 : :
543 : : static int
544 : 50 : gst_wavpack_enc_push_block (void *id, void *data, int32_t count)
545 : : {
546 : 50 : GstWavpackEncWriteID *wid = (GstWavpackEncWriteID *) id;
547 : 50 : GstWavpackEnc *enc = GST_WAVPACK_ENC (wid->wavpack_enc);
548 : : GstFlowReturn *flow;
549 : : GstBuffer *buffer;
550 : : GstPad *pad;
551 : 50 : guchar *block = (guchar *) data;
552 : :
553 [ - + ]: 50 : pad = (wid->correction) ? enc->wvcsrcpad : enc->srcpad;
554 : 50 : flow =
555 [ - + ]: 50 : (wid->correction) ? &enc->wvcsrcpad_last_return : &enc->
556 : : srcpad_last_return;
557 : :
558 : 50 : *flow = gst_pad_alloc_buffer_and_set_caps (pad, GST_BUFFER_OFFSET_NONE,
559 : : count, GST_PAD_CAPS (pad), &buffer);
560 : :
561 [ - + ]: 50 : if (*flow != GST_FLOW_OK) {
562 [ # # ][ # # ]: 0 : GST_WARNING_OBJECT (enc, "flow on %s:%s = %s",
[ # # ][ # # ]
[ # # ][ # # ]
563 : : GST_DEBUG_PAD_NAME (pad), gst_flow_get_name (*flow));
564 : 0 : return FALSE;
565 : : }
566 : :
567 : 50 : g_memmove (GST_BUFFER_DATA (buffer), block, count);
568 : :
569 [ + - ][ + - ]: 100 : if (count > sizeof (WavpackHeader) && memcmp (block, "wvpk", 4) == 0) {
570 : : /* if it's a Wavpack block set buffer timestamp and duration, etc */
571 : : WavpackHeader wph;
572 : :
573 [ - + ][ # # ]: 50 : GST_LOG_OBJECT (enc, "got %d bytes of encoded wavpack %sdata",
574 : : count, (wid->correction) ? "correction " : "");
575 : :
576 : 50 : gst_wavpack_read_header (&wph, block);
577 : :
578 : : /* Only set when pushing the first buffer again, in that case
579 : : * we don't want to delay the buffer or push newsegment events
580 : : */
581 [ + + ]: 50 : if (!wid->passthrough) {
582 : : /* Only push complete blocks */
583 [ + - ]: 48 : if (enc->pending_buffer == NULL) {
584 : 48 : enc->pending_buffer = buffer;
585 : 48 : enc->pending_offset = wph.block_index;
586 [ # # ]: 0 : } else if (enc->pending_offset == wph.block_index) {
587 : 0 : enc->pending_buffer = gst_buffer_join (enc->pending_buffer, buffer);
588 : : } else {
589 [ # # ]: 0 : GST_ERROR ("Got incomplete block, dropping");
590 : 0 : gst_buffer_unref (enc->pending_buffer);
591 : 0 : enc->pending_buffer = buffer;
592 : 0 : enc->pending_offset = wph.block_index;
593 : : }
594 : :
595 [ - + ]: 48 : if (!(wph.flags & FINAL_BLOCK))
596 : 0 : return TRUE;
597 : :
598 : 48 : buffer = enc->pending_buffer;
599 : 48 : enc->pending_buffer = NULL;
600 : 48 : enc->pending_offset = 0;
601 : :
602 : : /* if it's the first wavpack block, send a NEW_SEGMENT event */
603 [ + + ]: 48 : if (wph.block_index == 0) {
604 : 2 : gst_pad_push_event (pad,
605 : : gst_event_new_new_segment (FALSE,
606 : : 1.0, GST_FORMAT_TIME, 0, GST_BUFFER_OFFSET_NONE, 0));
607 : :
608 : : /* save header for later reference, so we can re-send it later on
609 : : * EOS with fixed up values for total sample count etc. */
610 [ + - ][ + - ]: 2 : if (enc->first_block == NULL && !wid->correction) {
611 : 2 : enc->first_block =
612 : 2 : g_memdup (GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
613 : 2 : enc->first_block_size = GST_BUFFER_SIZE (buffer);
614 : : }
615 : : }
616 : : }
617 : :
618 : : /* set buffer timestamp, duration, offset, offset_end from
619 : : * the wavpack header */
620 : 100 : GST_BUFFER_TIMESTAMP (buffer) = enc->timestamp_offset +
621 : 50 : gst_util_uint64_scale_int (GST_SECOND, wph.block_index,
622 : : enc->samplerate);
623 : 100 : GST_BUFFER_DURATION (buffer) =
624 : 50 : gst_util_uint64_scale_int (GST_SECOND, wph.block_samples,
625 : : enc->samplerate);
626 : 50 : GST_BUFFER_OFFSET (buffer) = wph.block_index;
627 : 50 : GST_BUFFER_OFFSET_END (buffer) = wph.block_index + wph.block_samples;
628 : : } else {
629 : : /* if it's something else set no timestamp and duration on the buffer */
630 [ # # ]: 0 : GST_DEBUG_OBJECT (enc, "got %d bytes of unknown data", count);
631 : :
632 : 0 : GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE;
633 : 0 : GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
634 : : }
635 : :
636 : : /* push the buffer and forward errors */
637 [ - + ]: 50 : GST_DEBUG_OBJECT (enc, "pushing buffer with %d bytes",
638 : : GST_BUFFER_SIZE (buffer));
639 : 50 : *flow = gst_pad_push (pad, buffer);
640 : :
641 [ - + ]: 50 : if (*flow != GST_FLOW_OK) {
642 [ # # ][ # # ]: 0 : GST_WARNING_OBJECT (enc, "flow on %s:%s = %s",
[ # # ][ # # ]
[ # # ][ # # ]
643 : : GST_DEBUG_PAD_NAME (pad), gst_flow_get_name (*flow));
644 : 0 : return FALSE;
645 : : }
646 : :
647 : 50 : return TRUE;
648 : : }
649 : :
650 : : static void
651 : 0 : gst_wavpack_enc_fix_channel_order (GstWavpackEnc * enc, gint32 * data,
652 : : gint nsamples)
653 : : {
654 : : gint i, j;
655 : : gint32 tmp[8];
656 : :
657 [ # # ]: 0 : for (i = 0; i < nsamples / enc->channels; i++) {
658 [ # # ]: 0 : for (j = 0; j < enc->channels; j++) {
659 : 0 : tmp[enc->channel_mapping[j]] = data[j];
660 : : }
661 [ # # ]: 0 : for (j = 0; j < enc->channels; j++) {
662 : 0 : data[j] = tmp[j];
663 : : }
664 : 0 : data += enc->channels;
665 : : }
666 : 0 : }
667 : :
668 : : static GstFlowReturn
669 : 2001 : gst_wavpack_enc_chain (GstPad * pad, GstBuffer * buf)
670 : : {
671 : 2001 : GstWavpackEnc *enc = GST_WAVPACK_ENC (gst_pad_get_parent (pad));
672 : 2001 : uint32_t sample_count = GST_BUFFER_SIZE (buf) / 4;
673 : : GstFlowReturn ret;
674 : :
675 : : /* reset the last returns to GST_FLOW_OK. This is only set to something else
676 : : * while WavpackPackSamples() or more specific gst_wavpack_enc_push_block()
677 : : * so not valid anymore */
678 : 2001 : enc->srcpad_last_return = enc->wvcsrcpad_last_return = GST_FLOW_OK;
679 : :
680 [ - + ]: 2001 : GST_DEBUG ("got %u raw samples", sample_count);
681 : :
682 : : /* check if we already have a valid WavpackContext, otherwise make one */
683 [ + + ]: 2001 : if (!enc->wp_context) {
684 : : /* create raw context */
685 : 2 : enc->wp_context =
686 [ - + ]: 2 : WavpackOpenFileOutput (gst_wavpack_enc_push_block, &enc->wv_id,
687 : 2 : (enc->correction_mode > 0) ? &enc->wvc_id : NULL);
688 [ - + ]: 2 : if (!enc->wp_context) {
689 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL),
[ # # ][ # # ]
690 : : ("error creating Wavpack context"));
691 : 0 : gst_object_unref (enc);
692 : 0 : gst_buffer_unref (buf);
693 : 0 : return GST_FLOW_ERROR;
694 : : }
695 : :
696 : : /* set the WavpackConfig according to our parameters */
697 : 2 : gst_wavpack_enc_set_wp_config (enc);
698 : :
699 : : /* set the configuration to the context now that we know everything
700 : : * and initialize the encoder */
701 [ + - ]: 2 : if (!WavpackSetConfiguration (enc->wp_context,
702 : : enc->wp_config, (uint32_t) (-1))
703 [ - + ]: 2 : || !WavpackPackInit (enc->wp_context)) {
704 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL),
[ # # ][ # # ]
705 : : ("error setting up wavpack encoding context"));
706 : 0 : WavpackCloseFile (enc->wp_context);
707 : 0 : gst_object_unref (enc);
708 : 0 : gst_buffer_unref (buf);
709 : 0 : return GST_FLOW_ERROR;
710 : : }
711 [ - + ]: 2 : GST_DEBUG ("setup of encoding context successfull");
712 : : }
713 : :
714 : : /* Save the timestamp of the first buffer. This will be later
715 : : * used as offset for all following buffers */
716 [ + + ]: 2001 : if (enc->timestamp_offset == GST_CLOCK_TIME_NONE) {
717 [ + - ]: 2 : if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
718 : 2 : enc->timestamp_offset = GST_BUFFER_TIMESTAMP (buf);
719 : 2 : enc->next_ts = GST_BUFFER_TIMESTAMP (buf);
720 : : } else {
721 : 0 : enc->timestamp_offset = 0;
722 : 0 : enc->next_ts = 0;
723 : : }
724 : : }
725 : :
726 : : /* Check if we have a continous stream, if not drop some samples or the buffer or
727 : : * insert some silence samples */
728 [ + - ][ - + ]: 2001 : if (enc->next_ts != GST_CLOCK_TIME_NONE &&
729 : 2001 : GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) {
730 : 0 : guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf);
731 : : guint64 diff_bytes;
732 : :
733 [ # # ][ # # ]: 0 : GST_WARNING_OBJECT (enc, "Buffer is older than previous "
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
734 : : "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
735 : : "), cannot handle. Clipping buffer.",
736 : : GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
737 : : GST_TIME_ARGS (enc->next_ts));
738 : :
739 : 0 : diff_bytes =
740 : 0 : GST_CLOCK_TIME_TO_FRAMES (diff, enc->samplerate) * enc->channels * 2;
741 [ # # ]: 0 : if (diff_bytes >= GST_BUFFER_SIZE (buf)) {
742 : 0 : gst_buffer_unref (buf);
743 : 0 : return GST_FLOW_OK;
744 : : }
745 : 0 : buf = gst_buffer_make_metadata_writable (buf);
746 : 0 : GST_BUFFER_DATA (buf) += diff_bytes;
747 : 0 : GST_BUFFER_SIZE (buf) -= diff_bytes;
748 : :
749 : 0 : GST_BUFFER_TIMESTAMP (buf) += diff;
750 [ # # ]: 0 : if (GST_BUFFER_DURATION_IS_VALID (buf))
751 : 0 : GST_BUFFER_DURATION (buf) -= diff;
752 : : }
753 : :
754 : : /* Allow a diff of at most 5 ms */
755 [ + - ]: 2001 : if (enc->next_ts != GST_CLOCK_TIME_NONE
756 [ + - ]: 2001 : && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
757 [ - + ][ # # ]: 2001 : if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts &&
758 : 0 : GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > 5 * GST_MSECOND) {
759 [ # # ]: 0 : GST_WARNING_OBJECT (enc,
760 : : "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
761 : : GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, 5 * GST_MSECOND);
762 : :
763 : 0 : WavpackFlushSamples (enc->wp_context);
764 : 0 : enc->timestamp_offset += (GST_BUFFER_TIMESTAMP (buf) - enc->next_ts);
765 : : }
766 : : }
767 : :
768 [ + - ]: 2001 : if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)
769 [ + + ]: 2001 : && GST_BUFFER_DURATION_IS_VALID (buf))
770 : 2000 : enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
771 : : else
772 : 1 : enc->next_ts = GST_CLOCK_TIME_NONE;
773 : :
774 [ - + ]: 2001 : if (enc->need_channel_remap) {
775 : 0 : buf = gst_buffer_make_writable (buf);
776 : 0 : gst_wavpack_enc_fix_channel_order (enc, (gint32 *) GST_BUFFER_DATA (buf),
777 : : sample_count);
778 : : }
779 : :
780 : : /* if we want to append the MD5 sum to the stream update it here
781 : : * with the current raw samples */
782 [ - + ]: 2001 : if (enc->md5) {
783 : 0 : g_checksum_update (enc->md5_context, GST_BUFFER_DATA (buf),
784 : 0 : GST_BUFFER_SIZE (buf));
785 : : }
786 : :
787 : : /* encode and handle return values from encoding */
788 [ + - ]: 2001 : if (WavpackPackSamples (enc->wp_context, (int32_t *) GST_BUFFER_DATA (buf),
789 : 2001 : sample_count / enc->channels)) {
790 [ - + ]: 2001 : GST_DEBUG ("encoding samples successful");
791 : 2001 : ret = GST_FLOW_OK;
792 : : } else {
793 [ # # ][ # # ]: 0 : if ((enc->srcpad_last_return == GST_FLOW_RESEND) ||
794 : 0 : (enc->wvcsrcpad_last_return == GST_FLOW_RESEND)) {
795 : 0 : ret = GST_FLOW_RESEND;
796 [ # # ][ # # ]: 0 : } else if ((enc->srcpad_last_return == GST_FLOW_OK) ||
797 : 0 : (enc->wvcsrcpad_last_return == GST_FLOW_OK)) {
798 : 0 : ret = GST_FLOW_OK;
799 [ # # ][ # # ]: 0 : } else if ((enc->srcpad_last_return == GST_FLOW_NOT_LINKED) &&
800 : 0 : (enc->wvcsrcpad_last_return == GST_FLOW_NOT_LINKED)) {
801 : 0 : ret = GST_FLOW_NOT_LINKED;
802 [ # # ][ # # ]: 0 : } else if ((enc->srcpad_last_return == GST_FLOW_WRONG_STATE) &&
803 : 0 : (enc->wvcsrcpad_last_return == GST_FLOW_WRONG_STATE)) {
804 : 0 : ret = GST_FLOW_WRONG_STATE;
805 : : } else {
806 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (enc, LIBRARY, ENCODE, (NULL),
[ # # ][ # # ]
807 : : ("encoding samples failed"));
808 : 0 : ret = GST_FLOW_ERROR;
809 : : }
810 : : }
811 : :
812 : 2001 : gst_buffer_unref (buf);
813 : 2001 : gst_object_unref (enc);
814 : 2001 : return ret;
815 : : }
816 : :
817 : : static void
818 : 2 : gst_wavpack_enc_rewrite_first_block (GstWavpackEnc * enc)
819 : : {
820 : 2 : GstEvent *event = gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES,
821 : : 0, GST_BUFFER_OFFSET_NONE, 0);
822 : : gboolean ret;
823 : :
824 [ - + ]: 2 : g_return_if_fail (enc);
825 [ - + ]: 2 : g_return_if_fail (enc->first_block);
826 : :
827 : : /* update the sample count in the first block */
828 : 2 : WavpackUpdateNumSamples (enc->wp_context, enc->first_block);
829 : :
830 : : /* try to seek to the beginning of the output */
831 : 2 : ret = gst_pad_push_event (enc->srcpad, event);
832 [ + - ]: 2 : if (ret) {
833 : : /* try to rewrite the first block */
834 [ - + ]: 2 : GST_DEBUG_OBJECT (enc, "rewriting first block ...");
835 : 2 : enc->wv_id.passthrough = TRUE;
836 : 2 : ret = gst_wavpack_enc_push_block (&enc->wv_id,
837 : : enc->first_block, enc->first_block_size);
838 : 2 : enc->wv_id.passthrough = FALSE;
839 : : } else {
840 [ # # ]: 2 : GST_WARNING_OBJECT (enc, "rewriting of first block failed. "
841 : : "Seeking to first block failed!");
842 : : }
843 : : }
844 : :
845 : : static gboolean
846 : 4 : gst_wavpack_enc_sink_event (GstPad * pad, GstEvent * event)
847 : : {
848 : 4 : GstWavpackEnc *enc = GST_WAVPACK_ENC (gst_pad_get_parent (pad));
849 : 4 : gboolean ret = TRUE;
850 : :
851 [ - + ]: 4 : GST_DEBUG ("Received %s event on sinkpad", GST_EVENT_TYPE_NAME (event));
852 : :
853 [ + + + ]: 4 : switch (GST_EVENT_TYPE (event)) {
854 : : case GST_EVENT_EOS:
855 : : /* Encode all remaining samples and flush them to the src pads */
856 : 2 : WavpackFlushSamples (enc->wp_context);
857 : :
858 : : /* Drop all remaining data, this is no complete block otherwise
859 : : * it would've been pushed already */
860 [ - + ]: 2 : if (enc->pending_buffer) {
861 : 0 : gst_object_unref (enc->pending_buffer);
862 : 0 : enc->pending_buffer = NULL;
863 : 0 : enc->pending_offset = 0;
864 : : }
865 : :
866 : : /* write the MD5 sum if we have to write one */
867 [ - + ][ # # ]: 2 : if ((enc->md5) && (enc->md5_context)) {
868 : : guint8 md5_digest[16];
869 : 0 : gsize digest_len = sizeof (md5_digest);
870 : :
871 : 0 : g_checksum_get_digest (enc->md5_context, md5_digest, &digest_len);
872 [ # # ]: 0 : if (digest_len == sizeof (md5_digest))
873 : 0 : WavpackStoreMD5Sum (enc->wp_context, md5_digest);
874 : : else
875 [ # # ]: 0 : GST_WARNING_OBJECT (enc, "Calculating MD5 digest failed");
876 : : }
877 : :
878 : : /* Try to rewrite the first frame with the correct sample number */
879 [ + - ]: 2 : if (enc->first_block)
880 : 2 : gst_wavpack_enc_rewrite_first_block (enc);
881 : :
882 : : /* close the context if not already happened */
883 [ + - ]: 2 : if (enc->wp_context) {
884 : 2 : WavpackCloseFile (enc->wp_context);
885 : 2 : enc->wp_context = NULL;
886 : : }
887 : :
888 : 2 : ret = gst_pad_event_default (pad, event);
889 : 2 : break;
890 : : case GST_EVENT_NEWSEGMENT:
891 [ - + ]: 1 : if (enc->wp_context) {
892 [ # # ]: 0 : GST_WARNING_OBJECT (enc, "got NEWSEGMENT after encoding "
893 : : "already started");
894 : : }
895 : : /* drop NEWSEGMENT events, we create our own when pushing
896 : : * the first buffer to the pads */
897 : 1 : gst_event_unref (event);
898 : 1 : ret = TRUE;
899 : 1 : break;
900 : : default:
901 : 1 : ret = gst_pad_event_default (pad, event);
902 : 1 : break;
903 : : }
904 : :
905 : 4 : gst_object_unref (enc);
906 : 4 : return ret;
907 : : }
908 : :
909 : : static GstStateChangeReturn
910 : 47 : gst_wavpack_enc_change_state (GstElement * element, GstStateChange transition)
911 : : {
912 : 47 : GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
913 : 47 : GstWavpackEnc *enc = GST_WAVPACK_ENC (element);
914 : :
915 [ + + + ]: 47 : switch (transition) {
916 : : case GST_STATE_CHANGE_NULL_TO_READY:
917 : : /* set the last returned GstFlowReturns of the two pads to GST_FLOW_OK
918 : : * as they're only set to something else in WavpackPackSamples() or more
919 : : * specific gst_wavpack_enc_push_block() and nothing happened there yet */
920 : 6 : enc->srcpad_last_return = enc->wvcsrcpad_last_return = GST_FLOW_OK;
921 : 6 : break;
922 : : case GST_STATE_CHANGE_READY_TO_PAUSED:
923 : 9 : break;
924 : : case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
925 : : default:
926 : 32 : break;
927 : : }
928 : :
929 : 47 : ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
930 : :
931 [ + + + + ]: 47 : switch (transition) {
932 : : case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
933 : 8 : break;
934 : : case GST_STATE_CHANGE_PAUSED_TO_READY:
935 : 9 : gst_wavpack_enc_reset (enc);
936 : 9 : break;
937 : : case GST_STATE_CHANGE_READY_TO_NULL:
938 : 6 : break;
939 : : default:
940 : 24 : break;
941 : : }
942 : :
943 : 47 : return ret;
944 : : }
945 : :
946 : : static void
947 : 0 : gst_wavpack_enc_set_property (GObject * object, guint prop_id,
948 : : const GValue * value, GParamSpec * pspec)
949 : : {
950 : 0 : GstWavpackEnc *enc = GST_WAVPACK_ENC (object);
951 : :
952 [ # # # # : 0 : switch (prop_id) {
# # # # ]
953 : : case ARG_MODE:
954 : 0 : enc->mode = g_value_get_enum (value);
955 : 0 : break;
956 : : case ARG_BITRATE:{
957 : 0 : guint val = g_value_get_uint (value);
958 : :
959 [ # # ][ # # ]: 0 : if ((val >= 24000) && (val <= 9600000)) {
960 : 0 : enc->bitrate = val;
961 : 0 : enc->bps = 0.0;
962 : : } else {
963 : 0 : enc->bitrate = 0;
964 : 0 : enc->bps = 0.0;
965 : : }
966 : 0 : break;
967 : : }
968 : : case ARG_BITSPERSAMPLE:{
969 : 0 : gdouble val = g_value_get_double (value);
970 : :
971 [ # # ][ # # ]: 0 : if ((val >= 2.0) && (val <= 24.0)) {
972 : 0 : enc->bps = val;
973 : 0 : enc->bitrate = 0;
974 : : } else {
975 : 0 : enc->bps = 0.0;
976 : 0 : enc->bitrate = 0;
977 : : }
978 : 0 : break;
979 : : }
980 : : case ARG_CORRECTION_MODE:
981 : 0 : enc->correction_mode = g_value_get_enum (value);
982 : 0 : break;
983 : : case ARG_MD5:
984 : 0 : enc->md5 = g_value_get_boolean (value);
985 : 0 : break;
986 : : case ARG_EXTRA_PROCESSING:
987 : 0 : enc->extra_processing = g_value_get_uint (value);
988 : 0 : break;
989 : : case ARG_JOINT_STEREO_MODE:
990 : 0 : enc->joint_stereo_mode = g_value_get_enum (value);
991 : 0 : break;
992 : : default:
993 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
994 : 0 : break;
995 : : }
996 : 0 : }
997 : :
998 : : static void
999 : 0 : gst_wavpack_enc_get_property (GObject * object, guint prop_id, GValue * value,
1000 : : GParamSpec * pspec)
1001 : : {
1002 : 0 : GstWavpackEnc *enc = GST_WAVPACK_ENC (object);
1003 : :
1004 [ # # # # : 0 : switch (prop_id) {
# # # # ]
1005 : : case ARG_MODE:
1006 : 0 : g_value_set_enum (value, enc->mode);
1007 : 0 : break;
1008 : : case ARG_BITRATE:
1009 [ # # ]: 0 : if (enc->bps == 0.0) {
1010 : 0 : g_value_set_uint (value, enc->bitrate);
1011 : : } else {
1012 : 0 : g_value_set_uint (value, 0);
1013 : : }
1014 : 0 : break;
1015 : : case ARG_BITSPERSAMPLE:
1016 [ # # ]: 0 : if (enc->bitrate == 0) {
1017 : 0 : g_value_set_double (value, enc->bps);
1018 : : } else {
1019 : 0 : g_value_set_double (value, 0.0);
1020 : : }
1021 : 0 : break;
1022 : : case ARG_CORRECTION_MODE:
1023 : 0 : g_value_set_enum (value, enc->correction_mode);
1024 : 0 : break;
1025 : : case ARG_MD5:
1026 : 0 : g_value_set_boolean (value, enc->md5);
1027 : 0 : break;
1028 : : case ARG_EXTRA_PROCESSING:
1029 : 0 : g_value_set_uint (value, enc->extra_processing);
1030 : 0 : break;
1031 : : case ARG_JOINT_STEREO_MODE:
1032 : 0 : g_value_set_enum (value, enc->joint_stereo_mode);
1033 : 0 : break;
1034 : : default:
1035 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1036 : 0 : break;
1037 : : }
1038 : 0 : }
1039 : :
1040 : : gboolean
1041 : 11 : gst_wavpack_enc_plugin_init (GstPlugin * plugin)
1042 : : {
1043 [ - + ]: 11 : if (!gst_element_register (plugin, "wavpackenc",
1044 : : GST_RANK_NONE, GST_TYPE_WAVPACK_ENC))
1045 : 0 : return FALSE;
1046 : :
1047 [ + - ]: 11 : GST_DEBUG_CATEGORY_INIT (gst_wavpack_enc_debug, "wavpack_enc", 0,
1048 : : "Wavpack encoder");
1049 : :
1050 : 11 : return TRUE;
1051 : : }
|