aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarton Balint <cus@passwd.hu>2021-02-06 19:48:51 +0100
committerMarton Balint <cus@passwd.hu>2021-03-12 23:55:30 +0100
commitb2d0826513c5e76f9bad2f1f0c809bc5c8e58b0c (patch)
tree1ac0aea9a27370f232f989949dd3f41eb62c4482
parent7f059a250bb7bcbf7bba537c1a059a5934413035 (diff)
downloadffmpeg-b2d0826513c5e76f9bad2f1f0c809bc5c8e58b0c.tar.gz
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>
-rw-r--r--libavdevice/pulse_audio_dec.c71
1 files changed, 41 insertions, 30 deletions
diff --git a/libavdevice/pulse_audio_dec.c b/libavdevice/pulse_audio_dec.c
index 0454a643dd..3777396ef6 100644
--- a/libavdevice/pulse_audio_dec.c
+++ b/libavdevice/pulse_audio_dec.c
@@ -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;
}