| /* GStreamer |
| * Copyright (C) <2017> Carlos Rafael Giani <dv at pseudoterminal dot org> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| |
| #ifndef __GST_NONSTREAM_AUDIO_DECODER_H__ |
| #define __GST_NONSTREAM_AUDIO_DECODER_H__ |
| |
| #include <gst/gst.h> |
| #include <gst/base/gstadapter.h> |
| #include <gst/audio/audio.h> |
| #include <gst/audio/audio-bad-prelude.h> |
| |
| G_BEGIN_DECLS |
| |
| |
| typedef struct _GstNonstreamAudioDecoder GstNonstreamAudioDecoder; |
| typedef struct _GstNonstreamAudioDecoderClass GstNonstreamAudioDecoderClass; |
| |
| |
| /** |
| * GstNonstreamAudioOutputMode: |
| * @GST_NONSTREAM_AUDIO_OUTPUT_MODE_LOOPING: Playback position is moved back to the beginning of the loop |
| * @GST_NONSTREAM_AUDIO_OUTPUT_MODE_STEADY: Playback position increases steadily, even when looping |
| * |
| * The output mode defines how the output behaves with regards to looping. Either the playback position is |
| * moved back to the beginning of the loop, acting like a backwards seek, or it increases steadily, as if |
| * loop were "unrolled". |
| */ |
| typedef enum |
| { |
| GST_NONSTREAM_AUDIO_OUTPUT_MODE_LOOPING, |
| GST_NONSTREAM_AUDIO_OUTPUT_MODE_STEADY |
| } GstNonstreamAudioOutputMode; |
| |
| |
| /** |
| * GstNonstreamAudioSubsongMode: |
| * @GST_NONSTREAM_AUDIO_SUBSONG_MODE_SINGLE: Only the current subsong is played |
| * @GST_NONSTREAM_AUDIO_SUBSONG_MODE_ALL: All subsongs are played (current subsong index is ignored) |
| * @GST_NONSTREAM_AUDIO_SUBSONG_MODE_DECODER_DEFAULT: Use decoder specific default behavior |
| * |
| * The subsong mode defines how the decoder shall handle subsongs. |
| */ |
| typedef enum |
| { |
| GST_NONSTREAM_AUDIO_SUBSONG_MODE_SINGLE, |
| GST_NONSTREAM_AUDIO_SUBSONG_MODE_ALL, |
| GST_NONSTREAM_AUDIO_SUBSONG_MODE_DECODER_DEFAULT |
| } GstNonstreamAudioSubsongMode; |
| |
| |
| #define GST_TYPE_NONSTREAM_AUDIO_DECODER (gst_nonstream_audio_decoder_get_type()) |
| #define GST_NONSTREAM_AUDIO_DECODER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_NONSTREAM_AUDIO_DECODER, GstNonstreamAudioDecoder)) |
| #define GST_NONSTREAM_AUDIO_DECODER_CAST(obj) ((GstNonstreamAudioDecoder *)(obj)) |
| #define GST_NONSTREAM_AUDIO_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_NONSTREAM_AUDIO_DECODER, GstNonstreamAudioDecoderClass)) |
| #define GST_NONSTREAM_AUDIO_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_NONSTREAM_AUDIO_DECODER, GstNonstreamAudioDecoderClass)) |
| #define GST_IS_NONSTREAM_AUDIO_DECODER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_NONSTREAM_AUDIO_DECODER)) |
| #define GST_IS_NONSTREAM_AUDIO_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_NONSTREAM_AUDIO_DECODER)) |
| |
| /** |
| * GST_NONSTREAM_AUDIO_DECODER_SINK_NAME: |
| * |
| * The name of the template for the sink pad. |
| */ |
| #define GST_NONSTREAM_AUDIO_DECODER_SINK_NAME "sink" |
| /** |
| * GST_NONSTREAM_AUDIO_DECODER_SRC_NAME: |
| * |
| * The name of the template for the source pad. |
| */ |
| #define GST_NONSTREAM_AUDIO_DECODER_SRC_NAME "src" |
| |
| /** |
| * GST_NONSTREAM_AUDIO_DECODER_SINK_PAD: |
| * @obj: base nonstream audio codec instance |
| * |
| * Gives the pointer to the sink #GstPad object of the element. |
| */ |
| #define GST_NONSTREAM_AUDIO_DECODER_SINK_PAD(obj) (((GstNonstreamAudioDecoder *) (obj))->sinkpad) |
| /** |
| * GST_NONSTREAM_AUDIO_DECODER_SRC_PAD: |
| * @obj: base nonstream audio codec instance |
| * |
| * Gives the pointer to the source #GstPad object of the element. |
| */ |
| #define GST_NONSTREAM_AUDIO_DECODER_SRC_PAD(obj) (((GstNonstreamAudioDecoder *) (obj))->srcpad) |
| |
| |
| /** |
| * GST_NONSTREAM_AUDIO_DECODER_LOCK_MUTEX: |
| * @obj: base nonstream audio codec instance |
| * |
| * Locks the decoder mutex. |
| * |
| * Internally, the mutex is locked before one of the class vfuncs are |
| * called, when position and duration queries are handled, and when |
| * properties are set/retrieved. |
| * |
| * Derived classes should call lock during decoder related modifications |
| * (for example, setting/clearing filter banks), when at the same time |
| * audio might get decoded. An example are configuration changes that |
| * happen when properties are set. Properties might be set from another |
| * thread, so while the derived decoder is reconfigured, the mutex |
| * should be locked. |
| */ |
| #define GST_NONSTREAM_AUDIO_DECODER_LOCK_MUTEX(obj) g_mutex_lock(&(((GstNonstreamAudioDecoder *)(obj))->mutex)) |
| #define GST_NONSTREAM_AUDIO_DECODER_UNLOCK_MUTEX(obj) g_mutex_unlock(&(((GstNonstreamAudioDecoder *)(obj))->mutex)) |
| |
| |
| /** |
| * GstNonstreamAudioDecoder: |
| * |
| * The opaque #GstNonstreamAudioDecoder data structure. |
| */ |
| struct _GstNonstreamAudioDecoder |
| { |
| GstElement element; |
| |
| /*< protected > */ |
| |
| /* source and sink pads */ |
| GstPad *sinkpad, *srcpad; |
| |
| /* loading information */ |
| gint64 upstream_size; |
| gboolean loaded_mode; |
| GstAdapter *input_data_adapter; |
| |
| /* subsong states */ |
| guint current_subsong; |
| GstNonstreamAudioSubsongMode subsong_mode; |
| GstClockTime subsong_duration; |
| |
| /* output states */ |
| GstNonstreamAudioOutputMode output_mode; |
| gint num_loops; |
| gboolean output_format_changed; |
| GstAudioInfo output_audio_info; |
| /* The difference between these two values is: cur_pos_in_samples is |
| * used for the GstBuffer offsets, while num_decoded_samples is used |
| * for the segment base time values. |
| * cur_pos_in_samples is reset after seeking, looping (when output mode |
| * is LOOPING) and switching subsongs, while num_decoded is only reset |
| * to 0 after a flushing seek (because flushing seeks alter the |
| * pipeline's base_time). */ |
| guint64 cur_pos_in_samples, num_decoded_samples; |
| GstSegment cur_segment; |
| gboolean discont; |
| |
| /* metadata */ |
| GstToc *toc; |
| |
| /* allocation */ |
| GstAllocator *allocator; |
| GstAllocationParams allocation_params; |
| |
| /* thread safety */ |
| GMutex mutex; |
| }; |
| |
| |
| /** |
| * GstNonstreamAudioDecoderClass: |
| * @element_class: The parent class structure |
| * @seek: Optional. |
| * Called when a seek event is received by the parent class. |
| * new_position is a pointer to a GstClockTime integer which |
| * contains a position relative to the current subsong. |
| * Minimum is 0, maximum is the subsong length. |
| * After this function finishes, new_position is set to the |
| * actual new position (which may differ from the request |
| * position, depending on the decoder). |
| * @tell: Optional. |
| * Called when a position query is received by the parent class. |
| * The position that this function returns must be relative to |
| * the current subsong. Thus, the minimum is 0, and the maximum |
| * is the subsong length. |
| * @load_from_buffer: Required if loads_from_sinkpad is set to TRUE (the default value). |
| * Loads the media from the given buffer. The entire media is supplied at once, |
| * so after this call, loading should be finished. This function |
| * can also make use of a suggested initial subsong & subsong mode and initial |
| * playback position (but isn't required to). In case it chooses a different starting |
| * position, the function must pass this position to *initial_position. |
| * The subclass does not have to unref the input buffer; the base class does that |
| * already. |
| * @load_from_custom: Required if loads_from_sinkpad is set to FALSE. |
| * Loads the media in a way defined by the custom sink. Data is not supplied; |
| * the derived class has to handle this on its own. Otherwise, this function is |
| * identical to @load_from_buffer. |
| * @get_main_tags: Optional. |
| * Returns a tag list containing the main song tags, or NULL if there are |
| * no such tags. Returned tags will be unref'd. Use this vfunc instead of |
| * manually pushing a tag event downstream to avoid edge cases where not yet |
| * pushed sticky tag events get overwritten before they are pushed (can for |
| * example happen with decodebin if tags are pushed downstream before the |
| * decodebin pads are linked). |
| * @set_current_subsong: Optional. |
| * Sets the current subsong. This function is allowed to switch to a different |
| * subsong than the required one, and can optionally make use of the suggested initial |
| * position. In case it chooses a different starting position, the function must pass |
| * this position to *initial_position. |
| * This function switches the subsong mode to GST_NONSTREAM_AUDIO_SUBSONG_MODE_SINGLE |
| * automatically. |
| * If this function is implemented by the subclass, @get_current_subsong and |
| * @get_num_subsongs should be implemented as well. |
| * @get_current_subsong: Optional. |
| * Returns the current subsong. |
| * If the current subsong mode is not GST_NONSTREAM_AUDIO_SUBSONG_MODE_SINGLE, this |
| * function's return value is undefined. |
| * If this function is implemented by the subclass, |
| * @get_num_subsongs should be implemented as well. |
| * @get_num_subsongs: Optional. |
| * Returns the number of subsongs available. |
| * The return values 0 and 1 have a similar, but distinct, meaning. |
| * If this function returns 0, then this decoder does not support subsongs at all. |
| * @get_current_subsong must then also always return 0. In other words, this function |
| * either never returns 0, or never returns anything else than 0. |
| * A return value of 1 means that the media contains either only one or no subsongs |
| * (the entire song is then considered to be one single subsong). 1 also means that only |
| * this very media has no or just one subsong, and the decoder itself can |
| * support multiple subsongs. |
| * @get_subsong_duration: Optional. |
| * Returns the duration of a subsong. Returns GST_CLOCK_TIME_NONE if duration is unknown. |
| * @get_subsong_tags: Optional. |
| * Returns tags for a subsong, or NULL if there are no tags. |
| * Returned tags will be unref'd. |
| * @set_subsong_mode: Optional. |
| * Sets the current subsong mode. Since this might influence the current playback position, |
| * this function must set the initial_position integer argument to a defined value. |
| * If the playback position is not affected at all, it must be set to GST_CLOCK_TIME_NONE. |
| * If the subsong is restarted after the mode switch, it is recommended to set the value |
| * to the position in the playback right after the switch (or 0 if the subsongs are always |
| * reset back to the beginning). |
| * @set_num_loops: Optional. |
| * Sets the number of loops for playback. If this is called during playback, |
| * the subclass must set any internal loop counters to zero. A loop value of -1 |
| * means infinite looping; 0 means no looping; and when the num_loops is greater than 0, |
| * playback should loop exactly num_loops times. If this function is implemented, |
| * @get_num_loops should be implemented as well. The function can ignore the given values |
| * and choose another; however, @get_num_loops should return this other value afterwards. |
| * It is up to the subclass to define where the loop starts and ends. It can mean that only |
| * a subset at the end or in the middle of a song is repeated, for example. |
| * If the current subsong mode is GST_NONSTREAM_AUDIO_SUBSONG_MODE_SINGLE, then the subsong |
| * is repeated this many times. If it is GST_NONSTREAM_AUDIO_SUBSONG_MODE_ALL, then all |
| * subsongs are repeated this many times. With GST_NONSTREAM_AUDIO_SUBSONG_MODE_DECODER_DEFAULT, |
| * the behavior is decoder specific. |
| * @get_num_loops: Optional. |
| * Returns the number of loops for playback. |
| * @get_supported_output_modes: Always required. |
| * Returns a bitmask containing the output modes the subclass supports. |
| * The mask is formed by a bitwise OR combination of integers, which can be calculated |
| * this way: 1 << GST_NONSTREAM_AUDIO_OUTPUT_MODE_<mode> , where mode is either STEADY or LOOPING |
| * @set_output_mode: Optional. |
| * Sets the output mode the subclass has to use. Unlike with most other functions, the subclass |
| * cannot choose a different mode; it must use the requested one. |
| * If the output mode is set to LOOPING, @gst_nonstream_audio_decoder_handle_loop |
| * must be called after playback moved back to the start of a loop. |
| * @decode: Always required. |
| * Allocates an output buffer, fills it with decoded audio samples, and must be passed on to |
| * *buffer . The number of decoded samples must be passed on to *num_samples. |
| * If decoding finishes or the decoding is no longer possible (for example, due to an |
| * unrecoverable error), this function returns FALSE, otherwise TRUE. |
| * @decide_allocation: Optional. |
| * Sets up the allocation parameters for allocating output |
| * buffers. The passed in query contains the result of the |
| * downstream allocation query. |
| * Subclasses should chain up to the parent implementation to |
| * invoke the default handler. |
| * @propose_allocation: Optional. |
| * Proposes buffer allocation parameters for upstream elements. |
| * Subclasses should chain up to the parent implementation to |
| * invoke the default handler. |
| * |
| * Subclasses can override any of the available optional virtual methods or not, as |
| * needed. At minimum, @load_from_buffer (or @load_from_custom), @get_supported_output_modes, |
| * and @decode need to be overridden. |
| * |
| * All functions are called with a locked decoder mutex. |
| * |
| * <note> If GST_ELEMENT_ERROR, GST_ELEMENT_WARNING, or GST_ELEMENT_INFO are called from |
| * inside one of these functions, it is strongly recommended to unlock the decoder mutex |
| * before and re-lock it after these macros to prevent potential deadlocks in case the |
| * application does something with the element when it receives an ERROR/WARNING/INFO |
| * message. Same goes for gst_element_post_message() calls and non-serialized events. </note> |
| * |
| * By default, this class works by reading media data from the sinkpad, and then commencing |
| * playback. Some decoders cannot be given data from a memory block, so the usual way of |
| * reading all upstream data and passing it to @load_from_buffer doesn't work then. In this case, |
| * set the value of loads_from_sinkpad to FALSE. This changes the way this class operates; |
| * it does not require a sinkpad to exist anymore, and will call @load_from_custom instead. |
| * One example of a decoder where this makes sense is UADE (Unix Amiga Delitracker Emulator). |
| * For some formats (such as TFMX), it needs to do the file loading by itself. |
| * Since most decoders can read input data from a memory block, the default value of |
| * loads_from_sinkpad is TRUE. |
| */ |
| struct _GstNonstreamAudioDecoderClass |
| { |
| GstElementClass element_class; |
| |
| gboolean loads_from_sinkpad; |
| |
| /*< public > */ |
| /* virtual methods for subclasses */ |
| |
| gboolean (*seek) (GstNonstreamAudioDecoder * dec, |
| GstClockTime * new_position); |
| GstClockTime (*tell) (GstNonstreamAudioDecoder * dec); |
| |
| gboolean (*load_from_buffer) (GstNonstreamAudioDecoder * dec, |
| GstBuffer * source_data, |
| guint initial_subsong, |
| GstNonstreamAudioSubsongMode initial_subsong_mode, |
| GstClockTime * initial_position, |
| GstNonstreamAudioOutputMode * initial_output_mode, |
| gint * initial_num_loops); |
| gboolean (*load_from_custom) (GstNonstreamAudioDecoder * dec, |
| guint initial_subsong, |
| GstNonstreamAudioSubsongMode initial_subsong_mode, |
| GstClockTime * initial_position, |
| GstNonstreamAudioOutputMode * initial_output_mode, |
| gint * initial_num_loops); |
| |
| GstTagList * (*get_main_tags) (GstNonstreamAudioDecoder * dec); |
| |
| gboolean (*set_current_subsong) (GstNonstreamAudioDecoder * dec, |
| guint subsong, |
| GstClockTime * initial_position); |
| guint (*get_current_subsong) (GstNonstreamAudioDecoder * dec); |
| |
| guint (*get_num_subsongs) (GstNonstreamAudioDecoder * dec); |
| GstClockTime (*get_subsong_duration) (GstNonstreamAudioDecoder * dec, |
| guint subsong); |
| GstTagList * (*get_subsong_tags) (GstNonstreamAudioDecoder * dec, |
| guint subsong); |
| gboolean (*set_subsong_mode) (GstNonstreamAudioDecoder * dec, |
| GstNonstreamAudioSubsongMode mode, |
| GstClockTime * initial_position); |
| |
| gboolean (*set_num_loops) (GstNonstreamAudioDecoder * dec, |
| gint num_loops); |
| gint (*get_num_loops) (GstNonstreamAudioDecoder * dec); |
| |
| guint (*get_supported_output_modes) (GstNonstreamAudioDecoder * dec); |
| gboolean (*set_output_mode) (GstNonstreamAudioDecoder * dec, |
| GstNonstreamAudioOutputMode mode, |
| GstClockTime * current_position); |
| |
| gboolean (*decode) (GstNonstreamAudioDecoder * dec, |
| GstBuffer ** buffer, |
| guint * num_samples); |
| |
| gboolean (*negotiate) (GstNonstreamAudioDecoder * dec); |
| |
| gboolean (*decide_allocation) (GstNonstreamAudioDecoder * dec, |
| GstQuery * query); |
| gboolean (*propose_allocation) (GstNonstreamAudioDecoder * dec, |
| GstQuery * query); |
| |
| /*< private > */ |
| gpointer _gst_reserved[GST_PADDING_LARGE]; |
| }; |
| |
| |
| GST_AUDIO_BAD_API |
| GType gst_nonstream_audio_decoder_get_type (void); |
| |
| |
| GST_AUDIO_BAD_API |
| void gst_nonstream_audio_decoder_handle_loop (GstNonstreamAudioDecoder * dec, |
| GstClockTime new_position); |
| |
| GST_AUDIO_BAD_API |
| gboolean gst_nonstream_audio_decoder_set_output_format (GstNonstreamAudioDecoder * dec, |
| GstAudioInfo const *audio_info); |
| |
| GST_AUDIO_BAD_API |
| gboolean gst_nonstream_audio_decoder_set_output_format_simple (GstNonstreamAudioDecoder * dec, |
| guint sample_rate, |
| GstAudioFormat sample_format, |
| guint num_channels); |
| |
| GST_AUDIO_BAD_API |
| void gst_nonstream_audio_decoder_get_downstream_info (GstNonstreamAudioDecoder * dec, |
| GstAudioFormat * format, |
| gint * sample_rate, |
| gint * num_channels); |
| |
| GST_AUDIO_BAD_API |
| GstBuffer *gst_nonstream_audio_decoder_allocate_output_buffer (GstNonstreamAudioDecoder * dec, |
| gsize size); |
| |
| |
| G_END_DECLS |
| |
| |
| #endif /* __GST_NONSTREAM_AUDIO_DECODER_H__ */ |