1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */ 2 /* GStreamer 3 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> 4 * Copyright (C) <2006> Nokia Corporation, Stefan Kost <stefan.kost@nokia.com>. 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., 51 Franklin St, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 */ 21 22 /** 23 * SECTION:element-wavparse 24 * 25 * Parse a .wav file into raw or compressed audio. 26 * 27 * Wavparse supports both push and pull mode operations, making it possible to 28 * stream from a network source. 29 * 30 * <refsect2> 31 * <title>Example launch line</title> 32 * |[ 33 * gst-launch-1.0 filesrc location=sine.wav ! wavparse ! audioconvert ! alsasink 34 * ]| Read a wav file and output to the soundcard using the ALSA element. The 35 * wav file is assumed to contain raw uncompressed samples. 36 * |[ 37 * gst-launch-1.0 gnomevfssrc location=http://www.example.org/sine.wav ! queue ! wavparse ! audioconvert ! alsasink 38 * ]| Stream data from a network url. 39 * </refsect2> 40 */ 41 42 /* 43 * TODO: 44 * http://replaygain.hydrogenaudio.org/file_format_wav.html 45 */ 46 47 #ifdef HAVE_CONFIG_H 48 #include "config.h" 49 #endif 50 51 #include <string.h> 52 #include <math.h> 53 54 #include "gstwavparse.h" 55 #include "gst/riff/riff-media.h" 56 #include <gst/base/gsttypefindhelper.h> 57 #include <gst/pbutils/descriptions.h> 58 #include <gst/gst-i18n-plugin.h> 59 60 #ifdef GSTREAMER_LITE 61 #include <fxplugins_common.h> 62 #endif // GSTREAMER_LITE 63 64 GST_DEBUG_CATEGORY_STATIC (wavparse_debug); 65 #define GST_CAT_DEFAULT (wavparse_debug) 66 67 /* Data size chunk of RF64, 68 * see http://tech.ebu.ch/docs/tech/tech3306-2009.pdf */ 69 #define GST_RS64_TAG_DS64 GST_MAKE_FOURCC ('d','s','6','4') 70 71 static void gst_wavparse_dispose (GObject * object); 72 73 static gboolean gst_wavparse_sink_activate (GstPad * sinkpad, 74 GstObject * parent); 75 static gboolean gst_wavparse_sink_activate_mode (GstPad * sinkpad, 76 GstObject * parent, GstPadMode mode, gboolean active); 77 static gboolean gst_wavparse_send_event (GstElement * element, 78 GstEvent * event); 79 static GstStateChangeReturn gst_wavparse_change_state (GstElement * element, 80 GstStateChange transition); 81 #ifdef GSTREAMER_LITE 82 static gboolean gst_wavparse_sink_query (GstPad * pad, GstObject *parent, GstQuery * query); 83 #endif // GSTREAMER_LITE 84 85 static gboolean gst_wavparse_pad_query (GstPad * pad, GstObject * parent, 86 GstQuery * query); 87 static gboolean gst_wavparse_pad_convert (GstPad * pad, GstFormat src_format, 88 gint64 src_value, GstFormat * dest_format, gint64 * dest_value); 89 90 static GstFlowReturn gst_wavparse_chain (GstPad * pad, GstObject * parent, 91 GstBuffer * buf); 92 static gboolean gst_wavparse_sink_event (GstPad * pad, GstObject * parent, 93 GstEvent * event); 94 static void gst_wavparse_loop (GstPad * pad); 95 static gboolean gst_wavparse_srcpad_event (GstPad * pad, GstObject * parent, 96 GstEvent * event); 97 98 static void gst_wavparse_set_property (GObject * object, guint prop_id, 99 const GValue * value, GParamSpec * pspec); 100 static void gst_wavparse_get_property (GObject * object, guint prop_id, 101 GValue * value, GParamSpec * pspec); 102 103 #define DEFAULT_IGNORE_LENGTH FALSE 104 105 enum 106 { 107 PROP_0, 108 PROP_IGNORE_LENGTH, 109 }; 110 111 static GstStaticPadTemplate sink_template_factory = 112 GST_STATIC_PAD_TEMPLATE ("sink", 113 GST_PAD_SINK, 114 GST_PAD_ALWAYS, 115 GST_STATIC_CAPS ("audio/x-wav") 116 ); 117 118 #define DEBUG_INIT \ 119 GST_DEBUG_CATEGORY_INIT (wavparse_debug, "wavparse", 0, "WAV parser"); 120 121 #define gst_wavparse_parent_class parent_class 122 G_DEFINE_TYPE_WITH_CODE (GstWavParse, gst_wavparse, GST_TYPE_ELEMENT, 123 DEBUG_INIT); 124 125 typedef struct 126 { 127 /* Offset Size Description Value 128 * 0x00 4 ID unique identification value 129 * 0x04 4 Position play order position 130 * 0x08 4 Data Chunk ID RIFF ID of corresponding data chunk 131 * 0x0c 4 Chunk Start Byte Offset of Data Chunk * 132 * 0x10 4 Block Start Byte Offset to sample of First Channel 133 * 0x14 4 Sample Offset Byte Offset to sample byte of First Channel 134 */ 135 guint32 id; 136 guint32 position; 137 guint32 data_chunk_id; 138 guint32 chunk_start; 139 guint32 block_start; 140 guint32 sample_offset; 141 } GstWavParseCue; 142 143 typedef struct 144 { 145 /* Offset Size Description Value 146 * 0x08 4 Cue Point ID 0 - 0xFFFFFFFF 147 * 0x0c Text 148 */ 149 guint32 cue_point_id; 150 gchar *text; 151 } GstWavParseLabl, GstWavParseNote; 152 153 static void 154 gst_wavparse_class_init (GstWavParseClass * klass) 155 { 156 GstElementClass *gstelement_class; 157 GObjectClass *object_class; 158 GstPadTemplate *src_template; 159 160 gstelement_class = (GstElementClass *) klass; 161 object_class = (GObjectClass *) klass; 162 163 parent_class = g_type_class_peek_parent (klass); 164 165 object_class->dispose = gst_wavparse_dispose; 166 167 object_class->set_property = gst_wavparse_set_property; 168 object_class->get_property = gst_wavparse_get_property; 169 170 /** 171 * GstWavParse:ignore-length: 172 * 173 * This selects whether the length found in a data chunk 174 * should be ignored. This may be useful for streamed audio 175 * where the length is unknown until the end of streaming, 176 * and various software/hardware just puts some random value 177 * in there and hopes it doesn't break too much. 178 */ 179 g_object_class_install_property (object_class, PROP_IGNORE_LENGTH, 180 g_param_spec_boolean ("ignore-length", 181 "Ignore length", 182 "Ignore length from the Wave header", 183 DEFAULT_IGNORE_LENGTH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) 184 ); 185 186 gstelement_class->change_state = gst_wavparse_change_state; 187 gstelement_class->send_event = gst_wavparse_send_event; 188 189 /* register pads */ 190 gst_element_class_add_static_pad_template (gstelement_class, 191 &sink_template_factory); 192 193 src_template = gst_pad_template_new ("src", GST_PAD_SRC, 194 GST_PAD_ALWAYS, gst_riff_create_audio_template_caps ()); 195 gst_element_class_add_pad_template (gstelement_class, src_template); 196 197 gst_element_class_set_static_metadata (gstelement_class, "WAV audio demuxer", 198 "Codec/Demuxer/Audio", 199 "Parse a .wav file into raw audio", 200 "Erik Walthinsen <omega@cse.ogi.edu>"); 201 } 202 203 static void 204 gst_wavparse_notes_free (GstWavParseNote * note) 205 { 206 if (note) 207 g_free (note->text); 208 g_free (note); 209 } 210 211 static void 212 gst_wavparse_labls_free (GstWavParseLabl * labl) 213 { 214 if (labl) 215 g_free (labl->text); 216 g_free (labl); 217 } 218 219 static void 220 gst_wavparse_reset (GstWavParse * wav) 221 { 222 wav->state = GST_WAVPARSE_START; 223 224 /* These will all be set correctly in the fmt chunk */ 225 wav->depth = 0; 226 wav->rate = 0; 227 wav->width = 0; 228 wav->channels = 0; 229 wav->blockalign = 0; 230 wav->bps = 0; 231 wav->fact = 0; 232 wav->offset = 0; 233 wav->end_offset = 0; 234 wav->dataleft = 0; 235 wav->datasize = 0; 236 wav->datastart = 0; 237 wav->chunk_size = 0; 238 wav->duration = 0; 239 wav->got_fmt = FALSE; 240 wav->first = TRUE; 241 242 if (wav->seek_event) 243 gst_event_unref (wav->seek_event); 244 wav->seek_event = NULL; 245 if (wav->adapter) { 246 gst_adapter_clear (wav->adapter); 247 g_object_unref (wav->adapter); 248 wav->adapter = NULL; 249 } 250 if (wav->tags) 251 gst_tag_list_unref (wav->tags); 252 wav->tags = NULL; 253 if (wav->toc) 254 gst_toc_unref (wav->toc); 255 wav->toc = NULL; 256 if (wav->cues) 257 g_list_free_full (wav->cues, g_free); 258 wav->cues = NULL; 259 if (wav->labls) 260 g_list_free_full (wav->labls, (GDestroyNotify) gst_wavparse_labls_free); 261 wav->labls = NULL; 262 if (wav->notes) 263 g_list_free_full (wav->notes, (GDestroyNotify) gst_wavparse_notes_free); 264 wav->notes = NULL; 265 if (wav->caps) 266 gst_caps_unref (wav->caps); 267 wav->caps = NULL; 268 if (wav->start_segment) 269 gst_event_unref (wav->start_segment); 270 wav->start_segment = NULL; 271 } 272 273 static void 274 gst_wavparse_dispose (GObject * object) 275 { 276 GstWavParse *wav = GST_WAVPARSE (object); 277 278 GST_DEBUG_OBJECT (wav, "WAV: Dispose"); 279 gst_wavparse_reset (wav); 280 281 G_OBJECT_CLASS (parent_class)->dispose (object); 282 } 283 284 static void 285 gst_wavparse_init (GstWavParse * wavparse) 286 { 287 #ifdef GSTREAMER_LITE 288 GstElementClass *klass = GST_ELEMENT_GET_CLASS (wavparse); 289 GstPadTemplate *src_template; 290 #endif // GSTREAMER_LITE 291 292 gst_wavparse_reset (wavparse); 293 294 /* sink */ 295 wavparse->sinkpad = 296 gst_pad_new_from_static_template (&sink_template_factory, "sink"); 297 gst_pad_set_activate_function (wavparse->sinkpad, 298 GST_DEBUG_FUNCPTR (gst_wavparse_sink_activate)); 299 gst_pad_set_activatemode_function (wavparse->sinkpad, 300 GST_DEBUG_FUNCPTR (gst_wavparse_sink_activate_mode)); 301 gst_pad_set_chain_function (wavparse->sinkpad, 302 GST_DEBUG_FUNCPTR (gst_wavparse_chain)); 303 gst_pad_set_event_function (wavparse->sinkpad, 304 GST_DEBUG_FUNCPTR (gst_wavparse_sink_event)); 305 306 #ifdef GSTREAMER_LITE 307 gst_pad_set_query_function (wavparse->sinkpad, 308 GST_DEBUG_FUNCPTR (gst_wavparse_sink_query)); 309 #endif // GSTREAMER_LITE 310 311 gst_element_add_pad (GST_ELEMENT_CAST (wavparse), wavparse->sinkpad); 312 313 /* src */ 314 wavparse->srcpad = 315 gst_pad_new_from_template (gst_element_class_get_pad_template 316 (GST_ELEMENT_GET_CLASS (wavparse), "src"), "src"); 317 gst_pad_use_fixed_caps (wavparse->srcpad); 318 gst_pad_set_query_function (wavparse->srcpad, 319 GST_DEBUG_FUNCPTR (gst_wavparse_pad_query)); 320 gst_pad_set_event_function (wavparse->srcpad, 321 GST_DEBUG_FUNCPTR (gst_wavparse_srcpad_event)); 322 gst_element_add_pad (GST_ELEMENT_CAST (wavparse), wavparse->srcpad); 323 } 324 325 static gboolean 326 gst_wavparse_parse_file_header (GstElement * element, GstBuffer * buf) 327 { 328 guint32 doctype; 329 330 if (!gst_riff_parse_file_header (element, buf, &doctype)) 331 return FALSE; 332 333 if (doctype != GST_RIFF_RIFF_WAVE) 334 goto not_wav; 335 336 return TRUE; 337 338 /* ERRORS */ 339 not_wav: 340 { 341 GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL), 342 ("File is not a WAVE file: 0x%" G_GINT32_MODIFIER "x", doctype)); 343 return FALSE; 344 } 345 } 346 347 static GstFlowReturn 348 gst_wavparse_stream_init (GstWavParse * wav) 349 { 350 GstFlowReturn res; 351 GstBuffer *buf = NULL; 352 353 if ((res = gst_pad_pull_range (wav->sinkpad, 354 wav->offset, 12, &buf)) != GST_FLOW_OK) 355 return res; 356 else if (!gst_wavparse_parse_file_header (GST_ELEMENT_CAST (wav), buf)) 357 return GST_FLOW_ERROR; 358 359 wav->offset += 12; 360 361 return GST_FLOW_OK; 362 } 363 364 static gboolean 365 gst_wavparse_time_to_bytepos (GstWavParse * wav, gint64 ts, gint64 * bytepos) 366 { 367 /* -1 always maps to -1 */ 368 if (ts == -1) { 369 *bytepos = -1; 370 return TRUE; 371 } 372 373 /* 0 always maps to 0 */ 374 if (ts == 0) { 375 *bytepos = 0; 376 return TRUE; 377 } 378 379 if (wav->bps > 0) { 380 *bytepos = gst_util_uint64_scale_ceil (ts, (guint64) wav->bps, GST_SECOND); 381 return TRUE; 382 } else if (wav->fact) { 383 guint64 bps = gst_util_uint64_scale (wav->datasize, wav->rate, wav->fact); 384 *bytepos = gst_util_uint64_scale_ceil (ts, bps, GST_SECOND); 385 return TRUE; 386 } 387 388 return FALSE; 389 } 390 391 /* This function is used to perform seeks on the element. 392 * 393 * It also works when event is NULL, in which case it will just 394 * start from the last configured segment. This technique is 395 * used when activating the element and to perform the seek in 396 * READY. 397 */ 398 static gboolean 399 gst_wavparse_perform_seek (GstWavParse * wav, GstEvent * event) 400 { 401 gboolean res; 402 gdouble rate; 403 GstFormat format, bformat; 404 GstSeekFlags flags; 405 GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type; 406 gint64 cur, stop, upstream_size; 407 gboolean flush; 408 gboolean update; 409 GstSegment seeksegment = { 0, }; 410 gint64 last_stop; 411 guint32 seqnum = 0; 412 413 if (event) { 414 GST_DEBUG_OBJECT (wav, "doing seek with event"); 415 416 gst_event_parse_seek (event, &rate, &format, &flags, 417 &cur_type, &cur, &stop_type, &stop); 418 seqnum = gst_event_get_seqnum (event); 419 420 /* no negative rates yet */ 421 if (rate < 0.0) 422 goto negative_rate; 423 424 if (format != wav->segment.format) { 425 GST_INFO_OBJECT (wav, "converting seek-event from %s to %s", 426 gst_format_get_name (format), 427 gst_format_get_name (wav->segment.format)); 428 res = TRUE; 429 if (cur_type != GST_SEEK_TYPE_NONE) 430 res = 431 gst_pad_query_convert (wav->srcpad, format, cur, 432 wav->segment.format, &cur); 433 if (res && stop_type != GST_SEEK_TYPE_NONE) 434 res = 435 gst_pad_query_convert (wav->srcpad, format, stop, 436 wav->segment.format, &stop); 437 if (!res) 438 goto no_format; 439 440 format = wav->segment.format; 441 } 442 } else { 443 GST_DEBUG_OBJECT (wav, "doing seek without event"); 444 flags = 0; 445 rate = 1.0; 446 cur_type = GST_SEEK_TYPE_SET; 447 stop_type = GST_SEEK_TYPE_SET; 448 } 449 450 /* in push mode, we must delegate to upstream */ 451 if (wav->streaming) { 452 gboolean res = FALSE; 453 454 /* if streaming not yet started; only prepare initial newsegment */ 455 if (!event || wav->state != GST_WAVPARSE_DATA) { 456 if (wav->start_segment) 457 gst_event_unref (wav->start_segment); 458 wav->start_segment = gst_event_new_segment (&wav->segment); 459 res = TRUE; 460 } else { 461 /* convert seek positions to byte positions in data sections */ 462 if (format == GST_FORMAT_TIME) { 463 /* should not fail */ 464 if (!gst_wavparse_time_to_bytepos (wav, cur, &cur)) 465 goto no_position; 466 if (!gst_wavparse_time_to_bytepos (wav, stop, &stop)) 467 goto no_position; 468 } 469 /* mind sample boundary and header */ 470 if (cur >= 0) { 471 cur -= (cur % wav->bytes_per_sample); 472 cur += wav->datastart; 473 } 474 if (stop >= 0) { 475 stop -= (stop % wav->bytes_per_sample); 476 stop += wav->datastart; 477 } 478 GST_DEBUG_OBJECT (wav, "Pushing BYTE seek rate %g, " 479 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, 480 stop); 481 /* BYTE seek event */ 482 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur, 483 stop_type, stop); 484 gst_event_set_seqnum (event, seqnum); 485 res = gst_pad_push_event (wav->sinkpad, event); 486 } 487 return res; 488 } 489 490 /* get flush flag */ 491 flush = flags & GST_SEEK_FLAG_FLUSH; 492 493 /* now we need to make sure the streaming thread is stopped. We do this by 494 * either sending a FLUSH_START event downstream which will cause the 495 * streaming thread to stop with a WRONG_STATE. 496 * For a non-flushing seek we simply pause the task, which will happen as soon 497 * as it completes one iteration (and thus might block when the sink is 498 * blocking in preroll). */ 499 if (flush) { 500 GstEvent *fevent; 501 GST_DEBUG_OBJECT (wav, "sending flush start"); 502 503 fevent = gst_event_new_flush_start (); 504 gst_event_set_seqnum (fevent, seqnum); 505 gst_pad_push_event (wav->sinkpad, gst_event_ref (fevent)); 506 gst_pad_push_event (wav->srcpad, fevent); 507 } else { 508 gst_pad_pause_task (wav->sinkpad); 509 } 510 511 /* we should now be able to grab the streaming thread because we stopped it 512 * with the above flush/pause code */ 513 GST_PAD_STREAM_LOCK (wav->sinkpad); 514 515 /* save current position */ 516 last_stop = wav->segment.position; 517 518 GST_DEBUG_OBJECT (wav, "stopped streaming at %" G_GINT64_FORMAT, last_stop); 519 520 /* copy segment, we need this because we still need the old 521 * segment when we close the current segment. */ 522 memcpy (&seeksegment, &wav->segment, sizeof (GstSegment)); 523 524 /* configure the seek parameters in the seeksegment. We will then have the 525 * right values in the segment to perform the seek */ 526 if (event) { 527 GST_DEBUG_OBJECT (wav, "configuring seek"); 528 gst_segment_do_seek (&seeksegment, rate, format, flags, 529 cur_type, cur, stop_type, stop, &update); 530 } 531 532 /* figure out the last position we need to play. If it's configured (stop != 533 * -1), use that, else we play until the total duration of the file */ 534 if ((stop = seeksegment.stop) == -1) 535 stop = seeksegment.duration; 536 537 GST_DEBUG_OBJECT (wav, "cur_type =%d", cur_type); 538 if ((cur_type != GST_SEEK_TYPE_NONE)) { 539 /* bring offset to bytes, if the bps is 0, we have the segment in BYTES and 540 * we can just copy the last_stop. If not, we use the bps to convert TIME to 541 * bytes. */ 542 if (!gst_wavparse_time_to_bytepos (wav, seeksegment.position, 543 (gint64 *) & wav->offset)) 544 wav->offset = seeksegment.position; 545 GST_LOG_OBJECT (wav, "offset=%" G_GUINT64_FORMAT, wav->offset); 546 wav->offset -= (wav->offset % wav->bytes_per_sample); 547 GST_LOG_OBJECT (wav, "offset=%" G_GUINT64_FORMAT, wav->offset); 548 wav->offset += wav->datastart; 549 GST_LOG_OBJECT (wav, "offset=%" G_GUINT64_FORMAT, wav->offset); 550 } else { 551 GST_LOG_OBJECT (wav, "continue from offset=%" G_GUINT64_FORMAT, 552 wav->offset); 553 } 554 555 if (stop_type != GST_SEEK_TYPE_NONE) { 556 if (!gst_wavparse_time_to_bytepos (wav, stop, (gint64 *) & wav->end_offset)) 557 wav->end_offset = stop; 558 GST_LOG_OBJECT (wav, "end_offset=%" G_GUINT64_FORMAT, wav->end_offset); 559 wav->end_offset -= (wav->end_offset % wav->bytes_per_sample); 560 GST_LOG_OBJECT (wav, "end_offset=%" G_GUINT64_FORMAT, wav->end_offset); 561 wav->end_offset += wav->datastart; 562 GST_LOG_OBJECT (wav, "end_offset=%" G_GUINT64_FORMAT, wav->end_offset); 563 } else { 564 GST_LOG_OBJECT (wav, "continue to end_offset=%" G_GUINT64_FORMAT, 565 wav->end_offset); 566 } 567 568 /* make sure filesize is not exceeded due to rounding errors or so, 569 * same precaution as in _stream_headers */ 570 bformat = GST_FORMAT_BYTES; 571 if (gst_pad_peer_query_duration (wav->sinkpad, bformat, &upstream_size)) 572 wav->end_offset = MIN (wav->end_offset, upstream_size); 573 574 if (wav->datasize > 0 && wav->end_offset > wav->datastart + wav->datasize) 575 wav->end_offset = wav->datastart + wav->datasize; 576 577 /* this is the range of bytes we will use for playback */ 578 wav->offset = MIN (wav->offset, wav->end_offset); 579 wav->dataleft = wav->end_offset - wav->offset; 580 581 GST_DEBUG_OBJECT (wav, 582 "seek: rate %lf, offset %" G_GUINT64_FORMAT ", end %" G_GUINT64_FORMAT 583 ", segment %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, rate, wav->offset, 584 wav->end_offset, GST_TIME_ARGS (seeksegment.start), GST_TIME_ARGS (stop)); 585 586 /* prepare for streaming again */ 587 if (flush) { 588 GstEvent *fevent; 589 590 /* if we sent a FLUSH_START, we now send a FLUSH_STOP */ 591 GST_DEBUG_OBJECT (wav, "sending flush stop"); 592 593 fevent = gst_event_new_flush_stop (TRUE); 594 gst_event_set_seqnum (fevent, seqnum); 595 gst_pad_push_event (wav->sinkpad, gst_event_ref (fevent)); 596 gst_pad_push_event (wav->srcpad, fevent); 597 } 598 599 /* now we did the seek and can activate the new segment values */ 600 memcpy (&wav->segment, &seeksegment, sizeof (GstSegment)); 601 602 /* if we're doing a segment seek, post a SEGMENT_START message */ 603 if (wav->segment.flags & GST_SEEK_FLAG_SEGMENT) { 604 gst_element_post_message (GST_ELEMENT_CAST (wav), 605 gst_message_new_segment_start (GST_OBJECT_CAST (wav), 606 wav->segment.format, wav->segment.position)); 607 } 608 609 /* now create the newsegment */ 610 GST_DEBUG_OBJECT (wav, "Creating newsegment from %" G_GINT64_FORMAT 611 " to %" G_GINT64_FORMAT, wav->segment.position, stop); 612 613 /* store the newsegment event so it can be sent from the streaming thread. */ 614 if (wav->start_segment) 615 gst_event_unref (wav->start_segment); 616 wav->start_segment = gst_event_new_segment (&wav->segment); 617 gst_event_set_seqnum (wav->start_segment, seqnum); 618 619 /* mark discont if we are going to stream from another position. */ 620 if (last_stop != wav->segment.position) { 621 GST_DEBUG_OBJECT (wav, "mark DISCONT, we did a seek to another position"); 622 wav->discont = TRUE; 623 } 624 625 /* and start the streaming task again */ 626 if (!wav->streaming) { 627 gst_pad_start_task (wav->sinkpad, (GstTaskFunction) gst_wavparse_loop, 628 wav->sinkpad, NULL); 629 } 630 631 GST_PAD_STREAM_UNLOCK (wav->sinkpad); 632 633 return TRUE; 634 635 /* ERRORS */ 636 negative_rate: 637 { 638 GST_DEBUG_OBJECT (wav, "negative playback rates are not supported yet."); 639 return FALSE; 640 } 641 no_format: 642 { 643 GST_DEBUG_OBJECT (wav, "unsupported format given, seek aborted."); 644 return FALSE; 645 } 646 no_position: 647 { 648 GST_DEBUG_OBJECT (wav, 649 "Could not determine byte position for desired time"); 650 return FALSE; 651 } 652 } 653 654 /* 655 * gst_wavparse_peek_chunk_info: 656 * @wav Wavparse object 657 * @tag holder for tag 658 * @size holder for tag size 659 * 660 * Peek next chunk info (tag and size) 661 * 662 * Returns: %TRUE when the chunk info (header) is available 663 */ 664 static gboolean 665 gst_wavparse_peek_chunk_info (GstWavParse * wav, guint32 * tag, guint32 * size) 666 { 667 const guint8 *data = NULL; 668 669 if (gst_adapter_available (wav->adapter) < 8) 670 return FALSE; 671 672 data = gst_adapter_map (wav->adapter, 8); 673 *tag = GST_READ_UINT32_LE (data); 674 *size = GST_READ_UINT32_LE (data + 4); 675 gst_adapter_unmap (wav->adapter); 676 677 GST_DEBUG ("Next chunk size is %u bytes, type %" GST_FOURCC_FORMAT, *size, 678 GST_FOURCC_ARGS (*tag)); 679 680 return TRUE; 681 } 682 683 /* 684 * gst_wavparse_peek_chunk: 685 * @wav Wavparse object 686 * @tag holder for tag 687 * @size holder for tag size 688 * 689 * Peek enough data for one full chunk 690 * 691 * Returns: %TRUE when the full chunk is available 692 */ 693 static gboolean 694 gst_wavparse_peek_chunk (GstWavParse * wav, guint32 * tag, guint32 * size) 695 { 696 guint32 peek_size = 0; 697 guint available; 698 699 if (!gst_wavparse_peek_chunk_info (wav, tag, size)) 700 return FALSE; 701 702 /* size 0 -> empty data buffer would surprise most callers, 703 * large size -> do not bother trying to squeeze that into adapter, 704 * so we throw poor man's exception, which can be caught if caller really 705 * wants to handle 0 size chunk */ 706 if (!(*size) || (*size) >= (1 << 30)) { 707 GST_INFO ("Invalid/unexpected chunk size %u for tag %" GST_FOURCC_FORMAT, 708 *size, GST_FOURCC_ARGS (*tag)); 709 /* chain should give up */ 710 wav->abort_buffering = TRUE; 711 return FALSE; 712 } 713 peek_size = (*size + 1) & ~1; 714 available = gst_adapter_available (wav->adapter); 715 716 if (available >= (8 + peek_size)) { 717 return TRUE; 718 } else { 719 GST_LOG ("but only %u bytes available now", available); 720 return FALSE; 721 } 722 } 723 724 /* 725 * gst_wavparse_calculate_duration: 726 * @wav: wavparse object 727 * 728 * Calculate duration on demand and store in @wav. Prefer bps, but use fact as a 729 * fallback. 730 * 731 * Returns: %TRUE if duration is available. 732 */ 733 static gboolean 734 gst_wavparse_calculate_duration (GstWavParse * wav) 735 { 736 if (wav->duration > 0) 737 return TRUE; 738 739 if (wav->bps > 0) { 740 GST_INFO_OBJECT (wav, "Got datasize %" G_GUINT64_FORMAT, wav->datasize); 741 wav->duration = 742 gst_util_uint64_scale_ceil (wav->datasize, GST_SECOND, 743 (guint64) wav->bps); 744 GST_INFO_OBJECT (wav, "Got duration (bps) %" GST_TIME_FORMAT, 745 GST_TIME_ARGS (wav->duration)); 746 return TRUE; 747 } else if (wav->fact) { 748 wav->duration = 749 gst_util_uint64_scale_ceil (GST_SECOND, wav->fact, wav->rate); 750 GST_INFO_OBJECT (wav, "Got duration (fact) %" GST_TIME_FORMAT, 751 GST_TIME_ARGS (wav->duration)); 752 return TRUE; 753 } 754 return FALSE; 755 } 756 757 static gboolean 758 gst_waveparse_ignore_chunk (GstWavParse * wav, GstBuffer * buf, guint32 tag, 759 guint32 size) 760 { 761 guint flush; 762 763 if (wav->streaming) { 764 if (!gst_wavparse_peek_chunk (wav, &tag, &size)) 765 return FALSE; 766 } 767 GST_DEBUG_OBJECT (wav, "Ignoring tag %" GST_FOURCC_FORMAT, 768 GST_FOURCC_ARGS (tag)); 769 flush = 8 + ((size + 1) & ~1); 770 wav->offset += flush; 771 if (wav->streaming) { 772 gst_adapter_flush (wav->adapter, flush); 773 } else { 774 gst_buffer_unref (buf); 775 } 776 777 return TRUE; 778 } 779 780 /* 781 * gst_wavparse_cue_chunk: 782 * @wav GstWavParse object 783 * @data holder for data 784 * @size holder for data size 785 * 786 * Parse cue chunk from @data to wav->cues. 787 * 788 * Returns: %TRUE when cue chunk is available 789 */ 790 static gboolean 791 gst_wavparse_cue_chunk (GstWavParse * wav, const guint8 * data, guint32 size) 792 { 793 guint32 i, ncues; 794 GList *cues = NULL; 795 GstWavParseCue *cue; 796 797 if (wav->cues) { 798 GST_WARNING_OBJECT (wav, "found another cue's"); 799 return TRUE; 800 } 801 802 ncues = GST_READ_UINT32_LE (data); 803 804 if (size < 4 + ncues * 24) { 805 GST_WARNING_OBJECT (wav, "broken file %d %d", size, ncues); 806 return FALSE; 807 } 808 809 /* parse data */ 810 data += 4; 811 for (i = 0; i < ncues; i++) { 812 cue = g_new0 (GstWavParseCue, 1); 813 cue->id = GST_READ_UINT32_LE (data); 814 cue->position = GST_READ_UINT32_LE (data + 4); 815 cue->data_chunk_id = GST_READ_UINT32_LE (data + 8); 816 cue->chunk_start = GST_READ_UINT32_LE (data + 12); 817 cue->block_start = GST_READ_UINT32_LE (data + 16); 818 cue->sample_offset = GST_READ_UINT32_LE (data + 20); 819 cues = g_list_append (cues, cue); 820 data += 24; 821 } 822 823 wav->cues = cues; 824 825 return TRUE; 826 } 827 828 /* 829 * gst_wavparse_labl_chunk: 830 * @wav GstWavParse object 831 * @data holder for data 832 * @size holder for data size 833 * 834 * Parse labl from @data to wav->labls. 835 * 836 * Returns: %TRUE when labl chunk is available 837 */ 838 static gboolean 839 gst_wavparse_labl_chunk (GstWavParse * wav, const guint8 * data, guint32 size) 840 { 841 GstWavParseLabl *labl; 842 843 if (size < 5) 844 return FALSE; 845 846 labl = g_new0 (GstWavParseLabl, 1); 847 848 /* parse data */ 849 data += 8; 850 labl->cue_point_id = GST_READ_UINT32_LE (data); 851 labl->text = g_memdup (data + 4, size - 4); 852 853 wav->labls = g_list_append (wav->labls, labl); 854 855 return TRUE; 856 } 857 858 /* 859 * gst_wavparse_note_chunk: 860 * @wav GstWavParse object 861 * @data holder for data 862 * @size holder for data size 863 * 864 * Parse note from @data to wav->notes. 865 * 866 * Returns: %TRUE when note chunk is available 867 */ 868 static gboolean 869 gst_wavparse_note_chunk (GstWavParse * wav, const guint8 * data, guint32 size) 870 { 871 GstWavParseNote *note; 872 873 if (size < 5) 874 return FALSE; 875 876 note = g_new0 (GstWavParseNote, 1); 877 878 /* parse data */ 879 data += 8; 880 note->cue_point_id = GST_READ_UINT32_LE (data); 881 note->text = g_memdup (data + 4, size - 4); 882 883 wav->notes = g_list_append (wav->notes, note); 884 885 return TRUE; 886 } 887 888 /* 889 * gst_wavparse_smpl_chunk: 890 * @wav GstWavParse object 891 * @data holder for data 892 * @size holder for data size 893 * 894 * Parse smpl chunk from @data. 895 * 896 * Returns: %TRUE when cue chunk is available 897 */ 898 static gboolean 899 gst_wavparse_smpl_chunk (GstWavParse * wav, const guint8 * data, guint32 size) 900 { 901 guint32 note_number; 902 903 /* 904 manufacturer_id = GST_READ_UINT32_LE (data); 905 product_id = GST_READ_UINT32_LE (data + 4); 906 sample_period = GST_READ_UINT32_LE (data + 8); 907 */ 908 note_number = GST_READ_UINT32_LE (data + 12); 909 /* 910 pitch_fraction = GST_READ_UINT32_LE (data + 16); 911 SMPTE_format = GST_READ_UINT32_LE (data + 20); 912 SMPTE_offset = GST_READ_UINT32_LE (data + 24); 913 num_sample_loops = GST_READ_UINT32_LE (data + 28); 914 List of Sample Loops, 24 bytes each 915 */ 916 917 if (!wav->tags) 918 wav->tags = gst_tag_list_new_empty (); 919 gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE, 920 GST_TAG_MIDI_BASE_NOTE, (guint) note_number, NULL); 921 return TRUE; 922 } 923 924 /* 925 * gst_wavparse_adtl_chunk: 926 * @wav GstWavParse object 927 * @data holder for data 928 * @size holder for data size 929 * 930 * Parse adtl from @data. 931 * 932 * Returns: %TRUE when adtl chunk is available 933 */ 934 static gboolean 935 gst_wavparse_adtl_chunk (GstWavParse * wav, const guint8 * data, guint32 size) 936 { 937 guint32 ltag, lsize, offset = 0; 938 939 while (size >= 8) { 940 ltag = GST_READ_UINT32_LE (data + offset); 941 lsize = GST_READ_UINT32_LE (data + offset + 4); 942 943 if (lsize + 8 > size) { 944 GST_WARNING_OBJECT (wav, "Invalid adtl size: %u + 8 > %u", lsize, size); 945 return FALSE; 946 } 947 948 switch (ltag) { 949 case GST_RIFF_TAG_labl: 950 gst_wavparse_labl_chunk (wav, data + offset, size); 951 break; 952 case GST_RIFF_TAG_note: 953 gst_wavparse_note_chunk (wav, data + offset, size); 954 break; 955 default: 956 GST_WARNING_OBJECT (wav, "Unknowm adtl %" GST_FOURCC_FORMAT, 957 GST_FOURCC_ARGS (ltag)); 958 GST_MEMDUMP_OBJECT (wav, "Unknowm adtl", &data[offset], lsize); 959 break; 960 } 961 offset += 8 + GST_ROUND_UP_2 (lsize); 962 size -= 8 + GST_ROUND_UP_2 (lsize); 963 } 964 965 return TRUE; 966 } 967 968 static GstTagList * 969 gst_wavparse_get_tags_toc_entry (GstToc * toc, gchar * id) 970 { 971 GstTagList *tags = NULL; 972 GstTocEntry *entry = NULL; 973 974 entry = gst_toc_find_entry (toc, id); 975 if (entry != NULL) { 976 tags = gst_toc_entry_get_tags (entry); 977 if (tags == NULL) { 978 tags = gst_tag_list_new_empty (); 979 gst_toc_entry_set_tags (entry, tags); 980 } 981 } 982 983 return tags; 984 } 985 986 /* 987 * gst_wavparse_create_toc: 988 * @wav GstWavParse object 989 * 990 * Create TOC from wav->cues and wav->labls. 991 */ 992 static gboolean 993 gst_wavparse_create_toc (GstWavParse * wav) 994 { 995 gint64 start, stop; 996 gchar *id; 997 GList *list; 998 GstWavParseCue *cue; 999 GstWavParseLabl *labl; 1000 GstWavParseNote *note; 1001 GstTagList *tags; 1002 GstToc *toc; 1003 GstTocEntry *entry = NULL, *cur_subentry = NULL, *prev_subentry = NULL; 1004 1005 GST_OBJECT_LOCK (wav); 1006 if (wav->toc) { 1007 GST_OBJECT_UNLOCK (wav); 1008 GST_WARNING_OBJECT (wav, "found another TOC"); 1009 return FALSE; 1010 } 1011 1012 if (!wav->cues) { 1013 GST_OBJECT_UNLOCK (wav); 1014 return TRUE; 1015 } 1016 1017 /* FIXME: send CURRENT scope toc too */ 1018 toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL); 1019 1020 /* add cue edition */ 1021 entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, "cue"); 1022 gst_toc_entry_set_start_stop_times (entry, 0, wav->duration); 1023 gst_toc_append_entry (toc, entry); 1024 1025 /* add tracks in cue edition */ 1026 list = wav->cues; 1027 while (list) { 1028 cue = list->data; 1029 prev_subentry = cur_subentry; 1030 /* previous track stop time = current track start time */ 1031 if (prev_subentry != NULL) { 1032 gst_toc_entry_get_start_stop_times (prev_subentry, &start, NULL); 1033 stop = gst_util_uint64_scale_round (cue->position, GST_SECOND, wav->rate); 1034 gst_toc_entry_set_start_stop_times (prev_subentry, start, stop); 1035 } 1036 id = g_strdup_printf ("%08x", cue->id); 1037 cur_subentry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_TRACK, id); 1038 g_free (id); 1039 start = gst_util_uint64_scale_round (cue->position, GST_SECOND, wav->rate); 1040 stop = wav->duration; 1041 gst_toc_entry_set_start_stop_times (cur_subentry, start, stop); 1042 gst_toc_entry_append_sub_entry (entry, cur_subentry); 1043 list = g_list_next (list); 1044 } 1045 1046 /* add tags in tracks */ 1047 list = wav->labls; 1048 while (list) { 1049 labl = list->data; 1050 id = g_strdup_printf ("%08x", labl->cue_point_id); 1051 tags = gst_wavparse_get_tags_toc_entry (toc, id); 1052 g_free (id); 1053 if (tags != NULL) { 1054 gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE, labl->text, 1055 NULL); 1056 } 1057 list = g_list_next (list); 1058 } 1059 list = wav->notes; 1060 while (list) { 1061 note = list->data; 1062 id = g_strdup_printf ("%08x", note->cue_point_id); 1063 tags = gst_wavparse_get_tags_toc_entry (toc, id); 1064 g_free (id); 1065 if (tags != NULL) { 1066 gst_tag_list_add (tags, GST_TAG_MERGE_PREPEND, GST_TAG_COMMENT, 1067 note->text, NULL); 1068 } 1069 list = g_list_next (list); 1070 } 1071 1072 /* send data as TOC */ 1073 wav->toc = toc; 1074 1075 /* send TOC event */ 1076 if (wav->toc) { 1077 GST_OBJECT_UNLOCK (wav); 1078 gst_pad_push_event (wav->srcpad, gst_event_new_toc (wav->toc, FALSE)); 1079 } 1080 1081 return TRUE; 1082 } 1083 1084 #define MAX_BUFFER_SIZE 4096 1085 1086 static gboolean 1087 parse_ds64 (GstWavParse * wav, GstBuffer * buf) 1088 { 1089 GstMapInfo map; 1090 guint32 dataSizeLow, dataSizeHigh; 1091 guint32 sampleCountLow, sampleCountHigh; 1092 1093 gst_buffer_map (buf, &map, GST_MAP_READ); 1094 dataSizeLow = GST_READ_UINT32_LE (map.data + 2 * 4); 1095 dataSizeHigh = GST_READ_UINT32_LE (map.data + 3 * 4); 1096 sampleCountLow = GST_READ_UINT32_LE (map.data + 4 * 4); 1097 sampleCountHigh = GST_READ_UINT32_LE (map.data + 5 * 4); 1098 gst_buffer_unmap (buf, &map); 1099 if (dataSizeHigh != 0xFFFFFFFF && dataSizeLow != 0xFFFFFFFF) { 1100 wav->datasize = ((guint64) dataSizeHigh << 32) | dataSizeLow; 1101 } 1102 if (sampleCountHigh != 0xFFFFFFFF && sampleCountLow != 0xFFFFFFFF) { 1103 wav->fact = ((guint64) sampleCountHigh << 32) | sampleCountLow; 1104 } 1105 1106 GST_DEBUG_OBJECT (wav, "Got 'ds64' TAG, datasize : %" G_GINT64_FORMAT 1107 " fact: %" G_GINT64_FORMAT, wav->datasize, wav->fact); 1108 return TRUE; 1109 } 1110 1111 static GstFlowReturn 1112 gst_wavparse_stream_headers (GstWavParse * wav) 1113 { 1114 GstFlowReturn res = GST_FLOW_OK; 1115 GstBuffer *buf = NULL; 1116 gst_riff_strf_auds *header = NULL; 1117 guint32 tag, size; 1118 gboolean gotdata = FALSE; 1119 GstCaps *caps = NULL; 1120 gchar *codec_name = NULL; 1121 gint64 upstream_size = 0; 1122 GstStructure *s; 1123 1124 /* search for "_fmt" chunk, which must be before "data" */ 1125 while (!wav->got_fmt) { 1126 GstBuffer *extra; 1127 1128 if (wav->streaming) { 1129 if (!gst_wavparse_peek_chunk (wav, &tag, &size)) 1130 return res; 1131 1132 gst_adapter_flush (wav->adapter, 8); 1133 wav->offset += 8; 1134 1135 if (size) { 1136 buf = gst_adapter_take_buffer (wav->adapter, size); 1137 if (size & 1) 1138 gst_adapter_flush (wav->adapter, 1); 1139 wav->offset += GST_ROUND_UP_2 (size); 1140 } else { 1141 buf = gst_buffer_new (); 1142 } 1143 } else { 1144 if ((res = gst_riff_read_chunk (GST_ELEMENT_CAST (wav), wav->sinkpad, 1145 &wav->offset, &tag, &buf)) != GST_FLOW_OK) 1146 return res; 1147 } 1148 1149 if (tag == GST_RS64_TAG_DS64) { 1150 if (!parse_ds64 (wav, buf)) 1151 goto fail; 1152 else 1153 continue; 1154 } 1155 1156 if (tag != GST_RIFF_TAG_fmt) { 1157 GST_DEBUG_OBJECT (wav, "skipping %" GST_FOURCC_FORMAT " chunk", 1158 GST_FOURCC_ARGS (tag)); 1159 gst_buffer_unref (buf); 1160 buf = NULL; 1161 continue; 1162 } 1163 1164 if (!(gst_riff_parse_strf_auds (GST_ELEMENT_CAST (wav), buf, &header, 1165 &extra))) 1166 goto parse_header_error; 1167 1168 buf = NULL; /* parse_strf_auds() took ownership of buffer */ 1169 1170 /* do sanity checks of header fields */ 1171 if (header->channels == 0) 1172 goto no_channels; 1173 if (header->rate == 0) 1174 goto no_rate; 1175 1176 GST_DEBUG_OBJECT (wav, "creating the caps"); 1177 1178 /* Note: gst_riff_create_audio_caps might need to fix values in 1179 * the header header depending on the format, so call it first */ 1180 /* FIXME: Need to handle the channel reorder map */ 1181 caps = gst_riff_create_audio_caps (header->format, NULL, header, extra, 1182 NULL, &codec_name, NULL); 1183 1184 if (extra) 1185 gst_buffer_unref (extra); 1186 1187 if (!caps) 1188 goto unknown_format; 1189 1190 /* If we got raw audio from upstream, we remove the codec_data field, 1191 * which may have been added if the wav header included an extended 1192 * chunk. We want to keep it for non raw audio. 1193 */ 1194 s = gst_caps_get_structure (caps, 0); 1195 if (s && gst_structure_has_name (s, "audio/x-raw")) { 1196 gst_structure_remove_field (s, "codec_data"); 1197 } 1198 1199 /* do more sanity checks of header fields 1200 * (these can be sanitized by gst_riff_create_audio_caps() 1201 */ 1202 wav->format = header->format; 1203 wav->rate = header->rate; 1204 wav->channels = header->channels; 1205 wav->blockalign = header->blockalign; 1206 wav->depth = header->bits_per_sample; 1207 wav->av_bps = header->av_bps; 1208 wav->vbr = FALSE; 1209 1210 g_free (header); 1211 header = NULL; 1212 1213 /* do format specific handling */ 1214 switch (wav->format) { 1215 case GST_RIFF_WAVE_FORMAT_MPEGL12: 1216 case GST_RIFF_WAVE_FORMAT_MPEGL3: 1217 { 1218 /* Note: workaround for mp2/mp3 embedded in wav, that relies on the 1219 * bitrate inside the mpeg stream */ 1220 GST_INFO ("resetting bps from %u to 0 for mp2/3", wav->av_bps); 1221 wav->bps = 0; 1222 break; 1223 } 1224 case GST_RIFF_WAVE_FORMAT_PCM: 1225 if (wav->blockalign > wav->channels * ((wav->depth + 7) / 8)) 1226 goto invalid_blockalign; 1227 /* fall through */ 1228 default: 1229 if (wav->av_bps > wav->blockalign * wav->rate) 1230 goto invalid_bps; 1231 /* use the configured bps */ 1232 wav->bps = wav->av_bps; 1233 break; 1234 } 1235 1236 wav->width = (wav->blockalign * 8) / wav->channels; 1237 wav->bytes_per_sample = wav->channels * wav->width / 8; 1238 1239 if (wav->bytes_per_sample <= 0) 1240 goto no_bytes_per_sample; 1241 1242 GST_DEBUG_OBJECT (wav, "blockalign = %u", (guint) wav->blockalign); 1243 GST_DEBUG_OBJECT (wav, "width = %u", (guint) wav->width); 1244 GST_DEBUG_OBJECT (wav, "depth = %u", (guint) wav->depth); 1245 GST_DEBUG_OBJECT (wav, "av_bps = %u", (guint) wav->av_bps); 1246 GST_DEBUG_OBJECT (wav, "frequency = %u", (guint) wav->rate); 1247 GST_DEBUG_OBJECT (wav, "channels = %u", (guint) wav->channels); 1248 GST_DEBUG_OBJECT (wav, "bytes_per_sample = %u", wav->bytes_per_sample); 1249 1250 /* bps can be 0 when we don't have a valid bitrate (mostly for compressed 1251 * formats). This will make the element output a BYTE format segment and 1252 * will not timestamp the outgoing buffers. 1253 */ 1254 GST_DEBUG_OBJECT (wav, "bps = %u", (guint) wav->bps); 1255 1256 GST_DEBUG_OBJECT (wav, "caps = %" GST_PTR_FORMAT, caps); 1257 1258 /* create pad later so we can sniff the first few bytes 1259 * of the real data and correct our caps if necessary */ 1260 gst_caps_replace (&wav->caps, caps); 1261 gst_caps_replace (&caps, NULL); 1262 1263 wav->got_fmt = TRUE; 1264 1265 if (wav->tags == NULL) 1266 wav->tags = gst_tag_list_new_empty (); 1267 1268 { 1269 GstCaps *templ_caps = gst_pad_get_pad_template_caps (wav->sinkpad); 1270 gst_pb_utils_add_codec_description_to_tag_list (wav->tags, 1271 GST_TAG_CONTAINER_FORMAT, templ_caps); 1272 gst_caps_unref (templ_caps); 1273 } 1274 1275 /* If bps is nonzero, then we do have a valid bitrate that can be 1276 * announced in a tag list. */ 1277 if (wav->bps) { 1278 guint bitrate = wav->bps * 8; 1279 gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE, 1280 GST_TAG_BITRATE, bitrate, NULL); 1281 } 1282 1283 if (codec_name) { 1284 gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE, 1285 GST_TAG_AUDIO_CODEC, codec_name, NULL); 1286 1287 g_free (codec_name); 1288 codec_name = NULL; 1289 } 1290 1291 } 1292 1293 gst_pad_peer_query_duration (wav->sinkpad, GST_FORMAT_BYTES, &upstream_size); 1294 GST_DEBUG_OBJECT (wav, "upstream size %" G_GUINT64_FORMAT, upstream_size); 1295 1296 /* loop headers until we get data */ 1297 while (!gotdata) { 1298 if (wav->streaming) { 1299 if (!gst_wavparse_peek_chunk_info (wav, &tag, &size)) 1300 goto exit; 1301 } else { 1302 GstMapInfo map; 1303 1304 buf = NULL; 1305 if ((res = 1306 gst_pad_pull_range (wav->sinkpad, wav->offset, 8, 1307 &buf)) != GST_FLOW_OK) 1308 #ifdef GSTREAMER_LITE 1309 if (res == GST_FLOW_FLUSHING) 1310 goto exit; 1311 else 1312 #endif // GSTREAMER_LITE 1313 goto header_read_error; 1314 gst_buffer_map (buf, &map, GST_MAP_READ); 1315 tag = GST_READ_UINT32_LE (map.data); 1316 size = GST_READ_UINT32_LE (map.data + 4); 1317 gst_buffer_unmap (buf, &map); 1318 } 1319 1320 GST_INFO_OBJECT (wav, 1321 "Got TAG: %" GST_FOURCC_FORMAT ", offset %" G_GUINT64_FORMAT ", size %" 1322 G_GUINT32_FORMAT, GST_FOURCC_ARGS (tag), wav->offset, size); 1323 1324 /* Maximum valid size is INT_MAX */ 1325 if (size & 0x80000000) { 1326 GST_WARNING_OBJECT (wav, "Invalid size, clipping to 0x7fffffff"); 1327 size = 0x7fffffff; 1328 } 1329 1330 /* Clip to upstream size if known */ 1331 if (upstream_size > 0 && size + wav->offset > upstream_size) { 1332 GST_WARNING_OBJECT (wav, "Clipping chunk size to file size"); 1333 g_assert (upstream_size >= wav->offset); 1334 size = upstream_size - wav->offset; 1335 } 1336 1337 /* wav is a st00pid format, we don't know for sure where data starts. 1338 * So we have to go bit by bit until we find the 'data' header 1339 */ 1340 switch (tag) { 1341 case GST_RIFF_TAG_data:{ 1342 guint64 size64; 1343 1344 GST_DEBUG_OBJECT (wav, "Got 'data' TAG, size : %u", size); 1345 size64 = size; 1346 if (wav->ignore_length) { 1347 GST_DEBUG_OBJECT (wav, "Ignoring length"); 1348 size64 = 0; 1349 } 1350 if (wav->streaming) { 1351 gst_adapter_flush (wav->adapter, 8); 1352 gotdata = TRUE; 1353 } else { 1354 gst_buffer_unref (buf); 1355 } 1356 wav->offset += 8; 1357 wav->datastart = wav->offset; 1358 /* use size from ds64 chunk if available */ 1359 if (size64 == -1 && wav->datasize > 0) { 1360 GST_DEBUG_OBJECT (wav, "Using ds64 datasize"); 1361 size64 = wav->datasize; 1362 } 1363 wav->chunk_size = size64; 1364 1365 /* If size is zero, then the data chunk probably actually extends to 1366 the end of the file */ 1367 if (size64 == 0 && upstream_size) { 1368 size64 = upstream_size - wav->datastart; 1369 } 1370 /* Or the file might be truncated */ 1371 else if (upstream_size) { 1372 size64 = MIN (size64, (upstream_size - wav->datastart)); 1373 } 1374 wav->datasize = size64; 1375 wav->dataleft = size64; 1376 wav->end_offset = size64 + wav->datastart; 1377 if (!wav->streaming) { 1378 /* We will continue parsing tags 'till end */ 1379 wav->offset += size64; 1380 } 1381 GST_DEBUG_OBJECT (wav, "datasize = %" G_GUINT64_FORMAT, size64); 1382 break; 1383 } 1384 case GST_RIFF_TAG_fact:{ 1385 if (wav->fact == 0 && 1386 wav->format != GST_RIFF_WAVE_FORMAT_MPEGL12 && 1387 wav->format != GST_RIFF_WAVE_FORMAT_MPEGL3) { 1388 const guint data_size = 4; 1389 1390 GST_INFO_OBJECT (wav, "Have fact chunk"); 1391 if (size < data_size) { 1392 if (!gst_waveparse_ignore_chunk (wav, buf, tag, size)) { 1393 /* need more data */ 1394 goto exit; 1395 } 1396 GST_DEBUG_OBJECT (wav, "need %u, available %u; ignoring chunk", 1397 data_size, size); 1398 break; 1399 } 1400 /* number of samples (for compressed formats) */ 1401 if (wav->streaming) { 1402 const guint8 *data = NULL; 1403 1404 if (!gst_wavparse_peek_chunk (wav, &tag, &size)) { 1405 goto exit; 1406 } 1407 gst_adapter_flush (wav->adapter, 8); 1408 data = gst_adapter_map (wav->adapter, data_size); 1409 #ifdef GSTREAMER_LITE 1410 if (data == NULL) { 1411 goto header_read_error; 1412 } 1413 #endif // GSTREAMER_LITE 1414 wav->fact = GST_READ_UINT32_LE (data); 1415 gst_adapter_unmap (wav->adapter); 1416 gst_adapter_flush (wav->adapter, GST_ROUND_UP_2 (size)); 1417 } else { 1418 gst_buffer_unref (buf); 1419 buf = NULL; 1420 if ((res = 1421 gst_pad_pull_range (wav->sinkpad, wav->offset + 8, 1422 data_size, &buf)) != GST_FLOW_OK) 1423 #ifdef GSTREAMER_LITE 1424 if (res == GST_FLOW_FLUSHING) 1425 goto exit; 1426 else 1427 #endif // GSTREAMER_LITE 1428 goto header_read_error; 1429 gst_buffer_extract (buf, 0, &wav->fact, 4); 1430 wav->fact = GUINT32_FROM_LE (wav->fact); 1431 gst_buffer_unref (buf); 1432 } 1433 GST_DEBUG_OBJECT (wav, "have fact %" G_GUINT64_FORMAT, wav->fact); 1434 wav->offset += 8 + GST_ROUND_UP_2 (size); 1435 break; 1436 } else { 1437 if (!gst_waveparse_ignore_chunk (wav, buf, tag, size)) { 1438 /* need more data */ 1439 goto exit; 1440 } 1441 } 1442 break; 1443 } 1444 case GST_RIFF_TAG_acid:{ 1445 const gst_riff_acid *acid = NULL; 1446 const guint data_size = sizeof (gst_riff_acid); 1447 gfloat tempo; 1448 1449 GST_INFO_OBJECT (wav, "Have acid chunk"); 1450 if (size < data_size) { 1451 if (!gst_waveparse_ignore_chunk (wav, buf, tag, size)) { 1452 /* need more data */ 1453 goto exit; 1454 } 1455 GST_DEBUG_OBJECT (wav, "need %u, available %u; ignoring chunk", 1456 data_size, size); 1457 break; 1458 } 1459 if (wav->streaming) { 1460 if (!gst_wavparse_peek_chunk (wav, &tag, &size)) { 1461 goto exit; 1462 } 1463 gst_adapter_flush (wav->adapter, 8); 1464 acid = (const gst_riff_acid *) gst_adapter_map (wav->adapter, 1465 data_size); 1466 tempo = acid->tempo; 1467 gst_adapter_unmap (wav->adapter); 1468 } else { 1469 GstMapInfo map; 1470 gst_buffer_unref (buf); 1471 buf = NULL; 1472 if ((res = 1473 gst_pad_pull_range (wav->sinkpad, wav->offset + 8, 1474 size, &buf)) != GST_FLOW_OK) 1475 #ifdef GSTREAMER_LITE 1476 if (res == GST_FLOW_FLUSHING) 1477 goto exit; 1478 else 1479 #endif // GSTREAMER_LITE 1480 goto header_read_error; 1481 gst_buffer_map (buf, &map, GST_MAP_READ); 1482 acid = (const gst_riff_acid *) map.data; 1483 tempo = acid->tempo; 1484 gst_buffer_unmap (buf, &map); 1485 } 1486 /* send data as tags */ 1487 if (!wav->tags) 1488 wav->tags = gst_tag_list_new_empty (); 1489 gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE, 1490 GST_TAG_BEATS_PER_MINUTE, tempo, NULL); 1491 1492 size = GST_ROUND_UP_2 (size); 1493 if (wav->streaming) { 1494 gst_adapter_flush (wav->adapter, size); 1495 } else { 1496 gst_buffer_unref (buf); 1497 } 1498 wav->offset += 8 + size; 1499 break; 1500 } 1501 /* FIXME: all list tags after data are ignored in streaming mode */ 1502 case GST_RIFF_TAG_LIST:{ 1503 guint32 ltag; 1504 1505 if (wav->streaming) { 1506 const guint8 *data = NULL; 1507 1508 if (gst_adapter_available (wav->adapter) < 12) { 1509 goto exit; 1510 } 1511 data = gst_adapter_map (wav->adapter, 12); 1512 ltag = GST_READ_UINT32_LE (data + 8); 1513 gst_adapter_unmap (wav->adapter); 1514 } else { 1515 gst_buffer_unref (buf); 1516 buf = NULL; 1517 if ((res = 1518 gst_pad_pull_range (wav->sinkpad, wav->offset, 12, 1519 &buf)) != GST_FLOW_OK) 1520 #ifdef GSTREAMER_LITE 1521 if (res == GST_FLOW_FLUSHING) 1522 goto exit; 1523 else 1524 #endif // GSTREAMER_LITE 1525 goto header_read_error; 1526 gst_buffer_extract (buf, 8, <ag, 4); 1527 ltag = GUINT32_FROM_LE (ltag); 1528 } 1529 switch (ltag) { 1530 case GST_RIFF_LIST_INFO:{ 1531 const gint data_size = size - 4; 1532 GstTagList *new; 1533 1534 GST_INFO_OBJECT (wav, "Have LIST chunk INFO size %u", data_size); 1535 if (wav->streaming) { 1536 if (!gst_wavparse_peek_chunk (wav, &tag, &size)) { 1537 goto exit; 1538 } 1539 gst_adapter_flush (wav->adapter, 12); 1540 wav->offset += 12; 1541 if (data_size > 0) { 1542 buf = gst_adapter_take_buffer (wav->adapter, data_size); 1543 if (data_size & 1) 1544 gst_adapter_flush (wav->adapter, 1); 1545 } 1546 } else { 1547 wav->offset += 12; 1548 gst_buffer_unref (buf); 1549 buf = NULL; 1550 if (data_size > 0) { 1551 if ((res = 1552 gst_pad_pull_range (wav->sinkpad, wav->offset, 1553 data_size, &buf)) != GST_FLOW_OK) 1554 #ifdef GSTREAMER_LITE 1555 if (res == GST_FLOW_FLUSHING) 1556 goto exit; 1557 else 1558 #endif // GSTREAMER_LITE 1559 goto header_read_error; 1560 } 1561 } 1562 if (data_size > 0) { 1563 /* parse tags */ 1564 gst_riff_parse_info (GST_ELEMENT (wav), buf, &new); 1565 if (new) { 1566 GstTagList *old = wav->tags; 1567 wav->tags = 1568 gst_tag_list_merge (old, new, GST_TAG_MERGE_REPLACE); 1569 if (old) 1570 gst_tag_list_unref (old); 1571 gst_tag_list_unref (new); 1572 } 1573 gst_buffer_unref (buf); 1574 wav->offset += GST_ROUND_UP_2 (data_size); 1575 } 1576 break; 1577 } 1578 case GST_RIFF_LIST_adtl:{ 1579 const gint data_size = size - 4; 1580 1581 GST_INFO_OBJECT (wav, "Have 'adtl' LIST, size %u", data_size); 1582 if (wav->streaming) { 1583 const guint8 *data = NULL; 1584 1585 gst_adapter_flush (wav->adapter, 12); 1586 wav->offset += 12; 1587 data = gst_adapter_map (wav->adapter, data_size); 1588 gst_wavparse_adtl_chunk (wav, data, data_size); 1589 gst_adapter_unmap (wav->adapter); 1590 } else { 1591 GstMapInfo map; 1592 1593 gst_buffer_unref (buf); 1594 buf = NULL; 1595 wav->offset += 12; 1596 if ((res = 1597 gst_pad_pull_range (wav->sinkpad, wav->offset, 1598 data_size, &buf)) != GST_FLOW_OK) 1599 goto header_read_error; 1600 gst_buffer_map (buf, &map, GST_MAP_READ); 1601 gst_wavparse_adtl_chunk (wav, (const guint8 *) map.data, 1602 data_size); 1603 gst_buffer_unmap (buf, &map); 1604 } 1605 wav->offset += GST_ROUND_UP_2 (data_size); 1606 break; 1607 } 1608 default: 1609 GST_WARNING_OBJECT (wav, "Ignoring LIST chunk %" GST_FOURCC_FORMAT, 1610 GST_FOURCC_ARGS (ltag)); 1611 if (!gst_waveparse_ignore_chunk (wav, buf, tag, size)) 1612 /* need more data */ 1613 goto exit; 1614 break; 1615 } 1616 break; 1617 } 1618 case GST_RIFF_TAG_cue:{ 1619 const guint data_size = size; 1620 1621 GST_DEBUG_OBJECT (wav, "Have 'cue' TAG, size : %u", data_size); 1622 if (wav->streaming) { 1623 const guint8 *data = NULL; 1624 1625 if (!gst_wavparse_peek_chunk (wav, &tag, &size)) { 1626 goto exit; 1627 } 1628 gst_adapter_flush (wav->adapter, 8); 1629 wav->offset += 8; 1630 data = gst_adapter_map (wav->adapter, data_size); 1631 if (!gst_wavparse_cue_chunk (wav, data, data_size)) { 1632 goto header_read_error; 1633 } 1634 gst_adapter_unmap (wav->adapter); 1635 } else { 1636 GstMapInfo map; 1637 1638 wav->offset += 8; 1639 gst_buffer_unref (buf); 1640 buf = NULL; 1641 if ((res = 1642 gst_pad_pull_range (wav->sinkpad, wav->offset, 1643 data_size, &buf)) != GST_FLOW_OK) 1644 goto header_read_error; 1645 gst_buffer_map (buf, &map, GST_MAP_READ); 1646 if (!gst_wavparse_cue_chunk (wav, (const guint8 *) map.data, 1647 data_size)) { 1648 goto header_read_error; 1649 } 1650 gst_buffer_unmap (buf, &map); 1651 } 1652 size = GST_ROUND_UP_2 (size); 1653 if (wav->streaming) { 1654 gst_adapter_flush (wav->adapter, size); 1655 } else { 1656 gst_buffer_unref (buf); 1657 } 1658 size = GST_ROUND_UP_2 (size); 1659 wav->offset += size; 1660 break; 1661 } 1662 case GST_RIFF_TAG_smpl:{ 1663 const gint data_size = size; 1664 1665 GST_DEBUG_OBJECT (wav, "Have 'smpl' TAG, size : %u", data_size); 1666 if (wav->streaming) { 1667 const guint8 *data = NULL; 1668 1669 if (!gst_wavparse_peek_chunk (wav, &tag, &size)) { 1670 goto exit; 1671 } 1672 gst_adapter_flush (wav->adapter, 8); 1673 wav->offset += 8; 1674 data = gst_adapter_map (wav->adapter, data_size); 1675 if (!gst_wavparse_smpl_chunk (wav, data, data_size)) { 1676 goto header_read_error; 1677 } 1678 gst_adapter_unmap (wav->adapter); 1679 } else { 1680 GstMapInfo map; 1681 1682 wav->offset += 8; 1683 gst_buffer_unref (buf); 1684 buf = NULL; 1685 if ((res = 1686 gst_pad_pull_range (wav->sinkpad, wav->offset, 1687 data_size, &buf)) != GST_FLOW_OK) 1688 goto header_read_error; 1689 gst_buffer_map (buf, &map, GST_MAP_READ); 1690 if (!gst_wavparse_smpl_chunk (wav, (const guint8 *) map.data, 1691 data_size)) { 1692 goto header_read_error; 1693 } 1694 gst_buffer_unmap (buf, &map); 1695 } 1696 size = GST_ROUND_UP_2 (size); 1697 if (wav->streaming) { 1698 gst_adapter_flush (wav->adapter, size); 1699 } else { 1700 gst_buffer_unref (buf); 1701 } 1702 size = GST_ROUND_UP_2 (size); 1703 wav->offset += size; 1704 break; 1705 } 1706 default: 1707 GST_WARNING_OBJECT (wav, "Ignoring chunk %" GST_FOURCC_FORMAT, 1708 GST_FOURCC_ARGS (tag)); 1709 if (!gst_waveparse_ignore_chunk (wav, buf, tag, size)) 1710 /* need more data */ 1711 goto exit; 1712 break; 1713 } 1714 1715 if (upstream_size && (wav->offset >= upstream_size)) { 1716 /* Now we are gone through the whole file */ 1717 gotdata = TRUE; 1718 } 1719 } 1720 1721 GST_DEBUG_OBJECT (wav, "Finished parsing headers"); 1722 1723 if (wav->bps <= 0 && wav->fact) { 1724 #if 0 1725 /* not a good idea, as for embedded mp2/mp3 we set bps to 0 earlier */ 1726 wav->bps = 1727 (guint32) gst_util_uint64_scale ((guint64) wav->rate, wav->datasize, 1728 (guint64) wav->fact); 1729 GST_INFO_OBJECT (wav, "calculated bps : %u, enabling VBR", wav->bps); 1730 #endif 1731 wav->vbr = TRUE; 1732 } 1733 1734 if (gst_wavparse_calculate_duration (wav)) { 1735 gst_segment_init (&wav->segment, GST_FORMAT_TIME); 1736 if (!wav->ignore_length) 1737 wav->segment.duration = wav->duration; 1738 if (!wav->toc) 1739 gst_wavparse_create_toc (wav); 1740 } else { 1741 /* no bitrate, let downstream peer do the math, we'll feed it bytes. */ 1742 gst_segment_init (&wav->segment, GST_FORMAT_BYTES); 1743 if (!wav->ignore_length) 1744 wav->segment.duration = wav->datasize; 1745 } 1746 1747 /* now we have all the info to perform a pending seek if any, if no 1748 * event, this will still do the right thing and it will also send 1749 * the right newsegment event downstream. */ 1750 gst_wavparse_perform_seek (wav, wav->seek_event); 1751 /* remove pending event */ 1752 gst_event_replace (&wav->seek_event, NULL); 1753 1754 /* we just started, we are discont */ 1755 wav->discont = TRUE; 1756 1757 wav->state = GST_WAVPARSE_DATA; 1758 1759 /* determine reasonable max buffer size, 1760 * that is, buffers not too small either size or time wise 1761 * so we do not end up with too many of them */ 1762 /* var abuse */ 1763 if (gst_wavparse_time_to_bytepos (wav, 40 * GST_MSECOND, &upstream_size)) 1764 wav->max_buf_size = upstream_size; 1765 else 1766 wav->max_buf_size = 0; 1767 wav->max_buf_size = MAX (wav->max_buf_size, MAX_BUFFER_SIZE); 1768 if (wav->blockalign > 0) 1769 wav->max_buf_size -= (wav->max_buf_size % wav->blockalign); 1770 1771 GST_DEBUG_OBJECT (wav, "max buffer size %u", wav->max_buf_size); 1772 1773 return GST_FLOW_OK; 1774 1775 /* ERROR */ 1776 exit: 1777 { 1778 g_free (codec_name); 1779 g_free (header); 1780 if (caps) 1781 gst_caps_unref (caps); 1782 return res; 1783 } 1784 fail: 1785 { 1786 res = GST_FLOW_ERROR; 1787 goto exit; 1788 } 1789 parse_header_error: 1790 { 1791 GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL), 1792 ("Couldn't parse audio header")); 1793 goto fail; 1794 } 1795 no_channels: 1796 { 1797 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), 1798 ("Stream claims to contain no channels - invalid data")); 1799 goto fail; 1800 } 1801 no_rate: 1802 { 1803 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), 1804 ("Stream with sample_rate == 0 - invalid data")); 1805 goto fail; 1806 } 1807 invalid_blockalign: 1808 { 1809 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), 1810 ("Stream claims blockalign = %u, which is more than %u - invalid data", 1811 wav->blockalign, wav->channels * ((wav->depth + 7) / 8))); 1812 goto fail; 1813 } 1814 invalid_bps: 1815 { 1816 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), 1817 ("Stream claims av_bsp = %u, which is more than %u - invalid data", 1818 wav->av_bps, wav->blockalign * wav->rate)); 1819 goto fail; 1820 } 1821 no_bytes_per_sample: 1822 { 1823 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), 1824 ("Could not caluclate bytes per sample - invalid data")); 1825 goto fail; 1826 } 1827 unknown_format: 1828 { 1829 GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL), 1830 ("No caps found for format 0x%x, %u channels, %u Hz", 1831 wav->format, wav->channels, wav->rate)); 1832 goto fail; 1833 } 1834 header_read_error: 1835 { 1836 GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL), 1837 ("Couldn't read in header %d (%s)", res, gst_flow_get_name (res))); 1838 goto fail; 1839 } 1840 } 1841 1842 /* 1843 * Read WAV file tag when streaming 1844 */ 1845 static GstFlowReturn 1846 gst_wavparse_parse_stream_init (GstWavParse * wav) 1847 { 1848 if (gst_adapter_available (wav->adapter) >= 12) { 1849 GstBuffer *tmp; 1850 1851 /* _take flushes the data */ 1852 tmp = gst_adapter_take_buffer (wav->adapter, 12); 1853 1854 GST_DEBUG ("Parsing wav header"); 1855 if (!gst_wavparse_parse_file_header (GST_ELEMENT_CAST (wav), tmp)) 1856 return GST_FLOW_ERROR; 1857 1858 wav->offset += 12; 1859 /* Go to next state */ 1860 wav->state = GST_WAVPARSE_HEADER; 1861 } 1862 return GST_FLOW_OK; 1863 } 1864 1865 /* handle an event sent directly to the element. 1866 * 1867 * This event can be sent either in the READY state or the 1868 * >READY state. The only event of interest really is the seek 1869 * event. 1870 * 1871 * In the READY state we can only store the event and try to 1872 * respect it when going to PAUSED. We assume we are in the 1873 * READY state when our parsing state != GST_WAVPARSE_DATA. 1874 * 1875 * When we are steaming, we can simply perform the seek right 1876 * away. 1877 */ 1878 static gboolean 1879 gst_wavparse_send_event (GstElement * element, GstEvent * event) 1880 { 1881 GstWavParse *wav = GST_WAVPARSE (element); 1882 gboolean res = FALSE; 1883 1884 GST_DEBUG_OBJECT (wav, "received event %s", GST_EVENT_TYPE_NAME (event)); 1885 1886 switch (GST_EVENT_TYPE (event)) { 1887 case GST_EVENT_SEEK: 1888 if (wav->state == GST_WAVPARSE_DATA) { 1889 /* we can handle the seek directly when streaming data */ 1890 res = gst_wavparse_perform_seek (wav, event); 1891 } else { 1892 GST_DEBUG_OBJECT (wav, "queuing seek for later"); 1893 1894 gst_event_replace (&wav->seek_event, event); 1895 1896 /* we always return true */ 1897 res = TRUE; 1898 } 1899 break; 1900 default: 1901 break; 1902 } 1903 gst_event_unref (event); 1904 return res; 1905 } 1906 1907 static gboolean 1908 gst_wavparse_have_dts_caps (const GstCaps * caps, GstTypeFindProbability prob) 1909 { 1910 GstStructure *s; 1911 1912 s = gst_caps_get_structure (caps, 0); 1913 if (!gst_structure_has_name (s, "audio/x-dts")) 1914 return FALSE; 1915 /* typefind behavior for DTS: 1916 * MAXIMUM: multiple frame syncs detected, certainly DTS 1917 * LIKELY: single frame sync at offset 0. Maybe DTS? 1918 * POSSIBLE: single frame sync, not at offset 0. Highly unlikely 1919 * to be DTS. */ 1920 if (prob > GST_TYPE_FIND_LIKELY) 1921 return TRUE; 1922 if (prob <= GST_TYPE_FIND_POSSIBLE) 1923 return FALSE; 1924 /* for maybe, check for at least a valid-looking rate and channels */ 1925 if (!gst_structure_has_field (s, "channels")) 1926 return FALSE; 1927 /* and for extra assurance we could also check the rate from the DTS frame 1928 * against the one in the wav header, but for now let's not do that */ 1929 return gst_structure_has_field (s, "rate"); 1930 } 1931 1932 static GstTagList * 1933 gst_wavparse_get_upstream_tags (GstWavParse * wav, GstTagScope scope) 1934 { 1935 GstTagList *tags = NULL; 1936 GstEvent *ev; 1937 gint i; 1938 1939 i = 0; 1940 while ((ev = gst_pad_get_sticky_event (wav->sinkpad, GST_EVENT_TAG, i++))) { 1941 gst_event_parse_tag (ev, &tags); 1942 if (tags != NULL && gst_tag_list_get_scope (tags) == scope) { 1943 tags = gst_tag_list_copy (tags); 1944 gst_tag_list_remove_tag (tags, GST_TAG_CONTAINER_FORMAT); 1945 gst_event_unref (ev); 1946 break; 1947 } 1948 tags = NULL; 1949 gst_event_unref (ev); 1950 } 1951 return tags; 1952 } 1953 1954 static void 1955 gst_wavparse_add_src_pad (GstWavParse * wav, GstBuffer * buf) 1956 { 1957 GstStructure *s; 1958 GstTagList *tags, *utags; 1959 1960 GST_DEBUG_OBJECT (wav, "adding src pad"); 1961 1962 g_assert (wav->caps != NULL); 1963 1964 s = gst_caps_get_structure (wav->caps, 0); 1965 if (s && gst_structure_has_name (s, "audio/x-raw") && buf != NULL) { 1966 GstTypeFindProbability prob; 1967 GstCaps *tf_caps; 1968 1969 tf_caps = gst_type_find_helper_for_buffer (GST_OBJECT (wav), buf, &prob); 1970 if (tf_caps != NULL) { 1971 GST_LOG ("typefind caps = %" GST_PTR_FORMAT ", P=%d", tf_caps, prob); 1972 if (gst_wavparse_have_dts_caps (tf_caps, prob)) { 1973 GST_INFO_OBJECT (wav, "Found DTS marker in file marked as raw PCM"); 1974 gst_caps_unref (wav->caps); 1975 wav->caps = tf_caps; 1976 1977 gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE, 1978 GST_TAG_AUDIO_CODEC, "dts", NULL); 1979 } else { 1980 GST_DEBUG_OBJECT (wav, "found caps %" GST_PTR_FORMAT " for stream " 1981 "marked as raw PCM audio, but ignoring for now", tf_caps); 1982 gst_caps_unref (tf_caps); 1983 } 1984 } 1985 } 1986 1987 gst_pad_set_caps (wav->srcpad, wav->caps); 1988 1989 if (wav->start_segment) { 1990 GST_DEBUG_OBJECT (wav, "Send start segment event on newpad"); 1991 gst_pad_push_event (wav->srcpad, wav->start_segment); 1992 wav->start_segment = NULL; 1993 } 1994 1995 /* upstream tags, e.g. from id3/ape tag before the wav file; assume for now 1996 * that there'll be only one scope/type of tag list from upstream, if any */ 1997 utags = gst_wavparse_get_upstream_tags (wav, GST_TAG_SCOPE_GLOBAL); 1998 if (utags == NULL) 1999 utags = gst_wavparse_get_upstream_tags (wav, GST_TAG_SCOPE_STREAM); 2000 2001 /* if there's a tag upstream it's probably been added to override the 2002 * tags from inside the wav header, so keep upstream tags if in doubt */ 2003 tags = gst_tag_list_merge (utags, wav->tags, GST_TAG_MERGE_KEEP); 2004 2005 if (wav->tags != NULL) { 2006 gst_tag_list_unref (wav->tags); 2007 wav->tags = NULL; 2008 } 2009 2010 if (utags != NULL) 2011 gst_tag_list_unref (utags); 2012 2013 /* send tags downstream, if any */ 2014 if (tags != NULL) 2015 gst_pad_push_event (wav->srcpad, gst_event_new_tag (tags)); 2016 } 2017 2018 static GstFlowReturn 2019 gst_wavparse_stream_data (GstWavParse * wav) 2020 { 2021 GstBuffer *buf = NULL; 2022 GstFlowReturn res = GST_FLOW_OK; 2023 guint64 desired, obtained; 2024 GstClockTime timestamp, next_timestamp, duration; 2025 guint64 pos, nextpos; 2026 2027 iterate_adapter: 2028 GST_LOG_OBJECT (wav, 2029 "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT " , dataleft: %" 2030 G_GINT64_FORMAT, wav->offset, wav->end_offset, wav->dataleft); 2031 2032 if ((wav->dataleft == 0 || wav->dataleft < wav->blockalign)) { 2033 /* In case chunk size is not declared in the begining get size from the 2034 * file size directly */ 2035 if (wav->chunk_size == 0) { 2036 gint64 upstream_size = 0; 2037 2038 /* Get the size of the file */ 2039 if (!gst_pad_peer_query_duration (wav->sinkpad, GST_FORMAT_BYTES, 2040 &upstream_size)) 2041 goto found_eos; 2042 2043 if (upstream_size < wav->offset + wav->datastart) 2044 goto found_eos; 2045 2046 /* If file has updated since the beggining continue reading the file */ 2047 wav->dataleft = upstream_size - wav->offset - wav->datastart; 2048 wav->end_offset = upstream_size; 2049 2050 /* Get the next n bytes and output them, if we can */ 2051 if (wav->dataleft == 0 || wav->dataleft < wav->blockalign) 2052 goto found_eos; 2053 } else { 2054 goto found_eos; 2055 } 2056 } 2057 2058 /* scale the amount of data by the segment rate so we get equal 2059 * amounts of data regardless of the playback rate */ 2060 desired = 2061 MIN (gst_guint64_to_gdouble (wav->dataleft), 2062 wav->max_buf_size * ABS (wav->segment.rate)); 2063 2064 if (desired >= wav->blockalign && wav->blockalign > 0) 2065 desired -= (desired % wav->blockalign); 2066 2067 GST_LOG_OBJECT (wav, "Fetching %" G_GINT64_FORMAT " bytes of data " 2068 "from the sinkpad", desired); 2069 2070 if (wav->streaming) { 2071 guint avail = gst_adapter_available (wav->adapter); 2072 guint extra; 2073 2074 /* flush some bytes if evil upstream sends segment that starts 2075 * before data or does is not send sample aligned segment */ 2076 if (G_LIKELY (wav->offset >= wav->datastart)) { 2077 extra = (wav->offset - wav->datastart) % wav->bytes_per_sample; 2078 } else { 2079 extra = wav->datastart - wav->offset; 2080 } 2081 2082 if (G_UNLIKELY (extra)) { 2083 extra = wav->bytes_per_sample - extra; 2084 if (extra <= avail) { 2085 GST_DEBUG_OBJECT (wav, "flushing %u bytes to sample boundary", extra); 2086 gst_adapter_flush (wav->adapter, extra); 2087 wav->offset += extra; 2088 wav->dataleft -= extra; 2089 goto iterate_adapter; 2090 } else { 2091 GST_DEBUG_OBJECT (wav, "flushing %u bytes", avail); 2092 gst_adapter_clear (wav->adapter); 2093 wav->offset += avail; 2094 wav->dataleft -= avail; 2095 return GST_FLOW_OK; 2096 } 2097 } 2098 2099 if (avail < desired) { 2100 GST_LOG_OBJECT (wav, "Got only %u bytes of data from the sinkpad", avail); 2101 return GST_FLOW_OK; 2102 } 2103 2104 buf = gst_adapter_take_buffer (wav->adapter, desired); 2105 } else { 2106 if ((res = gst_pad_pull_range (wav->sinkpad, wav->offset, 2107 desired, &buf)) != GST_FLOW_OK) 2108 goto pull_error; 2109 2110 /* we may get a short buffer at the end of the file */ 2111 if (gst_buffer_get_size (buf) < desired) { 2112 gsize size = gst_buffer_get_size (buf); 2113 2114 GST_LOG_OBJECT (wav, "Got only %" G_GSIZE_FORMAT " bytes of data", size); 2115 if (size >= wav->blockalign) { 2116 if (wav->blockalign > 0) { 2117 buf = gst_buffer_make_writable (buf); 2118 gst_buffer_resize (buf, 0, size - (size % wav->blockalign)); 2119 } 2120 } else { 2121 gst_buffer_unref (buf); 2122 goto found_eos; 2123 } 2124 } 2125 } 2126 2127 obtained = gst_buffer_get_size (buf); 2128 2129 /* our positions in bytes */ 2130 pos = wav->offset - wav->datastart; 2131 nextpos = pos + obtained; 2132 2133 /* update offsets, does not overflow. */ 2134 buf = gst_buffer_make_writable (buf); 2135 GST_BUFFER_OFFSET (buf) = pos / wav->bytes_per_sample; 2136 GST_BUFFER_OFFSET_END (buf) = nextpos / wav->bytes_per_sample; 2137 2138 /* first chunk of data? create the source pad. We do this only here so 2139 * we can detect broken .wav files with dts disguised as raw PCM (sigh) */ 2140 if (G_UNLIKELY (wav->first)) { 2141 wav->first = FALSE; 2142 /* this will also push the segment events */ 2143 gst_wavparse_add_src_pad (wav, buf); 2144 } else { 2145 /* If we have a pending start segment, send it now. */ 2146 if (G_UNLIKELY (wav->start_segment != NULL)) { 2147 gst_pad_push_event (wav->srcpad, wav->start_segment); 2148 wav->start_segment = NULL; 2149 } 2150 } 2151 2152 if (wav->bps > 0) { 2153 /* and timestamps if we have a bitrate, be careful for overflows */ 2154 timestamp = 2155 gst_util_uint64_scale_ceil (pos, GST_SECOND, (guint64) wav->bps); 2156 next_timestamp = 2157 gst_util_uint64_scale_ceil (nextpos, GST_SECOND, (guint64) wav->bps); 2158 duration = next_timestamp - timestamp; 2159 2160 /* update current running segment position */ 2161 if (G_LIKELY (next_timestamp >= wav->segment.start)) 2162 wav->segment.position = next_timestamp; 2163 } else if (wav->fact) { 2164 guint64 bps = 2165 gst_util_uint64_scale_int (wav->datasize, wav->rate, wav->fact); 2166 /* and timestamps if we have a bitrate, be careful for overflows */ 2167 timestamp = gst_util_uint64_scale_ceil (pos, GST_SECOND, bps); 2168 next_timestamp = gst_util_uint64_scale_ceil (nextpos, GST_SECOND, bps); 2169 duration = next_timestamp - timestamp; 2170 } else { 2171 /* no bitrate, all we know is that the first sample has timestamp 0, all 2172 * other positions and durations have unknown timestamp. */ 2173 if (pos == 0) 2174 timestamp = 0; 2175 else 2176 timestamp = GST_CLOCK_TIME_NONE; 2177 duration = GST_CLOCK_TIME_NONE; 2178 /* update current running segment position with byte offset */ 2179 if (G_LIKELY (nextpos >= wav->segment.start)) 2180 wav->segment.position = nextpos; 2181 } 2182 if ((pos > 0) && wav->vbr) { 2183 /* don't set timestamps for VBR files if it's not the first buffer */ 2184 timestamp = GST_CLOCK_TIME_NONE; 2185 duration = GST_CLOCK_TIME_NONE; 2186 } 2187 if (wav->discont) { 2188 GST_DEBUG_OBJECT (wav, "marking DISCONT"); 2189 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); 2190 wav->discont = FALSE; 2191 } 2192 2193 GST_BUFFER_TIMESTAMP (buf) = timestamp; 2194 GST_BUFFER_DURATION (buf) = duration; 2195 2196 GST_LOG_OBJECT (wav, 2197 "Got buffer. timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT 2198 ", size:%" G_GSIZE_FORMAT, GST_TIME_ARGS (timestamp), 2199 GST_TIME_ARGS (duration), gst_buffer_get_size (buf)); 2200 2201 if ((res = gst_pad_push (wav->srcpad, buf)) != GST_FLOW_OK) 2202 goto push_error; 2203 2204 if (obtained < wav->dataleft) { 2205 wav->offset += obtained; 2206 wav->dataleft -= obtained; 2207 } else { 2208 wav->offset += wav->dataleft; 2209 wav->dataleft = 0; 2210 } 2211 2212 /* Iterate until need more data, so adapter size won't grow */ 2213 if (wav->streaming) { 2214 GST_LOG_OBJECT (wav, 2215 "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT, wav->offset, 2216 wav->end_offset); 2217 goto iterate_adapter; 2218 } 2219 return res; 2220 2221 /* ERROR */ 2222 found_eos: 2223 { 2224 GST_DEBUG_OBJECT (wav, "found EOS"); 2225 return GST_FLOW_EOS; 2226 } 2227 pull_error: 2228 { 2229 /* check if we got EOS */ 2230 if (res == GST_FLOW_EOS) 2231 goto found_eos; 2232 2233 GST_WARNING_OBJECT (wav, 2234 "Error getting %" G_GINT64_FORMAT " bytes from the " 2235 "sinkpad (dataleft = %" G_GINT64_FORMAT ")", desired, wav->dataleft); 2236 return res; 2237 } 2238 push_error: 2239 { 2240 GST_INFO_OBJECT (wav, 2241 "Error pushing on srcpad %s:%s, reason %s, is linked? = %d", 2242 GST_DEBUG_PAD_NAME (wav->srcpad), gst_flow_get_name (res), 2243 gst_pad_is_linked (wav->srcpad)); 2244 return res; 2245 } 2246 } 2247 2248 static void 2249 gst_wavparse_loop (GstPad * pad) 2250 { 2251 GstFlowReturn ret; 2252 GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad)); 2253 GstEvent *event; 2254 gchar *stream_id; 2255 2256 GST_LOG_OBJECT (wav, "process data"); 2257 2258 switch (wav->state) { 2259 case GST_WAVPARSE_START: 2260 GST_INFO_OBJECT (wav, "GST_WAVPARSE_START"); 2261 if ((ret = gst_wavparse_stream_init (wav)) != GST_FLOW_OK) 2262 goto pause; 2263 2264 stream_id = 2265 gst_pad_create_stream_id (wav->srcpad, GST_ELEMENT_CAST (wav), NULL); 2266 event = gst_event_new_stream_start (stream_id); 2267 gst_event_set_group_id (event, gst_util_group_id_next ()); 2268 gst_pad_push_event (wav->srcpad, event); 2269 g_free (stream_id); 2270 2271 wav->state = GST_WAVPARSE_HEADER; 2272 /* fall-through */ 2273 2274 case GST_WAVPARSE_HEADER: 2275 GST_INFO_OBJECT (wav, "GST_WAVPARSE_HEADER"); 2276 if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK) 2277 goto pause; 2278 2279 wav->state = GST_WAVPARSE_DATA; 2280 GST_INFO_OBJECT (wav, "GST_WAVPARSE_DATA"); 2281 /* fall-through */ 2282 2283 case GST_WAVPARSE_DATA: 2284 if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK) 2285 goto pause; 2286 break; 2287 default: 2288 g_assert_not_reached (); 2289 } 2290 return; 2291 2292 /* ERRORS */ 2293 pause: 2294 { 2295 const gchar *reason = gst_flow_get_name (ret); 2296 2297 GST_DEBUG_OBJECT (wav, "pausing task, reason %s", reason); 2298 gst_pad_pause_task (pad); 2299 2300 if (ret == GST_FLOW_EOS) { 2301 /* handle end-of-stream/segment */ 2302 /* so align our position with the end of it, if there is one 2303 * this ensures a subsequent will arrive at correct base/acc time */ 2304 if (wav->segment.format == GST_FORMAT_TIME) { 2305 if (wav->segment.rate > 0.0 && 2306 GST_CLOCK_TIME_IS_VALID (wav->segment.stop)) 2307 wav->segment.position = wav->segment.stop; 2308 else if (wav->segment.rate < 0.0) 2309 wav->segment.position = wav->segment.start; 2310 } 2311 if (wav->state == GST_WAVPARSE_START || !wav->caps) { 2312 GST_ELEMENT_ERROR (wav, STREAM, WRONG_TYPE, (NULL), 2313 ("No valid input found before end of stream")); 2314 gst_pad_push_event (wav->srcpad, gst_event_new_eos ()); 2315 } else { 2316 /* add pad before we perform EOS */ 2317 if (G_UNLIKELY (wav->first)) { 2318 wav->first = FALSE; 2319 gst_wavparse_add_src_pad (wav, NULL); 2320 } 2321 2322 /* perform EOS logic */ 2323 if (wav->segment.flags & GST_SEEK_FLAG_SEGMENT) { 2324 GstClockTime stop; 2325 2326 if ((stop = wav->segment.stop) == -1) 2327 stop = wav->segment.duration; 2328 2329 gst_element_post_message (GST_ELEMENT_CAST (wav), 2330 gst_message_new_segment_done (GST_OBJECT_CAST (wav), 2331 wav->segment.format, stop)); 2332 gst_pad_push_event (wav->srcpad, 2333 gst_event_new_segment_done (wav->segment.format, stop)); 2334 } else { 2335 gst_pad_push_event (wav->srcpad, gst_event_new_eos ()); 2336 } 2337 } 2338 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) { 2339 /* for fatal errors we post an error message, post the error 2340 * first so the app knows about the error first. */ 2341 GST_ELEMENT_FLOW_ERROR (wav, ret); 2342 gst_pad_push_event (wav->srcpad, gst_event_new_eos ()); 2343 } 2344 return; 2345 } 2346 } 2347 2348 static GstFlowReturn 2349 gst_wavparse_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) 2350 { 2351 GstFlowReturn ret; 2352 GstWavParse *wav = GST_WAVPARSE (parent); 2353 2354 GST_LOG_OBJECT (wav, "adapter_push %" G_GSIZE_FORMAT " bytes", 2355 gst_buffer_get_size (buf)); 2356 2357 gst_adapter_push (wav->adapter, buf); 2358 2359 switch (wav->state) { 2360 case GST_WAVPARSE_START: 2361 GST_INFO_OBJECT (wav, "GST_WAVPARSE_START"); 2362 if ((ret = gst_wavparse_parse_stream_init (wav)) != GST_FLOW_OK) 2363 goto done; 2364 2365 if (wav->state != GST_WAVPARSE_HEADER) 2366 break; 2367 2368 /* otherwise fall-through */ 2369 case GST_WAVPARSE_HEADER: 2370 GST_INFO_OBJECT (wav, "GST_WAVPARSE_HEADER"); 2371 if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK) 2372 goto done; 2373 2374 if (!wav->got_fmt || wav->datastart == 0) 2375 break; 2376 2377 wav->state = GST_WAVPARSE_DATA; 2378 GST_INFO_OBJECT (wav, "GST_WAVPARSE_DATA"); 2379 2380 /* fall-through */ 2381 case GST_WAVPARSE_DATA: 2382 if (buf && GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) 2383 wav->discont = TRUE; 2384 if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK) 2385 goto done; 2386 break; 2387 default: 2388 g_return_val_if_reached (GST_FLOW_ERROR); 2389 } 2390 done: 2391 if (G_UNLIKELY (wav->abort_buffering)) { 2392 wav->abort_buffering = FALSE; 2393 ret = GST_FLOW_ERROR; 2394 /* sort of demux/parse error */ 2395 GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL), ("unhandled buffer size")); 2396 } 2397 #ifdef GSTREAMER_LITE 2398 else if (G_UNLIKELY(ret != GST_FLOW_OK && ret != GST_FLOW_FLUSHING && ret != GST_FLOW_EOS)) 2399 { 2400 GST_ELEMENT_ERROR (wav, STREAM, FAILED, 2401 (_("Internal data flow error.")), 2402 ("streaming task paused, reason %s (%d)", 2403 gst_flow_get_name (ret), ret)); 2404 } 2405 #endif // GSTREAMER_LITE 2406 2407 return ret; 2408 } 2409 2410 static GstFlowReturn 2411 gst_wavparse_flush_data (GstWavParse * wav) 2412 { 2413 GstFlowReturn ret = GST_FLOW_OK; 2414 guint av; 2415 2416 if ((av = gst_adapter_available (wav->adapter)) > 0) { 2417 ret = gst_wavparse_stream_data (wav); 2418 } 2419 2420 return ret; 2421 } 2422 2423 static gboolean 2424 gst_wavparse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) 2425 { 2426 GstWavParse *wav = GST_WAVPARSE (parent); 2427 gboolean ret = TRUE; 2428 2429 GST_LOG_OBJECT (wav, "handling %s event", GST_EVENT_TYPE_NAME (event)); 2430 2431 switch (GST_EVENT_TYPE (event)) { 2432 case GST_EVENT_CAPS: 2433 { 2434 /* discard, we'll come up with proper src caps */ 2435 gst_event_unref (event); 2436 break; 2437 } 2438 case GST_EVENT_SEGMENT: 2439 { 2440 gint64 start, stop, offset = 0, end_offset = -1; 2441 GstSegment segment; 2442 2443 /* some debug output */ 2444 gst_event_copy_segment (event, &segment); 2445 GST_DEBUG_OBJECT (wav, "received newsegment %" GST_SEGMENT_FORMAT, 2446 &segment); 2447 2448 if (wav->state != GST_WAVPARSE_DATA) { 2449 GST_DEBUG_OBJECT (wav, "still starting, eating event"); 2450 goto exit; 2451 } 2452 2453 /* now we are either committed to TIME or BYTE format, 2454 * and we only expect a BYTE segment, e.g. following a seek */ 2455 if (segment.format == GST_FORMAT_BYTES) { 2456 /* handle (un)signed issues */ 2457 start = segment.start; 2458 stop = segment.stop; 2459 if (start > 0) { 2460 offset = start; 2461 start -= wav->datastart; 2462 start = MAX (start, 0); 2463 } 2464 if (stop > 0) { 2465 end_offset = stop; 2466 stop -= wav->datastart; 2467 stop = MAX (stop, 0); 2468 } 2469 if (wav->segment.format == GST_FORMAT_TIME) { 2470 guint64 bps = wav->bps; 2471 2472 /* operating in format TIME, so we can convert */ 2473 if (!bps && wav->fact) 2474 bps = 2475 gst_util_uint64_scale_int (wav->datasize, wav->rate, wav->fact); 2476 if (bps) { 2477 if (start >= 0) 2478 start = 2479 gst_util_uint64_scale_ceil (start, GST_SECOND, 2480 (guint64) wav->bps); 2481 if (stop >= 0) 2482 stop = 2483 gst_util_uint64_scale_ceil (stop, GST_SECOND, 2484 (guint64) wav->bps); 2485 } 2486 } 2487 } else { 2488 GST_DEBUG_OBJECT (wav, "unsupported segment format, ignoring"); 2489 goto exit; 2490 } 2491 2492 segment.start = start; 2493 segment.stop = stop; 2494 2495 /* accept upstream's notion of segment and distribute along */ 2496 segment.format = wav->segment.format; 2497 segment.time = segment.position = segment.start; 2498 segment.duration = wav->segment.duration; 2499 segment.base = gst_segment_to_running_time (&wav->segment, 2500 GST_FORMAT_TIME, wav->segment.position); 2501 2502 gst_segment_copy_into (&segment, &wav->segment); 2503 2504 /* also store the newsegment event for the streaming thread */ 2505 if (wav->start_segment) 2506 gst_event_unref (wav->start_segment); 2507 GST_DEBUG_OBJECT (wav, "Storing newseg %" GST_SEGMENT_FORMAT, &segment); 2508 wav->start_segment = gst_event_new_segment (&segment); 2509 2510 /* stream leftover data in current segment */ 2511 gst_wavparse_flush_data (wav); 2512 /* and set up streaming thread for next one */ 2513 wav->offset = offset; 2514 wav->end_offset = end_offset; 2515 2516 if (wav->datasize > 0 && (wav->end_offset == -1 2517 || wav->end_offset > wav->datastart + wav->datasize)) 2518 wav->end_offset = wav->datastart + wav->datasize; 2519 2520 if (wav->end_offset != -1) { 2521 #ifdef GSTREAMER_LITE 2522 wav->dataleft = MIN(wav->datasize, wav->end_offset - wav->offset); 2523 #else 2524 wav->dataleft = wav->end_offset - wav->offset; 2525 #endif // GSTREAMER_LITE 2526 } else { 2527 /* infinity; upstream will EOS when done */ 2528 wav->dataleft = G_MAXUINT64; 2529 } 2530 exit: 2531 gst_event_unref (event); 2532 break; 2533 } 2534 #ifdef GSTREAMER_LITE 2535 case FX_EVENT_RANGE_READY: // This event appears only in pull mode during outrange seeking. 2536 ret = gst_pad_start_task (pad, (GstTaskFunction) gst_wavparse_loop, pad, NULL); 2537 gst_event_unref(event); 2538 break; 2539 #endif // GSTREAMER_LITE 2540 case GST_EVENT_EOS: 2541 if (wav->state == GST_WAVPARSE_START || !wav->caps) { 2542 GST_ELEMENT_ERROR (wav, STREAM, WRONG_TYPE, (NULL), 2543 ("No valid input found before end of stream")); 2544 } else { 2545 /* add pad if needed so EOS is seen downstream */ 2546 if (G_UNLIKELY (wav->first)) { 2547 wav->first = FALSE; 2548 gst_wavparse_add_src_pad (wav, NULL); 2549 } else { 2550 /* stream leftover data in current segment */ 2551 gst_wavparse_flush_data (wav); 2552 } 2553 } 2554 2555 /* fall-through */ 2556 case GST_EVENT_FLUSH_STOP: 2557 { 2558 GstClockTime dur; 2559 2560 if (wav->adapter) 2561 gst_adapter_clear (wav->adapter); 2562 wav->discont = TRUE; 2563 dur = wav->segment.duration; 2564 gst_segment_init (&wav->segment, wav->segment.format); 2565 wav->segment.duration = dur; 2566 /* fall-through */ 2567 } 2568 default: 2569 ret = gst_pad_event_default (wav->sinkpad, parent, event); 2570 break; 2571 } 2572 2573 return ret; 2574 } 2575 2576 #if 0 2577 /* convert and query stuff */ 2578 static const GstFormat * 2579 gst_wavparse_get_formats (GstPad * pad) 2580 { 2581 static const GstFormat formats[] = { 2582 GST_FORMAT_TIME, 2583 GST_FORMAT_BYTES, 2584 GST_FORMAT_DEFAULT, /* a "frame", ie a set of samples per Hz */ 2585 0 2586 }; 2587 2588 return formats; 2589 } 2590 #endif 2591 2592 static gboolean 2593 gst_wavparse_pad_convert (GstPad * pad, 2594 GstFormat src_format, gint64 src_value, 2595 GstFormat * dest_format, gint64 * dest_value) 2596 { 2597 GstWavParse *wavparse; 2598 gboolean res = TRUE; 2599 2600 wavparse = GST_WAVPARSE (GST_PAD_PARENT (pad)); 2601 2602 if (*dest_format == src_format) { 2603 *dest_value = src_value; 2604 return TRUE; 2605 } 2606 2607 if ((wavparse->bps == 0) && !wavparse->fact) 2608 goto no_bps_fact; 2609 2610 GST_INFO_OBJECT (wavparse, "converting value from %s to %s", 2611 gst_format_get_name (src_format), gst_format_get_name (*dest_format)); 2612 2613 switch (src_format) { 2614 case GST_FORMAT_BYTES: 2615 switch (*dest_format) { 2616 case GST_FORMAT_DEFAULT: 2617 *dest_value = src_value / wavparse->bytes_per_sample; 2618 /* make sure we end up on a sample boundary */ 2619 *dest_value -= *dest_value % wavparse->bytes_per_sample; 2620 break; 2621 case GST_FORMAT_TIME: 2622 /* src_value + datastart = offset */ 2623 GST_INFO_OBJECT (wavparse, 2624 "src=%" G_GINT64_FORMAT ", offset=%" G_GINT64_FORMAT, src_value, 2625 wavparse->offset); 2626 if (wavparse->bps > 0) 2627 *dest_value = gst_util_uint64_scale_ceil (src_value, GST_SECOND, 2628 (guint64) wavparse->bps); 2629 else if (wavparse->fact) { 2630 guint64 bps = gst_util_uint64_scale_int_ceil (wavparse->datasize, 2631 wavparse->rate, wavparse->fact); 2632 2633 *dest_value = 2634 gst_util_uint64_scale_int_ceil (src_value, GST_SECOND, bps); 2635 } else { 2636 res = FALSE; 2637 } 2638 break; 2639 default: 2640 res = FALSE; 2641 goto done; 2642 } 2643 break; 2644 2645 case GST_FORMAT_DEFAULT: 2646 switch (*dest_format) { 2647 case GST_FORMAT_BYTES: 2648 *dest_value = src_value * wavparse->bytes_per_sample; 2649 break; 2650 case GST_FORMAT_TIME: 2651 *dest_value = gst_util_uint64_scale (src_value, GST_SECOND, 2652 (guint64) wavparse->rate); 2653 break; 2654 default: 2655 res = FALSE; 2656 goto done; 2657 } 2658 break; 2659 2660 case GST_FORMAT_TIME: 2661 switch (*dest_format) { 2662 case GST_FORMAT_BYTES: 2663 if (wavparse->bps > 0) 2664 *dest_value = gst_util_uint64_scale (src_value, 2665 (guint64) wavparse->bps, GST_SECOND); 2666 else { 2667 guint64 bps = gst_util_uint64_scale_int (wavparse->datasize, 2668 wavparse->rate, wavparse->fact); 2669 2670 *dest_value = gst_util_uint64_scale (src_value, bps, GST_SECOND); 2671 } 2672 /* make sure we end up on a sample boundary */ 2673 *dest_value -= *dest_value % wavparse->blockalign; 2674 break; 2675 case GST_FORMAT_DEFAULT: 2676 *dest_value = gst_util_uint64_scale (src_value, 2677 (guint64) wavparse->rate, GST_SECOND); 2678 break; 2679 default: 2680 res = FALSE; 2681 goto done; 2682 } 2683 break; 2684 2685 default: 2686 res = FALSE; 2687 goto done; 2688 } 2689 2690 done: 2691 return res; 2692 2693 /* ERRORS */ 2694 no_bps_fact: 2695 { 2696 GST_DEBUG_OBJECT (wavparse, "bps 0 or no fact chunk, cannot convert"); 2697 res = FALSE; 2698 goto done; 2699 } 2700 } 2701 2702 /* handle queries for location and length in requested format */ 2703 static gboolean 2704 gst_wavparse_pad_query (GstPad * pad, GstObject * parent, GstQuery * query) 2705 { 2706 gboolean res = TRUE; 2707 GstWavParse *wav = GST_WAVPARSE (parent); 2708 2709 /* only if we know */ 2710 if (wav->state != GST_WAVPARSE_DATA) { 2711 return FALSE; 2712 } 2713 2714 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query)); 2715 2716 switch (GST_QUERY_TYPE (query)) { 2717 case GST_QUERY_POSITION: 2718 { 2719 gint64 curb; 2720 gint64 cur; 2721 GstFormat format; 2722 2723 /* this is not very precise, as we have pushed severla buffer upstream for prerolling */ 2724 curb = wav->offset - wav->datastart; 2725 gst_query_parse_position (query, &format, NULL); 2726 GST_INFO_OBJECT (wav, "pos query at %" G_GINT64_FORMAT, curb); 2727 2728 switch (format) { 2729 case GST_FORMAT_BYTES: 2730 format = GST_FORMAT_BYTES; 2731 cur = curb; 2732 break; 2733 default: 2734 res = gst_wavparse_pad_convert (pad, GST_FORMAT_BYTES, curb, 2735 &format, &cur); 2736 break; 2737 } 2738 if (res) 2739 gst_query_set_position (query, format, cur); 2740 break; 2741 } 2742 case GST_QUERY_DURATION: 2743 { 2744 gint64 duration = 0; 2745 GstFormat format; 2746 2747 if (wav->ignore_length) { 2748 res = FALSE; 2749 break; 2750 } 2751 2752 gst_query_parse_duration (query, &format, NULL); 2753 2754 switch (format) { 2755 case GST_FORMAT_BYTES:{ 2756 format = GST_FORMAT_BYTES; 2757 duration = wav->datasize; 2758 break; 2759 } 2760 case GST_FORMAT_TIME: 2761 if ((res = gst_wavparse_calculate_duration (wav))) { 2762 duration = wav->duration; 2763 } 2764 break; 2765 default: 2766 res = FALSE; 2767 break; 2768 } 2769 if (res) 2770 gst_query_set_duration (query, format, duration); 2771 break; 2772 } 2773 case GST_QUERY_CONVERT: 2774 { 2775 gint64 srcvalue, dstvalue; 2776 GstFormat srcformat, dstformat; 2777 2778 gst_query_parse_convert (query, &srcformat, &srcvalue, 2779 &dstformat, &dstvalue); 2780 res = gst_wavparse_pad_convert (pad, srcformat, srcvalue, 2781 &dstformat, &dstvalue); 2782 if (res) 2783 gst_query_set_convert (query, srcformat, srcvalue, dstformat, dstvalue); 2784 break; 2785 } 2786 case GST_QUERY_SEEKING:{ 2787 GstFormat fmt; 2788 gboolean seekable = FALSE; 2789 2790 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL); 2791 if (fmt == wav->segment.format) { 2792 if (wav->streaming) { 2793 GstQuery *q; 2794 2795 q = gst_query_new_seeking (GST_FORMAT_BYTES); 2796 if ((res = gst_pad_peer_query (wav->sinkpad, q))) { 2797 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL); 2798 GST_LOG_OBJECT (wav, "upstream BYTE seekable %d", seekable); 2799 } 2800 gst_query_unref (q); 2801 } else { 2802 GST_LOG_OBJECT (wav, "looping => seekable"); 2803 seekable = TRUE; 2804 res = TRUE; 2805 } 2806 } else if (fmt == GST_FORMAT_TIME) { 2807 res = TRUE; 2808 } 2809 if (res) { 2810 gst_query_set_seeking (query, fmt, seekable, 0, wav->segment.duration); 2811 } 2812 break; 2813 } 2814 default: 2815 res = gst_pad_query_default (pad, parent, query); 2816 break; 2817 } 2818 return res; 2819 } 2820 2821 #ifdef GSTREAMER_LITE 2822 static gboolean 2823 gst_wavparse_sink_query (GstPad* pad, GstObject *parent, GstQuery* query) 2824 { 2825 gboolean result = TRUE; 2826 switch (GST_QUERY_TYPE(query)) 2827 { 2828 case GST_QUERY_CUSTOM: 2829 { 2830 const GstStructure *s = gst_query_get_structure(query); 2831 if (gst_structure_has_name(s, GETRANGE_QUERY_NAME)) 2832 gst_structure_set(s, GETRANGE_QUERY_SUPPORTS_FIELDNANE, 2833 GETRANGE_QUERY_SUPPORTS_FIELDTYPE, 2834 TRUE, 2835 NULL); 2836 break; 2837 } 2838 default: 2839 result = gst_pad_query_default(pad, parent, query); 2840 break; 2841 } 2842 return result; 2843 } 2844 #endif // GSTREAMER_LITE 2845 2846 static gboolean 2847 gst_wavparse_srcpad_event (GstPad * pad, GstObject * parent, GstEvent * event) 2848 { 2849 GstWavParse *wavparse = GST_WAVPARSE (parent); 2850 gboolean res = FALSE; 2851 2852 GST_DEBUG_OBJECT (wavparse, "%s event", GST_EVENT_TYPE_NAME (event)); 2853 2854 switch (GST_EVENT_TYPE (event)) { 2855 case GST_EVENT_SEEK: 2856 /* can only handle events when we are in the data state */ 2857 if (wavparse->state == GST_WAVPARSE_DATA) { 2858 res = gst_wavparse_perform_seek (wavparse, event); 2859 } 2860 gst_event_unref (event); 2861 break; 2862 2863 case GST_EVENT_TOC_SELECT: 2864 { 2865 char *uid = NULL; 2866 GstTocEntry *entry = NULL; 2867 GstEvent *seek_event; 2868 gint64 start_pos; 2869 2870 if (!wavparse->toc) { 2871 GST_DEBUG_OBJECT (wavparse, "no TOC to select"); 2872 return FALSE; 2873 } else { 2874 gst_event_parse_toc_select (event, &uid); 2875 if (uid != NULL) { 2876 GST_OBJECT_LOCK (wavparse); 2877 entry = gst_toc_find_entry (wavparse->toc, uid); 2878 if (entry == NULL) { 2879 GST_OBJECT_UNLOCK (wavparse); 2880 GST_WARNING_OBJECT (wavparse, "no TOC entry with given UID: %s", 2881 uid); 2882 res = FALSE; 2883 } else { 2884 gst_toc_entry_get_start_stop_times (entry, &start_pos, NULL); 2885 GST_OBJECT_UNLOCK (wavparse); 2886 seek_event = gst_event_new_seek (1.0, 2887 GST_FORMAT_TIME, 2888 GST_SEEK_FLAG_FLUSH, 2889 GST_SEEK_TYPE_SET, start_pos, GST_SEEK_TYPE_SET, -1); 2890 res = gst_wavparse_perform_seek (wavparse, seek_event); 2891 gst_event_unref (seek_event); 2892 } 2893 g_free (uid); 2894 } else { 2895 GST_WARNING_OBJECT (wavparse, "received empty TOC select event"); 2896 res = FALSE; 2897 } 2898 } 2899 gst_event_unref (event); 2900 break; 2901 } 2902 2903 default: 2904 res = gst_pad_push_event (wavparse->sinkpad, event); 2905 break; 2906 } 2907 return res; 2908 } 2909 2910 static gboolean 2911 gst_wavparse_sink_activate (GstPad * sinkpad, GstObject * parent) 2912 { 2913 GstWavParse *wav = GST_WAVPARSE (parent); 2914 GstQuery *query; 2915 gboolean pull_mode; 2916 2917 if (wav->adapter) { 2918 gst_adapter_clear (wav->adapter); 2919 g_object_unref (wav->adapter); 2920 wav->adapter = NULL; 2921 } 2922 2923 query = gst_query_new_scheduling (); 2924 2925 if (!gst_pad_peer_query (sinkpad, query)) { 2926 gst_query_unref (query); 2927 goto activate_push; 2928 } 2929 2930 pull_mode = gst_query_has_scheduling_mode_with_flags (query, 2931 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE); 2932 gst_query_unref (query); 2933 2934 if (!pull_mode) 2935 goto activate_push; 2936 2937 GST_DEBUG_OBJECT (sinkpad, "activating pull"); 2938 wav->streaming = FALSE; 2939 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE); 2940 2941 activate_push: 2942 { 2943 GST_DEBUG_OBJECT (sinkpad, "activating push"); 2944 wav->streaming = TRUE; 2945 wav->adapter = gst_adapter_new (); 2946 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE); 2947 } 2948 } 2949 2950 2951 static gboolean 2952 gst_wavparse_sink_activate_mode (GstPad * sinkpad, GstObject * parent, 2953 GstPadMode mode, gboolean active) 2954 { 2955 gboolean res; 2956 2957 switch (mode) { 2958 case GST_PAD_MODE_PUSH: 2959 res = TRUE; 2960 break; 2961 case GST_PAD_MODE_PULL: 2962 if (active) { 2963 /* if we have a scheduler we can start the task */ 2964 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_wavparse_loop, 2965 sinkpad, NULL); 2966 } else { 2967 res = gst_pad_stop_task (sinkpad); 2968 } 2969 break; 2970 default: 2971 res = FALSE; 2972 break; 2973 } 2974 return res; 2975 } 2976 2977 static GstStateChangeReturn 2978 gst_wavparse_change_state (GstElement * element, GstStateChange transition) 2979 { 2980 GstStateChangeReturn ret; 2981 GstWavParse *wav = GST_WAVPARSE (element); 2982 2983 switch (transition) { 2984 case GST_STATE_CHANGE_NULL_TO_READY: 2985 break; 2986 case GST_STATE_CHANGE_READY_TO_PAUSED: 2987 gst_wavparse_reset (wav); 2988 break; 2989 case GST_STATE_CHANGE_PAUSED_TO_PLAYING: 2990 break; 2991 default: 2992 break; 2993 } 2994 2995 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); 2996 2997 switch (transition) { 2998 case GST_STATE_CHANGE_PLAYING_TO_PAUSED: 2999 break; 3000 case GST_STATE_CHANGE_PAUSED_TO_READY: 3001 #ifndef GSTREAMER_LITE 3002 gst_wavparse_destroy_sourcepad (wav); 3003 #endif // GSTREAMER_LITE 3004 gst_wavparse_reset (wav); 3005 break; 3006 case GST_STATE_CHANGE_READY_TO_NULL: 3007 break; 3008 default: 3009 break; 3010 } 3011 return ret; 3012 } 3013 3014 static void 3015 gst_wavparse_set_property (GObject * object, guint prop_id, 3016 const GValue * value, GParamSpec * pspec) 3017 { 3018 GstWavParse *self; 3019 3020 g_return_if_fail (GST_IS_WAVPARSE (object)); 3021 self = GST_WAVPARSE (object); 3022 3023 switch (prop_id) { 3024 case PROP_IGNORE_LENGTH: 3025 self->ignore_length = g_value_get_boolean (value); 3026 break; 3027 default: 3028 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); 3029 } 3030 3031 } 3032 3033 static void 3034 gst_wavparse_get_property (GObject * object, guint prop_id, 3035 GValue * value, GParamSpec * pspec) 3036 { 3037 GstWavParse *self; 3038 3039 g_return_if_fail (GST_IS_WAVPARSE (object)); 3040 self = GST_WAVPARSE (object); 3041 3042 switch (prop_id) { 3043 case PROP_IGNORE_LENGTH: 3044 g_value_set_boolean (value, self->ignore_length); 3045 break; 3046 default: 3047 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); 3048 } 3049 } 3050 3051 #ifdef GSTREAMER_LITE 3052 gboolean 3053 plugin_init_wavparse (GstPlugin * plugin) 3054 #else // GSTREAMER_LITE 3055 static gboolean 3056 plugin_init (GstPlugin * plugin) 3057 #endif // GSTREAMER_LITE 3058 { 3059 gst_riff_init (); 3060 3061 return gst_element_register (plugin, "wavparse", GST_RANK_PRIMARY, 3062 GST_TYPE_WAVPARSE); 3063 } 3064 3065 #ifndef GSTREAMER_LITE 3066 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, 3067 GST_VERSION_MINOR, 3068 wavparse, 3069 "Parse a .wav file into raw audio", 3070 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) 3071 #endif // GSTREAMER_LITE