Browse Source

avdevice/pulse_audio_dec: do not read undersized frames

Keep on reading fragments until we got fragment_size amount of data, otherwise
we might get frames with 1-2 samples only if pa_stream_peek is called slightly
less frequently than sample rate.

Note that fragments might contain a lot less data than fragment_size, so
reading multiple fragments to get fragment_size amount of data is intentional.

Signed-off-by: Marton Balint <cus@passwd.hu>
tags/n4.4
Marton Balint 4 years ago
parent
commit
b2d0826513
1 changed files with 41 additions and 30 deletions
  1. +41
    -30
      libavdevice/pulse_audio_dec.c

+ 41
- 30
libavdevice/pulse_audio_dec.c View File

@@ -48,6 +48,7 @@ typedef struct PulseData {
pa_threaded_mainloop *mainloop;
pa_context *context;
pa_stream *stream;
size_t pa_frame_size;

TimeFilter *timefilter;
int last_period;
@@ -250,6 +251,7 @@ static av_cold int pulse_read_header(AVFormatContext *s)
goto unlock_and_fail;
}
pd->fragment_size = queried_attr->fragsize;
pd->pa_frame_size = pa_frame_size(&ss);

pa_threaded_mainloop_unlock(pd->mainloop);

@@ -261,7 +263,7 @@ static av_cold int pulse_read_header(AVFormatContext *s)
avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */

pd->timefilter = ff_timefilter_new(1000000.0 / pd->sample_rate,
1000, 1.5E-6);
pd->fragment_size / pd->pa_frame_size, 1.5E-6);

if (!pd->timefilter) {
pulse_close(s);
@@ -286,12 +288,13 @@ static int pulse_read_packet(AVFormatContext *s, AVPacket *pkt)
int64_t dts;
pa_usec_t latency;
int negative;
ptrdiff_t pos = 0;

pa_threaded_mainloop_lock(pd->mainloop);

CHECK_DEAD_GOTO(pd, ret, unlock_and_fail);

while (!read_data) {
while (pos < pd->fragment_size) {
int r;

r = pa_stream_peek(pd->stream, &read_data, &read_length);
@@ -305,43 +308,51 @@ static int pulse_read_packet(AVFormatContext *s, AVPacket *pkt)
* silence, but that wouldn't work for compressed streams. */
r = pa_stream_drop(pd->stream);
CHECK_SUCCESS_GOTO(ret, r == 0, unlock_and_fail);
} else {
if (!pos) {
if (av_new_packet(pkt, pd->fragment_size) < 0) {
ret = AVERROR(ENOMEM);
goto unlock_and_fail;
}

dts = av_gettime();
pa_operation_unref(pa_stream_update_timing_info(pd->stream, NULL, NULL));

if (pa_stream_get_latency(pd->stream, &latency, &negative) >= 0) {
if (negative) {
dts += latency;
} else
dts -= latency;
} else {
av_log(s, AV_LOG_WARNING, "pa_stream_get_latency() failed\n");
}
}
if (pkt->size - pos < read_length) {
if (pos)
break;
pa_stream_drop(pd->stream);
/* Oversized fragment??? */
ret = AVERROR_EXTERNAL;
goto unlock_and_fail;
}
memcpy(pkt->data + pos, read_data, read_length);
pos += read_length;
pa_stream_drop(pd->stream);
}
}

if (av_new_packet(pkt, read_length) < 0) {
ret = AVERROR(ENOMEM);
goto unlock_and_fail;
}

dts = av_gettime();
pa_operation_unref(pa_stream_update_timing_info(pd->stream, NULL, NULL));

if (pa_stream_get_latency(pd->stream, &latency, &negative) >= 0) {
enum AVCodecID codec_id =
s->audio_codec_id == AV_CODEC_ID_NONE ? DEFAULT_CODEC_ID : s->audio_codec_id;
int frame_size = ((av_get_bits_per_sample(codec_id) >> 3) * pd->channels);
int frame_duration = read_length / frame_size;


if (negative) {
dts += latency;
} else
dts -= latency;
if (pd->wallclock)
pkt->pts = ff_timefilter_update(pd->timefilter, dts, pd->last_period);
pa_threaded_mainloop_unlock(pd->mainloop);

pd->last_period = frame_duration;
} else {
av_log(s, AV_LOG_WARNING, "pa_stream_get_latency() failed\n");
}
av_shrink_packet(pkt, pos);

memcpy(pkt->data, read_data, read_length);
pa_stream_drop(pd->stream);
if (pd->wallclock)
pkt->pts = ff_timefilter_update(pd->timefilter, dts, pd->last_period);
pd->last_period = pkt->size / pd->pa_frame_size;

pa_threaded_mainloop_unlock(pd->mainloop);
return 0;

unlock_and_fail:
av_packet_unref(pkt);
pa_threaded_mainloop_unlock(pd->mainloop);
return ret;
}


Loading…
Cancel
Save