mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-26 18:20:44 +00:00
6b8f92d84f
We need different export decorators for the different libs. For now no actual change though, just rename before the release, and add prelude headers to define the new decorator to GST_EXPORT.
412 lines
22 KiB
C
412 lines
22 KiB
C
/* 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__ */
|