aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2014-03-29 16:28:28 +0100
committerMichael Niedermayer <michaelni@gmx.at>2014-03-29 17:07:26 +0100
commitbcd5fd5346be263162792be595eff9fc08e5c853 (patch)
treeb832637e5bce2a8906f5e1802fb3906612c25a27
parent8a9d0a1561470a185a3d09676fcf9b44830a4bfe (diff)
parent3937b40e87c92993df6c62492c59f59cbeb97126 (diff)
downloadffmpeg-bcd5fd5346be263162792be595eff9fc08e5c853.tar.gz
Merge commit 'lukaszmluki/master^'
* commit 'lukaszmluki/master^': lavd/pulse_audio_enc: implement get_device_list callback lavd/pulse_audio_dec: implement get_device_list callback lavd/pulse_audio_common: add device detecting code lavu/mem: add av_dynarray_add_nofree function lavd/pulse_audio_enc: implement write_uncoded_frame callback tools/uncoded_frame: fix audio codec generation Merged-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r--doc/APIchanges3
-rw-r--r--libavdevice/pulse_audio_common.c177
-rw-r--r--libavdevice/pulse_audio_common.h5
-rw-r--r--libavdevice/pulse_audio_dec.c7
-rw-r--r--libavdevice/pulse_audio_enc.c26
-rw-r--r--libavutil/mem.c13
-rw-r--r--libavutil/mem.h19
-rw-r--r--libavutil/version.h2
-rw-r--r--tools/uncoded_frame.c4
9 files changed, 249 insertions, 7 deletions
diff --git a/doc/APIchanges b/doc/APIchanges
index 3890d1d78e..b8d8b8599d 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -15,6 +15,9 @@ libavutil: 2012-10-22
API changes, most recent first:
+2014-03-xx - xxxxxxx - lavu 52.70.100 - mem.h
+ Add av_dynarray_add_nofree() function.
+
2014-02-xx - xxxxxxx - lavu 53.08.0 - frame.h
Add av_frame_remove_side_data() for removing a single side data
instance from a frame.
diff --git a/libavdevice/pulse_audio_common.c b/libavdevice/pulse_audio_common.c
index f7227f6549..cfe97bc7cb 100644
--- a/libavdevice/pulse_audio_common.c
+++ b/libavdevice/pulse_audio_common.c
@@ -1,5 +1,6 @@
/*
- * Pulseaudio input
+ * Pulseaudio common
+ * Copyright (c) 2014 Lukasz Marek
* Copyright (c) 2011 Luca Barbato <lu_zero@gentoo.org>
*
* This file is part of FFmpeg.
@@ -21,6 +22,8 @@
#include "pulse_audio_common.h"
#include "libavutil/attributes.h"
+#include "libavutil/avstring.h"
+#include "libavutil/mem.h"
pa_sample_format_t av_cold ff_codec_id_to_pulse_format(enum AVCodecID codec_id)
{
@@ -39,3 +42,175 @@ pa_sample_format_t av_cold ff_codec_id_to_pulse_format(enum AVCodecID codec_id)
default: return PA_SAMPLE_INVALID;
}
}
+
+enum PulseAudioLoopState {
+ PA_LOOP_INITIALIZING,
+ PA_LOOP_READY,
+ PA_LOOP_FINISHED
+};
+
+typedef struct PulseAudioDeviceList {
+ AVDeviceInfoList *devices;
+ int error_code;
+ int output;
+ char *default_device;
+} PulseAudioDeviceList;
+
+static void pa_state_cb(pa_context *c, void *userdata)
+{
+ enum PulseAudioLoopState *loop_status = userdata;
+
+ switch (pa_context_get_state(c)) {
+ case PA_CONTEXT_FAILED:
+ case PA_CONTEXT_TERMINATED:
+ *loop_status = PA_LOOP_FINISHED;
+ break;
+ case PA_CONTEXT_READY:
+ *loop_status = PA_LOOP_READY;
+ break;
+ default:
+ break;
+ }
+}
+
+static void pulse_add_detected_device(PulseAudioDeviceList *info,
+ const char *name, const char *description)
+{
+ int ret;
+ AVDeviceInfo *new_device = NULL;
+
+ if (info->error_code)
+ return;
+
+ new_device = av_mallocz(sizeof(AVDeviceInfo));
+ if (!new_device) {
+ info->error_code = AVERROR(ENOMEM);
+ return;
+ }
+
+ new_device->device_description = av_strdup(description);
+ new_device->device_name = av_strdup(name);
+
+ if (!new_device->device_description || !new_device->device_name) {
+ info->error_code = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ if ((ret = av_dynarray_add_nofree(&info->devices->devices,
+ &info->devices->nb_devices, new_device)) < 0) {
+ info->error_code = ret;
+ goto fail;
+ }
+ return;
+
+ fail:
+ av_free(new_device->device_description);
+ av_free(new_device->device_name);
+ av_free(new_device);
+
+}
+
+static void pulse_audio_source_device_cb(pa_context *c, const pa_source_info *dev,
+ int eol, void *userdata)
+{
+ if (!eol)
+ pulse_add_detected_device(userdata, dev->name, dev->description);
+}
+
+static void pulse_audio_sink_device_cb(pa_context *c, const pa_sink_info *dev,
+ int eol, void *userdata)
+{
+ if (!eol)
+ pulse_add_detected_device(userdata, dev->name, dev->description);
+}
+
+static void pulse_server_info_cb(pa_context *c, const pa_server_info *i, void *userdata)
+{
+ PulseAudioDeviceList *info = userdata;
+ if (info->output)
+ info->default_device = av_strdup(i->default_sink_name);
+ else
+ info->default_device = av_strdup(i->default_source_name);
+ if (!info->default_device)
+ info->error_code = AVERROR(ENOMEM);
+}
+
+int ff_pulse_audio_get_devices(AVDeviceInfoList *devices, const char *server, int output)
+{
+ pa_mainloop *pa_ml = NULL;
+ pa_mainloop_api *pa_mlapi = NULL;
+ pa_operation *pa_op = NULL;
+ pa_context *pa_ctx = NULL;
+ enum pa_operation_state op_state;
+ enum PulseAudioLoopState loop_state = PA_LOOP_INITIALIZING;
+ PulseAudioDeviceList dev_list = { 0 };
+ int i;
+
+ dev_list.output = output;
+ dev_list.devices = devices;
+ devices->nb_devices = 0;
+ devices->devices = NULL;
+ if (!devices)
+ return AVERROR(EINVAL);
+ if (!(pa_ml = pa_mainloop_new()))
+ return AVERROR(ENOMEM);
+ if (!(pa_mlapi = pa_mainloop_get_api(pa_ml))) {
+ dev_list.error_code = AVERROR_EXTERNAL;
+ goto fail;
+ }
+ if (!(pa_ctx = pa_context_new(pa_mlapi, "Query devices"))) {
+ dev_list.error_code = AVERROR(ENOMEM);
+ goto fail;
+ }
+ pa_context_set_state_callback(pa_ctx, pa_state_cb, &loop_state);
+ if (pa_context_connect(pa_ctx, server, 0, NULL) < 0) {
+ dev_list.error_code = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ while (loop_state == PA_LOOP_INITIALIZING)
+ pa_mainloop_iterate(pa_ml, 1, NULL);
+ if (loop_state == PA_LOOP_FINISHED) {
+ dev_list.error_code = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ if (output)
+ pa_op = pa_context_get_sink_info_list(pa_ctx, pulse_audio_sink_device_cb, &dev_list);
+ else
+ pa_op = pa_context_get_source_info_list(pa_ctx, pulse_audio_source_device_cb, &dev_list);
+ while ((op_state = pa_operation_get_state(pa_op)) == PA_OPERATION_RUNNING)
+ pa_mainloop_iterate(pa_ml, 1, NULL);
+ if (op_state != PA_OPERATION_DONE)
+ dev_list.error_code = AVERROR_EXTERNAL;
+ pa_operation_unref(pa_op);
+ if (dev_list.error_code < 0)
+ goto fail;
+
+ pa_op = pa_context_get_server_info(pa_ctx, pulse_server_info_cb, &dev_list);
+ while ((op_state = pa_operation_get_state(pa_op)) == PA_OPERATION_RUNNING)
+ pa_mainloop_iterate(pa_ml, 1, NULL);
+ if (op_state != PA_OPERATION_DONE)
+ dev_list.error_code = AVERROR_EXTERNAL;
+ pa_operation_unref(pa_op);
+ if (dev_list.error_code < 0)
+ goto fail;
+
+ devices->default_device = -1;
+ for (i = 0; i < devices->nb_devices; i++) {
+ if (!strcmp(devices->devices[i]->device_name, dev_list.default_device)) {
+ devices->default_device = i;
+ break;
+ }
+ }
+
+ fail:
+ av_free(dev_list.default_device);
+ if(pa_ctx)
+ pa_context_disconnect(pa_ctx);
+ if (pa_ctx)
+ pa_context_unref(pa_ctx);
+ if (pa_ml)
+ pa_mainloop_free(pa_ml);
+ return dev_list.error_code;
+}
diff --git a/libavdevice/pulse_audio_common.h b/libavdevice/pulse_audio_common.h
index 99ba6a31f1..b049cdea1a 100644
--- a/libavdevice/pulse_audio_common.h
+++ b/libavdevice/pulse_audio_common.h
@@ -22,9 +22,12 @@
#ifndef AVDEVICE_PULSE_AUDIO_COMMON_H
#define AVDEVICE_PULSE_AUDIO_COMMON_H
-#include <pulse/simple.h>
+#include <pulse/pulseaudio.h>
#include "libavcodec/avcodec.h"
+#include "avdevice.h"
pa_sample_format_t ff_codec_id_to_pulse_format(enum AVCodecID codec_id);
+int ff_pulse_audio_get_devices(AVDeviceInfoList *devices, const char *server, int output);
+
#endif /* AVDEVICE_PULSE_AUDIO_COMMON_H */
diff --git a/libavdevice/pulse_audio_dec.c b/libavdevice/pulse_audio_dec.c
index 49d6f7e7c7..ec94fe1b4a 100644
--- a/libavdevice/pulse_audio_dec.c
+++ b/libavdevice/pulse_audio_dec.c
@@ -147,6 +147,12 @@ static av_cold int pulse_close(AVFormatContext *s)
return 0;
}
+static int pulse_get_device_list(AVFormatContext *h, AVDeviceInfoList *device_list)
+{
+ PulseData *s = h->priv_data;
+ return ff_pulse_audio_get_devices(device_list, s->server, 0);
+}
+
#define OFFSET(a) offsetof(PulseData, a)
#define D AV_OPT_FLAG_DECODING_PARAM
@@ -176,6 +182,7 @@ AVInputFormat ff_pulse_demuxer = {
.read_header = pulse_read_header,
.read_packet = pulse_read_packet,
.read_close = pulse_close,
+ .get_device_list = pulse_get_device_list,
.flags = AVFMT_NOFILE,
.priv_class = &pulse_demuxer_class,
};
diff --git a/libavdevice/pulse_audio_enc.c b/libavdevice/pulse_audio_enc.c
index 4fb64ed471..fa2a7cb0c5 100644
--- a/libavdevice/pulse_audio_enc.c
+++ b/libavdevice/pulse_audio_enc.c
@@ -141,6 +141,24 @@ static int pulse_write_packet(AVFormatContext *h, AVPacket *pkt)
return 0;
}
+static int pulse_write_frame(AVFormatContext *h, int stream_index,
+ AVFrame **frame, unsigned flags)
+{
+ AVPacket pkt;
+
+ /* Planar formats are not supported yet. */
+ if (flags & AV_WRITE_UNCODED_FRAME_QUERY)
+ return av_sample_fmt_is_planar(h->streams[stream_index]->codec->sample_fmt) ?
+ AVERROR(EINVAL) : 0;
+
+ pkt.data = (*frame)->data[0];
+ pkt.size = (*frame)->nb_samples * av_get_bytes_per_sample((*frame)->format) * (*frame)->channels;
+ pkt.dts = (*frame)->pkt_dts;
+ pkt.duration = av_frame_get_pkt_duration(*frame);
+ return pulse_write_packet(h, &pkt);
+}
+
+
static void pulse_get_output_timestamp(AVFormatContext *h, int stream, int64_t *dts, int64_t *wall)
{
PulseData *s = h->priv_data;
@@ -149,6 +167,12 @@ static void pulse_get_output_timestamp(AVFormatContext *h, int stream, int64_t *
*dts = s->timestamp - latency;
}
+static int pulse_get_device_list(AVFormatContext *h, AVDeviceInfoList *device_list)
+{
+ PulseData *s = h->priv_data;
+ return ff_pulse_audio_get_devices(device_list, s->server, 1);
+}
+
#define OFFSET(a) offsetof(PulseData, a)
#define E AV_OPT_FLAG_ENCODING_PARAM
@@ -178,8 +202,10 @@ AVOutputFormat ff_pulse_muxer = {
.video_codec = AV_CODEC_ID_NONE,
.write_header = pulse_write_header,
.write_packet = pulse_write_packet,
+ .write_uncoded_frame = pulse_write_frame,
.write_trailer = pulse_write_trailer,
.get_output_timestamp = pulse_get_output_timestamp,
+ .get_device_list = pulse_get_device_list,
.flags = AVFMT_NOFILE | AVFMT_ALLOW_FLUSH,
.priv_class = &pulse_muxer_class,
};
diff --git a/libavutil/mem.c b/libavutil/mem.c
index e0d0d9040b..8226168eed 100644
--- a/libavutil/mem.c
+++ b/libavutil/mem.c
@@ -278,6 +278,19 @@ void *av_memdup(const void *p, size_t size)
return ptr;
}
+int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
+{
+ void **tab = *(void ***)tab_ptr;
+
+ AV_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
+ tab[*nb_ptr] = elem;
+ *(void ***)tab_ptr = tab;
+ }, {
+ return AVERROR(ENOMEM);
+ });
+ return 0;
+}
+
void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
{
void **tab = *(void ***)tab_ptr;
diff --git a/libavutil/mem.h b/libavutil/mem.h
index 703ce81936..801c53ff51 100644
--- a/libavutil/mem.h
+++ b/libavutil/mem.h
@@ -276,11 +276,26 @@ void av_freep(void *ptr);
* @param tab_ptr pointer to the array to grow
* @param nb_ptr pointer to the number of elements in the array
* @param elem element to add
- * @see av_dynarray2_add()
+ * @see av_dynarray_add_nofree(), av_dynarray2_add()
*/
void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem);
/**
+ * Add an element to a dynamic array.
+ *
+ * Function has the same functionality as av_dynarray_add(),
+ * but it doesn't free memory on fails. It returns error code
+ * instead and leave current buffer untouched.
+ *
+ * @param tab_ptr pointer to the array to grow
+ * @param nb_ptr pointer to the number of elements in the array
+ * @param elem element to add
+ * @return >=0 on success, negative otherwise.
+ * @see av_dynarray_add(), av_dynarray2_add()
+ */
+int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem);
+
+/**
* Add an element of size elem_size to a dynamic array.
*
* The array is reallocated when its number of elements reaches powers of 2.
@@ -299,7 +314,7 @@ void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem);
* the new added element is not filled.
* @return pointer to the data of the element to copy in the new allocated space.
* If NULL, the new allocated space is left uninitialized."
- * @see av_dynarray_add()
+ * @see av_dynarray_add(), av_dynarray_add_nofree()
*/
void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
const uint8_t *elem_data);
diff --git a/libavutil/version.h b/libavutil/version.h
index 45f5adc804..644f157242 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -56,7 +56,7 @@
*/
#define LIBAVUTIL_VERSION_MAJOR 52
-#define LIBAVUTIL_VERSION_MINOR 69
+#define LIBAVUTIL_VERSION_MINOR 70
#define LIBAVUTIL_VERSION_MICRO 100
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
diff --git a/tools/uncoded_frame.c b/tools/uncoded_frame.c
index eafbbfde17..53e71eacbf 100644
--- a/tools/uncoded_frame.c
+++ b/tools/uncoded_frame.c
@@ -177,12 +177,12 @@ int main(int argc, char **argv)
st->stream->codec->pix_fmt = st->link->format;
break;
case AVMEDIA_TYPE_AUDIO:
- st->stream->codec->codec_id =
- av_get_pcm_codec(st->stream->codec->sample_fmt, -1);
st->stream->codec->channel_layout = st->link->channel_layout;
st->stream->codec->channels = avfilter_link_get_channels(st->link);
st->stream->codec->sample_rate = st->link->sample_rate;
st->stream->codec->sample_fmt = st->link->format;
+ st->stream->codec->codec_id =
+ av_get_pcm_codec(st->stream->codec->sample_fmt, -1);
break;
default:
av_assert0(!"reached");