mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 16:50:47 +00:00
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.
|
|
*
|
|
* > 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.
|
|
*
|
|
* 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__ */
|