Commit bb6d00f0 authored by Michael Niedermayer's avatar Michael Niedermayer

Merge remote-tracking branch 'lukaszmluki/master'

* lukaszmluki/master:
  lavd/pulse_audio_enc: respect minreq while checking buffer fullness
  lavd/pulse_audio_enc: signal that buffer is still writable after write
  lavd/pulse_audio_enc: add pointer checks
  lavd/pulse_audio_enc: add more buffer attributes
  lavd/fbdev_dec: implement fbdev_get_device_list callback
  lavd/fbdev_enc: move list device code to fbdev_common
  lavd/fbdev_enc: remove redundant assignments
Merged-by: 's avatarMichael Niedermayer <michaelni@gmx.at>
parents 421b21ca 5bef4878
...@@ -290,6 +290,20 @@ When both options are provided then the highest value is used ...@@ -290,6 +290,20 @@ When both options are provided then the highest value is used
are set to 0 (which is default), the device will use the default are set to 0 (which is default), the device will use the default
PulseAudio duration value. By default PulseAudio set buffer duration PulseAudio duration value. By default PulseAudio set buffer duration
to around 2 seconds. to around 2 seconds.
@item prebuf
Specify pre-buffering size in bytes. The server does not start with
playback before at least @option{prebuf} bytes are available in the
buffer. By default this option is initialized to the same value as
@option{buffer_size} or @option{buffer_duration} (whichever is bigger).
@item minreq
Specify minimum request size in bytes. The server does not request less
than @option{minreq} bytes from the client, instead waits until the buffer
is free enough to request more bytes at once. It is recommended to not set
this option, which will initialize this to a value that is deemed sensible
by the server.
@end table @end table
@subsection Examples @subsection Examples
......
...@@ -20,9 +20,13 @@ ...@@ -20,9 +20,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdlib.h> #include <stdlib.h>
#include "fbdev_common.h" #include "fbdev_common.h"
#include "libavutil/common.h" #include "libavutil/common.h"
#include "avdevice.h"
struct rgb_pixfmt_map_entry { struct rgb_pixfmt_map_entry {
int bits_per_pixel; int bits_per_pixel;
...@@ -65,3 +69,61 @@ const char* ff_fbdev_default_device() ...@@ -65,3 +69,61 @@ const char* ff_fbdev_default_device()
return dev; return dev;
} }
int ff_fbdev_get_device_list(AVDeviceInfoList *device_list)
{
struct fb_var_screeninfo varinfo;
struct fb_fix_screeninfo fixinfo;
char device_file[12];
AVDeviceInfo *device = NULL;
int i, fd, ret = 0;
const char *default_device = ff_fbdev_default_device();
if (!device_list)
return AVERROR(EINVAL);
for (i = 0; i <= 31; i++) {
snprintf(device_file, sizeof(device_file), "/dev/fb%d", i);
if ((fd = avpriv_open(device_file, O_RDWR)) < 0)
continue;
if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) == -1)
goto fail_device;
if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) == -1)
goto fail_device;
device = av_mallocz(sizeof(AVDeviceInfo));
if (!device) {
ret = AVERROR(ENOMEM);
goto fail_device;
}
device->device_name = av_strdup(device_file);
device->device_description = av_strdup(fixinfo.id);
if (!device->device_name || !device->device_description) {
ret = AVERROR(ENOMEM);
goto fail_device;
}
if ((ret = av_dynarray_add_nofree(&device_list->devices,
&device_list->nb_devices, device)) < 0)
goto fail_device;
if (default_device && !strcmp(device->device_name, default_device)) {
device_list->default_device = device_list->nb_devices - 1;
default_device = NULL;
}
close(fd);
continue;
fail_device:
if (device) {
av_free(device->device_name);
av_free(device->device_description);
av_freep(&device);
}
if (fd >= 0)
close(fd);
if (ret < 0)
return ret;
}
return 0;
}
...@@ -27,8 +27,12 @@ ...@@ -27,8 +27,12 @@
#include <linux/fb.h> #include <linux/fb.h>
#include "libavutil/pixfmt.h" #include "libavutil/pixfmt.h"
struct AVDeviceInfoList;
enum AVPixelFormat ff_get_pixfmt_from_fb_varinfo(struct fb_var_screeninfo *varinfo); enum AVPixelFormat ff_get_pixfmt_from_fb_varinfo(struct fb_var_screeninfo *varinfo);
const char* ff_fbdev_default_device(void); const char* ff_fbdev_default_device(void);
int ff_fbdev_get_device_list(struct AVDeviceInfoList *device_list);
#endif /* AVDEVICE_FBDEV_COMMON_H */ #endif /* AVDEVICE_FBDEV_COMMON_H */
...@@ -205,6 +205,11 @@ static av_cold int fbdev_read_close(AVFormatContext *avctx) ...@@ -205,6 +205,11 @@ static av_cold int fbdev_read_close(AVFormatContext *avctx)
return 0; return 0;
} }
static int fbdev_get_device_list(AVFormatContext *s, AVDeviceInfoList *device_list)
{
return ff_fbdev_get_device_list(device_list);
}
#define OFFSET(x) offsetof(FBDevContext, x) #define OFFSET(x) offsetof(FBDevContext, x)
#define DEC AV_OPT_FLAG_DECODING_PARAM #define DEC AV_OPT_FLAG_DECODING_PARAM
static const AVOption options[] = { static const AVOption options[] = {
...@@ -227,6 +232,7 @@ AVInputFormat ff_fbdev_demuxer = { ...@@ -227,6 +232,7 @@ AVInputFormat ff_fbdev_demuxer = {
.read_header = fbdev_read_header, .read_header = fbdev_read_header,
.read_packet = fbdev_read_packet, .read_packet = fbdev_read_packet,
.read_close = fbdev_read_close, .read_close = fbdev_read_close,
.get_device_list = fbdev_get_device_list,
.flags = AVFMT_NOFILE, .flags = AVFMT_NOFILE,
.priv_class = &fbdev_class, .priv_class = &fbdev_class,
}; };
...@@ -186,64 +186,7 @@ static av_cold int fbdev_write_trailer(AVFormatContext *h) ...@@ -186,64 +186,7 @@ static av_cold int fbdev_write_trailer(AVFormatContext *h)
static int fbdev_get_device_list(AVFormatContext *s, AVDeviceInfoList *device_list) static int fbdev_get_device_list(AVFormatContext *s, AVDeviceInfoList *device_list)
{ {
struct fb_var_screeninfo varinfo; return ff_fbdev_get_device_list(device_list);
struct fb_fix_screeninfo fixinfo;
char device_file[12];
AVDeviceInfo *device = NULL;
int i, fd = -1, ret = 0;
const char *default_device = ff_fbdev_default_device();
if (!device_list)
return AVERROR(EINVAL);
for (i = 0; i <= 31; i++) {
snprintf(device_file, sizeof(device_file), "/dev/fb%d", i);
if ((fd = avpriv_open(device_file, O_RDWR)) < 0)
continue;
if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) == -1)
goto fail_device;
if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) == -1)
goto fail_device;
device = av_mallocz(sizeof(AVDeviceInfo));
if (!device) {
ret = AVERROR(ENOMEM);
goto fail_device;
}
device->device_name = av_strdup(device_file);
device->device_description = av_strdup(fixinfo.id);
if (!device->device_name || !device->device_description) {
ret = AVERROR(ENOMEM);
goto fail_device;
}
if ((ret = av_dynarray_add_nofree(&device_list->devices,
&device_list->nb_devices, device)) < 0)
goto fail_device;
if (default_device && !strcmp(device->device_name, default_device)) {
device_list->default_device = device_list->nb_devices - 1;
default_device = NULL;
}
close(fd);
fd = -1;
continue;
fail_device:
if (device) {
av_free(device->device_name);
av_free(device->device_description);
av_freep(&device);
}
if (fd >= 0) {
close(fd);
fd = -1;
}
if (ret < 0)
return ret;
}
return 0;
} }
#define OFFSET(x) offsetof(FBDevContext, x) #define OFFSET(x) offsetof(FBDevContext, x)
......
...@@ -38,6 +38,8 @@ typedef struct PulseData { ...@@ -38,6 +38,8 @@ typedef struct PulseData {
int64_t timestamp; int64_t timestamp;
int buffer_size; /**< Buffer size in bytes */ int buffer_size; /**< Buffer size in bytes */
int buffer_duration; /**< Buffer size in ms, recalculated to buffer_size */ int buffer_duration; /**< Buffer size in ms, recalculated to buffer_size */
int prebuf;
int minreq;
int last_result; int last_result;
pa_threaded_mainloop *mainloop; pa_threaded_mainloop *mainloop;
pa_context *ctx; pa_context *ctx;
...@@ -475,6 +477,10 @@ static av_cold int pulse_write_header(AVFormatContext *h) ...@@ -475,6 +477,10 @@ static av_cold int pulse_write_header(AVFormatContext *h)
av_log(s, AV_LOG_DEBUG, "Real buffer length is %u bytes\n", buffer_attributes.tlength); av_log(s, AV_LOG_DEBUG, "Real buffer length is %u bytes\n", buffer_attributes.tlength);
} else if (s->buffer_size) } else if (s->buffer_size)
buffer_attributes.tlength = s->buffer_size; buffer_attributes.tlength = s->buffer_size;
if (s->prebuf)
buffer_attributes.prebuf = s->prebuf;
if (s->minreq)
buffer_attributes.minreq = s->minreq;
sample_spec.format = ff_codec_id_to_pulse_format(st->codec->codec_id); sample_spec.format = ff_codec_id_to_pulse_format(st->codec->codec_id);
sample_spec.rate = st->codec->sample_rate; sample_spec.rate = st->codec->sample_rate;
...@@ -578,6 +584,14 @@ static av_cold int pulse_write_header(AVFormatContext *h) ...@@ -578,6 +584,14 @@ static av_cold int pulse_write_header(AVFormatContext *h)
goto fail; goto fail;
} }
/* read back buffer attributes for future use */
buffer_attributes = *pa_stream_get_buffer_attr(s->stream);
s->buffer_size = buffer_attributes.tlength;
s->prebuf = buffer_attributes.prebuf;
s->minreq = buffer_attributes.minreq;
av_log(s, AV_LOG_DEBUG, "Real buffer attributes: size: %d, prebuf: %d, minreq: %d\n",
s->buffer_size, s->prebuf, s->minreq);
pa_threaded_mainloop_unlock(s->mainloop); pa_threaded_mainloop_unlock(s->mainloop);
if ((ret = pulse_subscribe_events(s)) < 0) { if ((ret = pulse_subscribe_events(s)) < 0) {
...@@ -610,6 +624,7 @@ static int pulse_write_packet(AVFormatContext *h, AVPacket *pkt) ...@@ -610,6 +624,7 @@ static int pulse_write_packet(AVFormatContext *h, AVPacket *pkt)
{ {
PulseData *s = h->priv_data; PulseData *s = h->priv_data;
int ret; int ret;
int64_t writable_size;
if (!pkt) if (!pkt)
return pulse_flash_stream(s); return pulse_flash_stream(s);
...@@ -632,7 +647,7 @@ static int pulse_write_packet(AVFormatContext *h, AVPacket *pkt) ...@@ -632,7 +647,7 @@ static int pulse_write_packet(AVFormatContext *h, AVPacket *pkt)
av_log(s, AV_LOG_ERROR, "PulseAudio stream is in invalid state.\n"); av_log(s, AV_LOG_ERROR, "PulseAudio stream is in invalid state.\n");
goto fail; goto fail;
} }
while (!pa_stream_writable_size(s->stream)) { while (pa_stream_writable_size(s->stream) < s->minreq) {
if (s->nonblocking) { if (s->nonblocking) {
pa_threaded_mainloop_unlock(s->mainloop); pa_threaded_mainloop_unlock(s->mainloop);
return AVERROR(EAGAIN); return AVERROR(EAGAIN);
...@@ -644,6 +659,9 @@ static int pulse_write_packet(AVFormatContext *h, AVPacket *pkt) ...@@ -644,6 +659,9 @@ static int pulse_write_packet(AVFormatContext *h, AVPacket *pkt)
av_log(s, AV_LOG_ERROR, "pa_stream_write failed: %s\n", pa_strerror(ret)); av_log(s, AV_LOG_ERROR, "pa_stream_write failed: %s\n", pa_strerror(ret));
goto fail; goto fail;
} }
if ((writable_size = pa_stream_writable_size(s->stream)) >= s->minreq)
avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_BUFFER_WRITABLE, &writable_size, sizeof(writable_size));
pa_threaded_mainloop_unlock(s->mainloop); pa_threaded_mainloop_unlock(s->mainloop);
return 0; return 0;
...@@ -678,7 +696,9 @@ static void pulse_get_output_timestamp(AVFormatContext *h, int stream, int64_t * ...@@ -678,7 +696,9 @@ static void pulse_get_output_timestamp(AVFormatContext *h, int stream, int64_t *
pa_threaded_mainloop_lock(s->mainloop); pa_threaded_mainloop_lock(s->mainloop);
pa_stream_get_latency(s->stream, &latency, &neg); pa_stream_get_latency(s->stream, &latency, &neg);
pa_threaded_mainloop_unlock(s->mainloop); pa_threaded_mainloop_unlock(s->mainloop);
if (wall)
*wall = av_gettime(); *wall = av_gettime();
if (dts)
*dts = s->timestamp - (neg ? -latency : latency); *dts = s->timestamp - (neg ? -latency : latency);
} }
...@@ -745,6 +765,8 @@ static const AVOption options[] = { ...@@ -745,6 +765,8 @@ static const AVOption options[] = {
{ "device", "set device name", OFFSET(device), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, { "device", "set device name", OFFSET(device), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
{ "buffer_size", "set buffer size in bytes", OFFSET(buffer_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, { "buffer_size", "set buffer size in bytes", OFFSET(buffer_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
{ "buffer_duration", "set buffer duration in millisecs", OFFSET(buffer_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, { "buffer_duration", "set buffer duration in millisecs", OFFSET(buffer_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
{ "prebuf", "set pre-buffering size", OFFSET(prebuf), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
{ "minreq", "set minimum request size", OFFSET(minreq), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
{ NULL } { NULL }
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment