Make new USE_BUFFERS command

Make a new USE_BUFFERS command to atomically send a buffer array to the
remote client. We can use this to then clean up an old array and go to
the PAUSED state if possible.
Work on formats. Make one structure that can hold all video formats.
Work on pipeline suspend and resume.
Add jpeg support to v4l2.
Work on enum_formats with a filter in v4l2.
This commit is contained in:
Wim Taymans 2016-08-26 17:43:48 +02:00
parent 7e858ff694
commit b67c216a04
24 changed files with 688 additions and 514 deletions

View file

@ -123,42 +123,42 @@ enum {
static const SpaPropInfo prop_info[] =
{
{ PROP_ID_DEVICE, "device", "ALSA device, as defined in an asound configuration file",
{ PROP_ID_DEVICE, offsetof (SpaALSASinkProps, device),
"device", "ALSA device, as defined in an asound configuration file",
SPA_PROP_FLAG_READWRITE,
SPA_PROP_TYPE_STRING, 63,
SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
NULL,
offsetof (SpaALSASinkProps, device) },
{ PROP_ID_DEVICE_NAME, "device-name", "Human-readable name of the sound device",
NULL },
{ PROP_ID_DEVICE_NAME, offsetof (SpaALSASinkProps, device_name),
"device-name", "Human-readable name of the sound device",
SPA_PROP_FLAG_READABLE,
SPA_PROP_TYPE_STRING, 127,
SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
NULL,
offsetof (SpaALSASinkProps, device_name) },
{ PROP_ID_CARD_NAME, "card-name", "Human-readable name of the sound card",
NULL },
{ PROP_ID_CARD_NAME, offsetof (SpaALSASinkProps, card_name),
"card-name", "Human-readable name of the sound card",
SPA_PROP_FLAG_READABLE,
SPA_PROP_TYPE_STRING, 127,
SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
NULL,
offsetof (SpaALSASinkProps, card_name) },
{ PROP_ID_BUFFER_TIME, "buffer-time", "The total size of the buffer in time",
NULL },
{ PROP_ID_BUFFER_TIME, offsetof (SpaALSASinkProps, buffer_time),
"buffer-time", "The total size of the buffer in time",
SPA_PROP_FLAG_READWRITE,
SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
SPA_PROP_RANGE_TYPE_MIN_MAX, 2, uint32_range,
NULL,
offsetof (SpaALSASinkProps, buffer_time) },
{ PROP_ID_PERIOD_TIME, "period-time", "The size of a period in time",
NULL },
{ PROP_ID_PERIOD_TIME, offsetof (SpaALSASinkProps, period_time),
"period-time", "The size of a period in time",
SPA_PROP_FLAG_READWRITE,
SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
SPA_PROP_RANGE_TYPE_MIN_MAX, 2, uint32_range,
NULL,
offsetof (SpaALSASinkProps, period_time) },
{ PROP_ID_PERIOD_EVENT, "period-event", "Generate an event each period",
NULL },
{ PROP_ID_PERIOD_EVENT, offsetof (SpaALSASinkProps, period_event),
"period-event", "Generate an event each period",
SPA_PROP_FLAG_READWRITE,
SPA_PROP_TYPE_BOOL, sizeof (bool),
SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
NULL,
offsetof (SpaALSASinkProps, period_event) },
NULL },
};
static SpaResult

View file

@ -84,24 +84,24 @@ enum {
static const SpaPropInfo prop_info[] =
{
{ PROP_ID_WAVE, "wave", "Oscillator waveform",
{ PROP_ID_WAVE, offsetof (SpaAudioTestSrcProps, wave),
"wave", "Oscillator waveform",
SPA_PROP_FLAG_READWRITE,
SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (wave_range), wave_range,
NULL,
offsetof (SpaAudioTestSrcProps, wave) },
{ PROP_ID_FREQ, "freq", "Frequency of test signal. The sample rate needs to be at least 4 times higher",
NULL },
{ PROP_ID_FREQ, offsetof (SpaAudioTestSrcProps, freq),
"freq", "Frequency of test signal. The sample rate needs to be at least 4 times higher",
SPA_PROP_FLAG_READWRITE,
SPA_PROP_TYPE_DOUBLE, sizeof (double),
SPA_PROP_RANGE_TYPE_MIN_MAX, 2, freq_range,
NULL,
offsetof (SpaAudioTestSrcProps, freq) },
{ PROP_ID_VOLUME, "volume", "The Volume factor",
NULL },
{ PROP_ID_VOLUME, offsetof (SpaAudioTestSrcProps, volume),
"volume", "The Volume factor",
SPA_PROP_FLAG_READWRITE,
SPA_PROP_TYPE_DOUBLE, sizeof (double),
SPA_PROP_RANGE_TYPE_MIN_MAX, 2, volume_range,
NULL,
offsetof (SpaAudioTestSrcProps, volume) },
NULL },
};
static void
@ -465,7 +465,7 @@ spa_audiotestsrc_node_port_pull_output (SpaNode *node,
{
SpaAudioTestSrc *this;
size_t j, size;
uint8_t *ptr;
uint8_t *ptr = NULL;
unsigned int i;
bool have_error = false;

View file

@ -55,7 +55,7 @@ struct _FFMpegBuffer {
};
typedef struct {
SpaVideoRawFormat raw_format[2];
SpaFormatVideo format[2];
SpaFormat *current_format;
bool have_buffers;
FFMpegBuffer buffers[MAX_BUFFERS];
@ -278,12 +278,14 @@ spa_ffmpeg_dec_node_port_enum_formats (SpaNode *node,
switch (index) {
case 0:
spa_video_raw_format_init (&s->raw_format[0]);
spa_format_video_init (SPA_MEDIA_TYPE_VIDEO,
SPA_MEDIA_SUBTYPE_RAW,
&s->format[0]);
break;
default:
return SPA_RESULT_ENUM_END;
}
*format = &s->raw_format[0].format;
*format = &s->format[0].format;
*(int*)state = ++index;
return SPA_RESULT_OK;
@ -298,8 +300,6 @@ spa_ffmpeg_dec_node_port_set_format (SpaNode *node,
SpaFFMpegDec *this;
SpaFFMpegState *state;
SpaResult res;
SpaFormat *f, *tf;
size_t fs;
if (node == NULL || node->handle == NULL || format == NULL)
return SPA_RESULT_INVALID_ARGUMENTS;
@ -316,22 +316,12 @@ spa_ffmpeg_dec_node_port_set_format (SpaNode *node,
return SPA_RESULT_OK;
}
if (format->media_type == SPA_MEDIA_TYPE_VIDEO) {
if (format->media_subtype == SPA_MEDIA_SUBTYPE_RAW) {
if ((res = spa_video_raw_format_parse (format, &state->raw_format[0]) < 0))
return res;
f = &state->raw_format[0].format;
tf = &state->raw_format[1].format;
fs = sizeof (SpaVideoRawFormat);
} else
return SPA_RESULT_INVALID_MEDIA_TYPE;
} else
return SPA_RESULT_INVALID_MEDIA_TYPE;
if ((res = spa_format_video_parse (format, &state->format[0]) < 0))
return res;
if (!(flags & SPA_PORT_FORMAT_FLAG_TEST_ONLY)) {
memcpy (tf, f, fs);
state->current_format = tf;
memcpy (&state->format[1], &state->format[0], sizeof (SpaFormatVideo));
state->current_format = &state->format[1].format;
}
return SPA_RESULT_OK;

View file

@ -55,7 +55,7 @@ struct _FFMpegBuffer {
};
typedef struct {
SpaVideoRawFormat raw_format[2];
SpaFormatVideo format[2];
SpaFormat *current_format;
bool have_buffers;
FFMpegBuffer buffers[MAX_BUFFERS];
@ -278,12 +278,14 @@ spa_ffmpeg_enc_node_port_enum_formats (SpaNode *node,
switch (index) {
case 0:
spa_video_raw_format_init (&s->raw_format[0]);
spa_format_video_init (SPA_MEDIA_TYPE_VIDEO,
SPA_MEDIA_SUBTYPE_RAW,
&s->format[0]);
break;
default:
return SPA_RESULT_ENUM_END;
}
*format = &s->raw_format[0].format;
*format = &s->format[0].format;
*(int*)state = ++index;
return SPA_RESULT_OK;
@ -298,8 +300,6 @@ spa_ffmpeg_enc_node_port_set_format (SpaNode *node,
SpaFFMpegEnc *this;
SpaFFMpegState *state;
SpaResult res;
SpaFormat *f, *tf;
size_t fs;
if (node == NULL || node->handle == NULL || format == NULL)
return SPA_RESULT_INVALID_ARGUMENTS;
@ -315,23 +315,16 @@ spa_ffmpeg_enc_node_port_set_format (SpaNode *node,
state->current_format = NULL;
return SPA_RESULT_OK;
}
if ((res = spa_format_video_parse (format, &state->format[0]) < 0))
return res;
if (format->media_type == SPA_MEDIA_TYPE_VIDEO) {
if (format->media_subtype == SPA_MEDIA_SUBTYPE_RAW) {
if ((res = spa_video_raw_format_parse (format, &state->raw_format[0]) < 0))
return res;
f = &state->raw_format[0].format;
tf = &state->raw_format[1].format;
fs = sizeof (SpaVideoRawFormat);
} else
return SPA_RESULT_INVALID_MEDIA_TYPE;
} else
if (format->media_type != SPA_MEDIA_TYPE_VIDEO ||
format->media_subtype != SPA_MEDIA_SUBTYPE_RAW)
return SPA_RESULT_INVALID_MEDIA_TYPE;
if (!(flags & SPA_PORT_FORMAT_FLAG_TEST_ONLY)) {
memcpy (tf, f, fs);
state->current_format = tf;
memcpy (&state->format[1], &state->format[0], sizeof (SpaFormatVideo));
state->current_format = &state->format[1].format;
}
return SPA_RESULT_OK;

View file

@ -88,12 +88,12 @@ enum {
static const SpaPropInfo prop_info[PROP_ID_LAST] =
{
{ PROP_ID_SOCKET, "socket", "The Socket factor",
{ PROP_ID_SOCKET, offsetof (SpaProxyProps, socketfd),
"socket", "The Socket factor",
SPA_PROP_FLAG_READWRITE,
SPA_PROP_TYPE_INT, sizeof (int),
SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
NULL,
offsetof (SpaProxyProps, socketfd) },
NULL },
};
static void
@ -626,10 +626,9 @@ spa_proxy_node_port_get_status (SpaNode *node,
}
static SpaResult
add_buffer (SpaProxy *this, SpaControlBuilder *builder, uint32_t port_id, SpaBuffer *buffer)
add_buffer_mem (SpaProxy *this, SpaControlBuilder *builder, uint32_t port_id, SpaBuffer *buffer)
{
SpaControlCmdAddMem am;
SpaControlCmdAddBuffer ab;
int i;
SpaBuffer *b;
SpaMemory *bmem;
@ -661,6 +660,10 @@ add_buffer (SpaProxy *this, SpaControlBuilder *builder, uint32_t port_id, SpaBuf
fprintf (stderr, "proxy %p: error invalid memory\n", this);
continue;
}
if (mem->fd == -1) {
fprintf (stderr, "proxy %p: error memory without fd\n", this);
continue;
}
am.port_id = port_id;
am.mem = mem->mem;
@ -670,42 +673,10 @@ add_buffer (SpaProxy *this, SpaControlBuilder *builder, uint32_t port_id, SpaBuf
am.size = mem->size;
spa_control_builder_add_cmd (builder, SPA_CONTROL_CMD_ADD_MEM, &am);
}
ab.port_id = port_id;
ab.buffer_id = b->id;
ab.mem.mem = bmem->mem;
ab.mem.offset = b->mem.offset;
ab.mem.size = b->mem.size;
spa_control_builder_add_cmd (builder, SPA_CONTROL_CMD_ADD_BUFFER, &ab);
return SPA_RESULT_OK;
}
static SpaResult
remove_buffer (SpaProxy *this, SpaControlBuilder *builder, uint32_t port_id, SpaBuffer *buffer)
{
SpaControlCmdRemoveBuffer rb;
SpaControlCmdRemoveMem rm;
unsigned int i;
rb.port_id = port_id;
rb.buffer_id = buffer->id;
spa_control_builder_add_cmd (builder, SPA_CONTROL_CMD_REMOVE_BUFFER, &rb);
rm.port_id = port_id;
rm.mem = buffer->mem.mem;
spa_control_builder_add_cmd (builder, SPA_CONTROL_CMD_REMOVE_MEM, &rm);
for (i = 0; i < buffer->n_datas; i++) {
SpaData *d = &SPA_BUFFER_DATAS (buffer)[i];
rm.port_id = port_id;
rm.mem = d->mem.mem;
spa_control_builder_add_cmd (builder, SPA_CONTROL_CMD_REMOVE_MEM, &rm);
}
return SPA_RESULT_OK;
}
static SpaResult
spa_proxy_node_port_use_buffers (SpaNode *node,
uint32_t port_id,
@ -720,6 +691,7 @@ spa_proxy_node_port_use_buffers (SpaNode *node,
uint8_t buf[4096];
int fds[32];
SpaResult res;
SpaControlCmdUseBuffers ub;
if (node == NULL || node->handle == NULL)
return SPA_RESULT_INVALID_ARGUMENTS;
@ -737,9 +709,6 @@ spa_proxy_node_port_use_buffers (SpaNode *node,
spa_control_builder_init_into (&builder, buf, sizeof (buf), fds, sizeof (fds));
for (i = 0; i < port->n_buffers; i++)
remove_buffer (this, &builder, port_id, port->buffers[i]);
if (buffers == NULL || n_buffers == 0) {
port->buffers = NULL;
port->n_buffers = 0;
@ -748,7 +717,12 @@ spa_proxy_node_port_use_buffers (SpaNode *node,
port->n_buffers = n_buffers;
}
for (i = 0; i < port->n_buffers; i++)
add_buffer (this, &builder, port_id, port->buffers[i]);
add_buffer_mem (this, &builder, port_id, port->buffers[i]);
ub.port_id = port_id;
ub.n_buffers = port->n_buffers;
ub.buffers = port->buffers;
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_USE_BUFFERS, &ub);
spa_control_builder_end (&builder, &control);
@ -1044,9 +1018,7 @@ parse_control (SpaProxy *this,
break;
case SPA_CONTROL_CMD_REMOVE_MEM:
break;
case SPA_CONTROL_CMD_ADD_BUFFER:
break;
case SPA_CONTROL_CMD_REMOVE_BUFFER:
case SPA_CONTROL_CMD_USE_BUFFERS:
break;
case SPA_CONTROL_CMD_PROCESS_BUFFER:

View file

@ -140,24 +140,24 @@ enum {
static const SpaPropInfo prop_info[] =
{
{ PROP_ID_DEVICE, "device", "V4l2 device location",
{ PROP_ID_DEVICE, offsetof (SpaV4l2SourceProps, device),
"device", "V4l2 device location",
SPA_PROP_FLAG_READWRITE,
SPA_PROP_TYPE_STRING, 63,
SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
NULL,
offsetof (SpaV4l2SourceProps, device) },
{ PROP_ID_DEVICE_NAME, "device-name", "Human-readable name of the device",
NULL },
{ PROP_ID_DEVICE_NAME, offsetof (SpaV4l2SourceProps, device_name),
"device-name", "Human-readable name of the device",
SPA_PROP_FLAG_READABLE,
SPA_PROP_TYPE_STRING, 127,
SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
NULL,
offsetof (SpaV4l2SourceProps, device_name) },
{ PROP_ID_DEVICE_FD, "device-fd", "Device file descriptor",
NULL },
{ PROP_ID_DEVICE_FD, offsetof (SpaV4l2SourceProps, device_fd),
"device-fd", "Device file descriptor",
SPA_PROP_FLAG_READABLE,
SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
NULL,
offsetof (SpaV4l2SourceProps, device_fd) },
NULL },
};
static SpaResult
@ -357,15 +357,15 @@ spa_v4l2_format_init (V4l2Format *f)
f->fmt.props.n_prop_info = 3;
f->fmt.props.prop_info = f->infos;
spa_video_raw_fill_prop_info (&f->infos[0],
SPA_PROP_ID_VIDEO_FORMAT,
offsetof (V4l2Format, format));
spa_video_raw_fill_prop_info (&f->infos[1],
SPA_PROP_ID_VIDEO_SIZE,
offsetof (V4l2Format, size));
spa_video_raw_fill_prop_info (&f->infos[2],
SPA_PROP_ID_VIDEO_FRAMERATE,
offsetof (V4l2Format, framerate));
spa_prop_info_fill_video (&f->infos[0],
SPA_PROP_ID_VIDEO_FORMAT,
offsetof (V4l2Format, format));
spa_prop_info_fill_video (&f->infos[1],
SPA_PROP_ID_VIDEO_SIZE,
offsetof (V4l2Format, size));
spa_prop_info_fill_video (&f->infos[2],
SPA_PROP_ID_VIDEO_FRAMERATE,
offsetof (V4l2Format, framerate));
}
static SpaResult
@ -386,7 +386,7 @@ spa_v4l2_source_node_port_enum_formats (SpaNode *node,
if (port_id != 0)
return SPA_RESULT_INVALID_PORT;
res = spa_v4l2_enum_format (this, format, state);
res = spa_v4l2_enum_format (this, format, filter, state);
return res;
}
@ -403,7 +403,7 @@ spa_v4l2_source_node_port_set_format (SpaNode *node,
V4l2Format *f, *tf;
size_t fs;
if (node == NULL || node->handle == NULL || format == NULL)
if (node == NULL || node->handle == NULL)
return SPA_RESULT_INVALID_ARGUMENTS;
this = (SpaV4l2Source *) node->handle;
@ -417,6 +417,7 @@ spa_v4l2_source_node_port_set_format (SpaNode *node,
spa_v4l2_clear_buffers (this);
spa_v4l2_close (this);
state->current_format = NULL;
update_state (this, SPA_NODE_STATE_CONFIGURE);
return SPA_RESULT_OK;
}

View file

@ -230,28 +230,28 @@ static const FormatInfo format_info[] =
{ V4L2_PIX_FMT_SRGGB8, SPA_VIDEO_FORMAT_UNKNOWN, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_BAYER },
/* compressed formats */
{V4L2_PIX_FMT_MJPEG, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_MJPG },
{V4L2_PIX_FMT_JPEG, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_IMAGE, SPA_MEDIA_SUBTYPE_JPEG },
{V4L2_PIX_FMT_PJPG, SPA_VIDEO_FORMAT_UNKNOWN, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_RAW },
{V4L2_PIX_FMT_DV, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_DV },
{V4L2_PIX_FMT_MPEG, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_MPEGTS },
{V4L2_PIX_FMT_H264, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_H264 },
{V4L2_PIX_FMT_H264_NO_SC, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_H264 },
{V4L2_PIX_FMT_H264_MVC, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_H264 },
{V4L2_PIX_FMT_H263, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_H263 },
{V4L2_PIX_FMT_MPEG1, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_MPEG1 },
{V4L2_PIX_FMT_MPEG2, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_MPEG2 },
{V4L2_PIX_FMT_MPEG4, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_MPEG4 },
{V4L2_PIX_FMT_XVID, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_XVID },
{V4L2_PIX_FMT_VC1_ANNEX_G, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_VC1 },
{V4L2_PIX_FMT_VC1_ANNEX_L, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_VC1 },
{V4L2_PIX_FMT_VP8, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_VP8 },
{ V4L2_PIX_FMT_MJPEG, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_MJPG },
{ V4L2_PIX_FMT_JPEG, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_IMAGE, SPA_MEDIA_SUBTYPE_JPEG },
{ V4L2_PIX_FMT_PJPG, SPA_VIDEO_FORMAT_UNKNOWN, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_RAW },
{ V4L2_PIX_FMT_DV, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_DV },
{ V4L2_PIX_FMT_MPEG, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_MPEGTS },
{ V4L2_PIX_FMT_H264, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_H264 },
{ V4L2_PIX_FMT_H264_NO_SC, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_H264 },
{ V4L2_PIX_FMT_H264_MVC, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_H264 },
{ V4L2_PIX_FMT_H263, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_H263 },
{ V4L2_PIX_FMT_MPEG1, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_MPEG1 },
{ V4L2_PIX_FMT_MPEG2, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_MPEG2 },
{ V4L2_PIX_FMT_MPEG4, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_MPEG4 },
{ V4L2_PIX_FMT_XVID, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_XVID },
{ V4L2_PIX_FMT_VC1_ANNEX_G, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_VC1 },
{ V4L2_PIX_FMT_VC1_ANNEX_L, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_VC1 },
{ V4L2_PIX_FMT_VP8, SPA_VIDEO_FORMAT_ENCODED, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_VP8 },
/* Vendor-specific formats */
{V4L2_PIX_FMT_WNVA, SPA_VIDEO_FORMAT_UNKNOWN, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_RAW },
{V4L2_PIX_FMT_SN9C10X, SPA_VIDEO_FORMAT_UNKNOWN, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_RAW },
{V4L2_PIX_FMT_PWC1, SPA_VIDEO_FORMAT_UNKNOWN, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_RAW },
{V4L2_PIX_FMT_PWC2, SPA_VIDEO_FORMAT_UNKNOWN, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_RAW },
{ V4L2_PIX_FMT_WNVA, SPA_VIDEO_FORMAT_UNKNOWN, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_RAW },
{ V4L2_PIX_FMT_SN9C10X, SPA_VIDEO_FORMAT_UNKNOWN, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_RAW },
{ V4L2_PIX_FMT_PWC1, SPA_VIDEO_FORMAT_UNKNOWN, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_RAW },
{ V4L2_PIX_FMT_PWC2, SPA_VIDEO_FORMAT_UNKNOWN, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_RAW },
};
static const FormatInfo *
@ -280,15 +280,33 @@ video_format_to_format_info (SpaVideoFormat format)
}
#endif
static const FormatInfo *
find_format_info_by_media_type (SpaMediaType type,
SpaMediaSubType subtype,
SpaVideoFormat format,
int startidx)
{
int i;
for (i = startidx; i < SPA_N_ELEMENTS (format_info); i++) {
if ((format_info[i].media_type == type) &&
(format_info[i].media_subtype == subtype) &&
(format == SPA_VIDEO_FORMAT_UNKNOWN || format_info[i].format == format))
return &format_info[i];
}
return NULL;
}
#define FOURCC_ARGS(f) (f)&0x7f,((f)>>8)&0x7f,((f)>>16)&0x7f,((f)>>24)&0x7f
static SpaResult
spa_v4l2_enum_format (SpaV4l2Source *this, SpaFormat **format, void **cookie)
spa_v4l2_enum_format (SpaV4l2Source *this, SpaFormat **format, const SpaFormat *filter, void **cookie)
{
SpaV4l2State *state = &this->state[0];
int res, i, pi;
V4l2Format *fmt;
const FormatInfo *info;
SpaVideoFormat video_format;
if (spa_v4l2_open (this) < 0)
return SPA_RESULT_ERROR;
@ -306,15 +324,47 @@ spa_v4l2_enum_format (SpaV4l2Source *this, SpaFormat **format, void **cookie)
*cookie = state;
}
again:
if (state->next_fmtdesc) {
if ((res = xioctl (state->fd, VIDIOC_ENUM_FMT, &state->fmtdesc)) < 0) {
if (errno != EINVAL)
perror ("VIDIOC_ENUM_FMT");
return SPA_RESULT_ENUM_END;
if (filter) {
SpaPropValue val;
if (state->fmtdesc.index == 1)
return SPA_RESULT_ENUM_END;
video_format = SPA_VIDEO_FORMAT_UNKNOWN;
if ((filter->media_type == SPA_MEDIA_TYPE_VIDEO)) {
if (filter->media_subtype == SPA_MEDIA_SUBTYPE_RAW) {
if (spa_props_get_prop (&filter->props,
spa_props_index_for_id (&filter->props, SPA_PROP_ID_VIDEO_FORMAT),
&val) >= 0) {
video_format = *((SpaVideoFormat *)val.value);
}
} else {
video_format = SPA_VIDEO_FORMAT_ENCODED;
}
} else if ((filter->media_type == SPA_MEDIA_TYPE_IMAGE)) {
video_format = SPA_VIDEO_FORMAT_ENCODED;
} else
return SPA_RESULT_ENUM_END;
info = find_format_info_by_media_type (filter->media_type,
filter->media_subtype,
video_format,
0);
if (info == NULL)
return SPA_RESULT_ENUM_END;
state->fmtdesc.pixelformat = info->fourcc;
} else {
if ((res = xioctl (state->fd, VIDIOC_ENUM_FMT, &state->fmtdesc)) < 0) {
if (errno != EINVAL)
perror ("VIDIOC_ENUM_FMT");
return SPA_RESULT_ENUM_END;
}
}
state->next_fmtdesc = false;
state->frmsize.index = 0;
state->frmsize.pixel_format = state->fmtdesc.pixelformat;
state->next_frmsize = true;
@ -354,23 +404,23 @@ again:
fmt->fmt.props.unset_mask = 0;
if (info->media_subtype == SPA_MEDIA_SUBTYPE_RAW) {
spa_video_raw_fill_prop_info (&fmt->infos[pi],
SPA_PROP_ID_VIDEO_FORMAT,
offsetof (V4l2Format, format));
spa_prop_info_fill_video (&fmt->infos[pi],
SPA_PROP_ID_VIDEO_FORMAT,
offsetof (V4l2Format, format));
fmt->format = info->format;
pi = ++fmt->fmt.props.n_prop_info;
}
spa_video_raw_fill_prop_info (&fmt->infos[pi],
SPA_PROP_ID_VIDEO_SIZE,
offsetof (V4l2Format, size));
spa_prop_info_fill_video (&fmt->infos[pi],
SPA_PROP_ID_VIDEO_SIZE,
offsetof (V4l2Format, size));
fmt->size.width = state->frmsize.discrete.width;
fmt->size.height = state->frmsize.discrete.height;
pi = ++fmt->fmt.props.n_prop_info;
spa_video_raw_fill_prop_info (&fmt->infos[pi],
SPA_PROP_ID_VIDEO_FRAMERATE,
offsetof (V4l2Format, framerate));
spa_prop_info_fill_video (&fmt->infos[pi],
SPA_PROP_ID_VIDEO_FRAMERATE,
offsetof (V4l2Format, framerate));
fmt->infos[pi].range_type = SPA_PROP_RANGE_TYPE_ENUM;
fmt->infos[pi].range_values = fmt->ranges;
fmt->infos[pi].n_range_values = 0;
@ -417,21 +467,16 @@ spa_v4l2_set_format (SpaV4l2Source *this, V4l2Format *f, bool try_only)
struct v4l2_format reqfmt, fmt;
struct v4l2_streamparm streamparm;
const FormatInfo *info = NULL;
int i;
CLEAR (fmt);
CLEAR (streamparm);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
for (i = 0; i < SPA_N_ELEMENTS (format_info); i++) {
if (format_info[i].media_type == f->fmt.media_type &&
format_info[i].media_subtype == f->fmt.media_subtype &&
format_info[i].format == f->format) {
info = &format_info[i];
break;
}
}
info = find_format_info_by_media_type (f->fmt.media_type,
f->fmt.media_subtype,
f->format,
0);
if (info == NULL)
return -1;

View file

@ -75,18 +75,18 @@ enum {
static const SpaPropInfo prop_info[] =
{
{ PROP_ID_VOLUME, "volume", "The Volume factor",
{ PROP_ID_VOLUME, offsetof (SpaVolumeProps, volume),
"volume", "The Volume factor",
SPA_PROP_FLAG_READWRITE,
SPA_PROP_TYPE_DOUBLE, sizeof (double),
SPA_PROP_RANGE_TYPE_MIN_MAX, 2, volume_range,
NULL,
offsetof (SpaVolumeProps, volume) },
{ PROP_ID_MUTE, "mute", "Mute",
NULL },
{ PROP_ID_MUTE, offsetof (SpaVolumeProps, mute),
"mute", "Mute",
SPA_PROP_FLAG_READWRITE,
SPA_PROP_TYPE_BOOL, sizeof (bool),
SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
NULL,
offsetof (SpaVolumeProps, mute) },
NULL },
};
static void

View file

@ -76,7 +76,7 @@ struct _SpaXvSink {
SpaEventCallback event_cb;
void *user_data;
SpaVideoRawFormat raw_format[2];
SpaFormatVideo format[2];
SpaFormat *current_format;
SpaXvState state;
@ -97,24 +97,24 @@ enum {
static const SpaPropInfo prop_info[] =
{
{ PROP_ID_DEVICE, "device", "Xv device location",
{ PROP_ID_DEVICE, offsetof (SpaXvSinkProps, device),
"device", "Xv device location",
SPA_PROP_FLAG_READWRITE,
SPA_PROP_TYPE_STRING, 63,
SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
NULL,
offsetof (SpaXvSinkProps, device) },
{ PROP_ID_DEVICE_NAME, "device-name", "Human-readable name of the device",
NULL },
{ PROP_ID_DEVICE_NAME, offsetof (SpaXvSinkProps, device_name),
"device-name", "Human-readable name of the device",
SPA_PROP_FLAG_READABLE,
SPA_PROP_TYPE_STRING, 127,
SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
NULL,
offsetof (SpaXvSinkProps, device_name) },
{ PROP_ID_DEVICE_FD, "device-fd", "Device file descriptor",
NULL },
{ PROP_ID_DEVICE_FD, offsetof (SpaXvSinkProps, device_fd),
"device-fd", "Device file descriptor",
SPA_PROP_FLAG_READABLE,
SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
NULL,
offsetof (SpaXvSinkProps, device_fd) },
NULL },
};
static SpaResult
@ -308,12 +308,14 @@ spa_xv_sink_node_port_enum_formats (SpaNode *node,
switch (index) {
case 0:
spa_video_raw_format_init (&this->raw_format[0]);
spa_format_video_init (SPA_MEDIA_TYPE_VIDEO,
SPA_MEDIA_SUBTYPE_RAW,
&this->format[0]);
break;
default:
return SPA_RESULT_ENUM_END;
}
*format = &this->raw_format[0].format;
*format = &this->format[0].format;
*(int*)state = ++index;
return SPA_RESULT_OK;
@ -345,12 +347,12 @@ spa_xv_sink_node_port_set_format (SpaNode *node,
if (format->media_type == SPA_MEDIA_TYPE_VIDEO) {
if (format->media_subtype == SPA_MEDIA_SUBTYPE_RAW) {
if ((res = spa_video_raw_format_parse (format, &this->raw_format[0]) < 0))
if ((res = spa_format_video_parse (format, &this->format[0]) < 0))
return res;
f = &this->raw_format[0].format;
tf = &this->raw_format[1].format;
fs = sizeof (SpaVideoRawFormat);
f = &this->format[0].format;
tf = &this->format[1].format;
fs = sizeof (SpaVideoFormat);
} else
return SPA_RESULT_INVALID_MEDIA_TYPE;
} else