diff mbox series

[FFmpeg-devel,2/5] avdevice/alsa_dec: make sure we have enough data in non-blocking mode

Message ID 20210221164659.19180-2-cus@passwd.hu
State Superseded
Headers show
Series [FFmpeg-devel,1/5] avdevice/alsa_dec: do not set codecpar frame_size | expand

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished
andriy/PPC64_make success Make finished
andriy/PPC64_make_fate success Make fate finished

Commit Message

Marton Balint Feb. 21, 2021, 4:46 p.m. UTC
Otherwise we might return 1-2 samples per packet if av_read_frame() call rate is
only sligthly less than the stream sample rate.

Signed-off-by: Marton Balint <cus@passwd.hu>
---
 libavdevice/alsa_dec.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

Comments

Nicolas George Feb. 28, 2021, 1:02 p.m. UTC | #1
Marton Balint (12021-02-21):
> Otherwise we might return 1-2 samples per packet if av_read_frame() call rate is
> only sligthly less than the stream sample rate.
> 
> Signed-off-by: Marton Balint <cus@passwd.hu>
> ---
>  libavdevice/alsa_dec.c | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)

Looping snd_pcm_readi() seems like a more robust solution to this issue.

Regards,
Marton Balint Feb. 28, 2021, 1:42 p.m. UTC | #2
On Sun, 28 Feb 2021, Nicolas George wrote:

> Marton Balint (12021-02-21):
>> Otherwise we might return 1-2 samples per packet if av_read_frame() call rate is
>> only sligthly less than the stream sample rate.
>>
>> Signed-off-by: Marton Balint <cus@passwd.hu>
>> ---
>>  libavdevice/alsa_dec.c | 18 ++++++++++++++++++
>>  1 file changed, 18 insertions(+)
>
> Looping snd_pcm_readi() seems like a more robust solution to this issue.

Robust how? For non-blocking mode that would mean you have to keep the 
read data in the context if you read less than period size. Doable, but 
I wanted to avoid it.

Regards,
Marton
Nicolas George Feb. 28, 2021, 1:46 p.m. UTC | #3
Marton Balint (12021-02-28):
> Robust how? For non-blocking mode that would mean you have to keep the read
> data in the context if you read less than period size. Doable, but I wanted
> to avoid it.

That is exactly what I am suggesting. It does not rely on less tested
functions like snd_pcm_avail() (I have observed bugs with this kind of
functions and some of the infrastructure plugins), and it does not
require starting the PCM manually at seemingly random places in the
code.

Regards,
diff mbox series

Patch

diff --git a/libavdevice/alsa_dec.c b/libavdevice/alsa_dec.c
index 6d568737b3..8e5c53f56b 100644
--- a/libavdevice/alsa_dec.c
+++ b/libavdevice/alsa_dec.c
@@ -78,6 +78,12 @@  static av_cold int audio_read_header(AVFormatContext *s1)
         return AVERROR(EIO);
     }
 
+    ret = snd_pcm_start(s->h);
+    if (ret < 0) {
+        av_log(s1, AV_LOG_ERROR, "cannot start pcm (%s)\n", snd_strerror(ret));
+        goto fail;
+    }
+
     /* take real parameters */
     st->codecpar->codec_type  = AVMEDIA_TYPE_AUDIO;
     st->codecpar->codec_id    = codec_id;
@@ -104,6 +110,13 @@  static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
     int64_t dts;
     snd_pcm_sframes_t delay = 0;
 
+    // Avoid returning 1-2 samples if call rate is slightly less than sample rate
+    if (s1->flags & AVFMT_FLAG_NONBLOCK) {
+        res = snd_pcm_avail(s->h);
+        if (res >= 0 && res < s->period_size)
+            return AVERROR(EAGAIN);
+    }
+
     if (av_new_packet(pkt, s->period_size * s->frame_size) < 0) {
         return AVERROR(EIO);
     }
@@ -121,6 +134,11 @@  static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
 
             return AVERROR(EIO);
         }
+        res = snd_pcm_start(s->h);
+        if (res < 0) {
+            av_log(s1, AV_LOG_ERROR, "cannot start pcm after recovery (%s)\n", snd_strerror(res));
+            return AVERROR(EIO);
+        }
         ff_timefilter_reset(s->timefilter);
     }