diff options
author | Jan Schmidt <jan@centricular.com> | 2013-12-26 23:21:45 +1100 |
---|---|---|
committer | Jan Schmidt <jan@centricular.com> | 2013-12-27 04:04:45 +1100 |
commit | c24a1254c9f1f73e23a1471ce9dd08f513618c8b (patch) | |
tree | c68e0e95c92fd70529d191e33ac3bd0750a8e829 /gst-libs/gst/audio/gstaudiodecoder.c | |
parent | 01c7fb11ba17bd70bd00ab5c2db6639ea9da3458 (diff) |
audiodecoder: Choose a default initial caps before sending GAP
If there are no caps from the audio decoder when handling a GAP
event - as when one is received right at the start on a DVD without
initial audio - then choose any default caps for downstream and
then send the GAP, so the audio sink has a configured format in
which to start the ringbuffer.
Also, make the audio sink reject a GAP without caps with a clearer
error message.
Fixes bug https://bugzilla.gnome.org/show_bug.cgi?id=603921
Diffstat (limited to 'gst-libs/gst/audio/gstaudiodecoder.c')
-rw-r--r-- | gst-libs/gst/audio/gstaudiodecoder.c | 114 |
1 files changed, 82 insertions, 32 deletions
diff --git a/gst-libs/gst/audio/gstaudiodecoder.c b/gst-libs/gst/audio/gstaudiodecoder.c index c8068716e..7bd338f17 100644 --- a/gst-libs/gst/audio/gstaudiodecoder.c +++ b/gst-libs/gst/audio/gstaudiodecoder.c | |||
@@ -1732,6 +1732,86 @@ gst_audio_decoder_do_byte (GstAudioDecoder * dec) | |||
1732 | dec->priv->ctx.info.rate <= dec->priv->samples_out; | 1732 | dec->priv->ctx.info.rate <= dec->priv->samples_out; |
1733 | } | 1733 | } |
1734 | 1734 | ||
1735 | /* Must be called holding the GST_AUDIO_DECODER_STREAM_LOCK */ | ||
1736 | static gboolean | ||
1737 | gst_audio_decoder_negotiate_default_caps (GstAudioDecoder * dec) | ||
1738 | { | ||
1739 | GstCaps *caps; | ||
1740 | |||
1741 | caps = gst_pad_get_current_caps (dec->srcpad); | ||
1742 | if (caps && !gst_audio_info_from_caps (&dec->priv->ctx.info, caps)) | ||
1743 | return FALSE; | ||
1744 | |||
1745 | caps = gst_pad_get_allowed_caps (dec->srcpad); | ||
1746 | if (!caps || gst_caps_is_empty (caps) || gst_caps_is_any (caps)) | ||
1747 | return FALSE; | ||
1748 | |||
1749 | caps = gst_caps_fixate (caps); | ||
1750 | if (!caps || !gst_audio_info_from_caps (&dec->priv->ctx.info, caps)) | ||
1751 | return FALSE; | ||
1752 | |||
1753 | GST_INFO_OBJECT (dec, | ||
1754 | "Chose default caps %" GST_PTR_FORMAT " for initial gap", caps); | ||
1755 | gst_caps_unref (caps); | ||
1756 | |||
1757 | if (!gst_audio_decoder_negotiate_unlocked (dec)) { | ||
1758 | GST_INFO_OBJECT (dec, "Failed to negotiate default caps for initial gap"); | ||
1759 | gst_pad_mark_reconfigure (dec->srcpad); | ||
1760 | return FALSE; | ||
1761 | } | ||
1762 | |||
1763 | return TRUE; | ||
1764 | } | ||
1765 | |||
1766 | static gboolean | ||
1767 | gst_audio_decoder_handle_gap (GstAudioDecoder * dec, GstEvent * event) | ||
1768 | { | ||
1769 | gboolean ret; | ||
1770 | GstClockTime timestamp, duration; | ||
1771 | |||
1772 | /* Ensure we have caps first */ | ||
1773 | GST_AUDIO_DECODER_STREAM_LOCK (dec); | ||
1774 | if (!GST_AUDIO_INFO_IS_VALID (&dec->priv->ctx.info)) { | ||
1775 | if (!gst_audio_decoder_negotiate_default_caps (dec)) { | ||
1776 | GST_ELEMENT_ERROR (dec, STREAM, FORMAT, (NULL), | ||
1777 | ("Decoder output not negotiated before GAP event.")); | ||
1778 | GST_AUDIO_DECODER_STREAM_UNLOCK (dec); | ||
1779 | return FALSE; | ||
1780 | } | ||
1781 | } | ||
1782 | GST_AUDIO_DECODER_STREAM_UNLOCK (dec); | ||
1783 | |||
1784 | gst_event_parse_gap (event, ×tamp, &duration); | ||
1785 | |||
1786 | /* time progressed without data, see if we can fill the gap with | ||
1787 | * some concealment data */ | ||
1788 | GST_DEBUG_OBJECT (dec, | ||
1789 | "gap event: plc %d, do_plc %d, position %" GST_TIME_FORMAT | ||
1790 | " duration %" GST_TIME_FORMAT, | ||
1791 | dec->priv->plc, dec->priv->ctx.do_plc, | ||
1792 | GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration)); | ||
1793 | |||
1794 | if (dec->priv->plc && dec->priv->ctx.do_plc && dec->input_segment.rate > 0.0) { | ||
1795 | GstAudioDecoderClass *klass = GST_AUDIO_DECODER_GET_CLASS (dec); | ||
1796 | GstBuffer *buf; | ||
1797 | |||
1798 | /* hand subclass empty frame with duration that needs covering */ | ||
1799 | buf = gst_buffer_new (); | ||
1800 | GST_BUFFER_TIMESTAMP (buf) = timestamp; | ||
1801 | GST_BUFFER_DURATION (buf) = duration; | ||
1802 | /* best effort, not much error handling */ | ||
1803 | gst_audio_decoder_handle_frame (dec, klass, buf); | ||
1804 | ret = TRUE; | ||
1805 | gst_event_unref (event); | ||
1806 | } else { | ||
1807 | /* sub-class doesn't know how to handle empty buffers, | ||
1808 | * so just try sending GAP downstream */ | ||
1809 | send_pending_events (dec); | ||
1810 | ret = gst_audio_decoder_push_event (dec, event); | ||
1811 | } | ||
1812 | return ret; | ||
1813 | } | ||
1814 | |||
1735 | static gboolean | 1815 | static gboolean |
1736 | gst_audio_decoder_sink_eventfunc (GstAudioDecoder * dec, GstEvent * event) | 1816 | gst_audio_decoder_sink_eventfunc (GstAudioDecoder * dec, GstEvent * event) |
1737 | { | 1817 | { |
@@ -1819,39 +1899,9 @@ gst_audio_decoder_sink_eventfunc (GstAudioDecoder * dec, GstEvent * event) | |||
1819 | ret = TRUE; | 1899 | ret = TRUE; |
1820 | break; | 1900 | break; |
1821 | } | 1901 | } |
1822 | case GST_EVENT_GAP:{ | 1902 | case GST_EVENT_GAP: |
1823 | GstClockTime timestamp, duration; | 1903 | ret = gst_audio_decoder_handle_gap (dec, event); |
1824 | gst_event_parse_gap (event, ×tamp, &duration); | ||
1825 | |||
1826 | /* time progressed without data, see if we can fill the gap with | ||
1827 | * some concealment data */ | ||
1828 | GST_DEBUG_OBJECT (dec, | ||
1829 | "gap event: plc %d, do_plc %d, position %" GST_TIME_FORMAT | ||
1830 | " duration %" GST_TIME_FORMAT, | ||
1831 | dec->priv->plc, dec->priv->ctx.do_plc, | ||
1832 | GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration)); | ||
1833 | if (dec->priv->plc && dec->priv->ctx.do_plc && | ||
1834 | dec->input_segment.rate > 0.0) { | ||
1835 | GstAudioDecoderClass *klass; | ||
1836 | GstBuffer *buf; | ||
1837 | |||
1838 | klass = GST_AUDIO_DECODER_GET_CLASS (dec); | ||
1839 | /* hand subclass empty frame with duration that needs covering */ | ||
1840 | buf = gst_buffer_new (); | ||
1841 | GST_BUFFER_TIMESTAMP (buf) = timestamp; | ||
1842 | GST_BUFFER_DURATION (buf) = duration; | ||
1843 | /* best effort, not much error handling */ | ||
1844 | gst_audio_decoder_handle_frame (dec, klass, buf); | ||
1845 | ret = TRUE; | ||
1846 | gst_event_unref (event); | ||
1847 | } else { | ||
1848 | /* FIXME: sub-class doesn't know how to handle empty buffers, | ||
1849 | * so just try sending GAP downstream */ | ||
1850 | send_pending_events (dec); | ||
1851 | ret = gst_audio_decoder_push_event (dec, event); | ||
1852 | } | ||
1853 | break; | 1904 | break; |
1854 | } | ||
1855 | case GST_EVENT_FLUSH_STOP: | 1905 | case GST_EVENT_FLUSH_STOP: |
1856 | GST_AUDIO_DECODER_STREAM_LOCK (dec); | 1906 | GST_AUDIO_DECODER_STREAM_LOCK (dec); |
1857 | /* prepare for fresh start */ | 1907 | /* prepare for fresh start */ |