FFmpeg
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
Examples
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
libavdevice
pulse_audio_enc.c
Go to the documentation of this file.
1
/*
2
* Copyright (c) 2013 Lukasz Marek <lukasz.m.luki@gmail.com>
3
*
4
* This file is part of FFmpeg.
5
*
6
* FFmpeg is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
10
*
11
* FFmpeg is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with FFmpeg; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
*/
20
21
#include <pulse/simple.h>
22
#include <pulse/error.h>
23
#include "
libavformat/avformat.h
"
24
#include "
libavformat/internal.h
"
25
#include "
libavutil/opt.h
"
26
#include "
libavutil/time.h
"
27
#include "
libavutil/log.h
"
28
#include "
pulse_audio_common.h
"
29
30
typedef
struct
PulseData
{
31
AVClass
*
class
;
32
const
char
*
server
;
33
const
char
*
name
;
34
const
char
*
stream_name
;
35
const
char
*
device
;
36
pa_simple *
pa
;
37
int64_t
timestamp
;
38
}
PulseData
;
39
40
static
av_cold
int
pulse_write_header
(
AVFormatContext
*h)
41
{
42
PulseData
*
s
= h->
priv_data
;
43
AVStream
*st = NULL;
44
int
ret
;
45
pa_sample_spec ss;
46
pa_buffer_attr attr = { -1, -1, -1, -1, -1 };
47
const
char
*stream_name = s->
stream_name
;
48
49
if
(h->
nb_streams
!= 1 || h->
streams
[0]->
codec
->
codec_type
!=
AVMEDIA_TYPE_AUDIO
) {
50
av_log
(s,
AV_LOG_ERROR
,
"Only a single audio stream is supported.\n"
);
51
return
AVERROR
(EINVAL);
52
}
53
st = h->
streams
[0];
54
55
if
(!stream_name) {
56
if
(h->
filename
[0])
57
stream_name = h->
filename
;
58
else
59
stream_name =
"Playback"
;
60
}
61
62
ss.format =
codec_id_to_pulse_format
(st->
codec
->
codec_id
);
63
ss.rate = st->
codec
->
sample_rate
;
64
ss.channels = st->
codec
->
channels
;
65
66
s->
pa
= pa_simple_new(s->
server
,
// Server
67
s->
name
,
// Application name
68
PA_STREAM_PLAYBACK,
69
s->
device
,
// Device
70
stream_name,
// Description of a stream
71
&ss,
// Sample format
72
NULL,
// Use default channel map
73
&attr,
// Buffering attributes
74
&ret);
// Result
75
76
if
(!s->
pa
) {
77
av_log
(s,
AV_LOG_ERROR
,
"pa_simple_new failed: %s\n"
, pa_strerror(ret));
78
return
AVERROR
(EIO);
79
}
80
81
avpriv_set_pts_info
(st, 64, 1, 1000000);
/* 64 bits pts in us */
82
83
return
0;
84
}
85
86
static
av_cold
int
pulse_write_trailer
(
AVFormatContext
*h)
87
{
88
PulseData
*
s
= h->
priv_data
;
89
pa_simple_flush(s->
pa
, NULL);
90
pa_simple_free(s->
pa
);
91
s->
pa
= NULL;
92
return
0;
93
}
94
95
static
int
pulse_write_packet
(
AVFormatContext
*h,
AVPacket
*
pkt
)
96
{
97
PulseData
*
s
= h->
priv_data
;
98
int
error;
99
100
if
(!pkt) {
101
if
(pa_simple_flush(s->
pa
, &error) < 0) {
102
av_log
(s,
AV_LOG_ERROR
,
"pa_simple_flush failed: %s\n"
, pa_strerror(error));
103
return
AVERROR
(EIO);
104
}
105
return
0;
106
}
107
108
if
(pkt->
dts
!=
AV_NOPTS_VALUE
)
109
s->
timestamp
= pkt->
dts
;
110
111
if
(pkt->
duration
) {
112
s->
timestamp
+= pkt->
duration
;
113
}
else
{
114
AVStream
*st = h->
streams
[0];
115
AVCodecContext
*codec_ctx = st->
codec
;
116
AVRational
r
= { 1, codec_ctx->
sample_rate
};
117
int64_t samples = pkt->
size
/ (
av_get_bytes_per_sample
(codec_ctx->
sample_fmt
) * codec_ctx->
channels
);
118
s->
timestamp
+=
av_rescale_q
(samples, r, st->
time_base
);
119
}
120
121
if
(pa_simple_write(s->
pa
, pkt->
data
, pkt->
size
, &error) < 0) {
122
av_log
(s,
AV_LOG_ERROR
,
"pa_simple_write failed: %s\n"
, pa_strerror(error));
123
return
AVERROR
(EIO);
124
}
125
126
return
0;
127
}
128
129
static
void
pulse_get_output_timestamp
(
AVFormatContext
*h,
int
stream, int64_t *dts, int64_t *wall)
130
{
131
PulseData
*
s
= h->
priv_data
;
132
pa_usec_t latency = pa_simple_get_latency(s->
pa
, NULL);
133
*wall =
av_gettime
();
134
*dts = s->
timestamp
- latency;
135
}
136
137
#define OFFSET(a) offsetof(PulseData, a)
138
#define E AV_OPT_FLAG_ENCODING_PARAM
139
140
static
const
AVOption
options
[] = {
141
{
"server"
,
"set PulseAudio server"
,
OFFSET
(server),
AV_OPT_TYPE_STRING
, {.str = NULL}, 0, 0,
E
},
142
{
"name"
,
"set application name"
,
OFFSET
(
name
),
AV_OPT_TYPE_STRING
, {.str =
LIBAVFORMAT_IDENT
}, 0, 0,
E
},
143
{
"stream_name"
,
"set stream description"
,
OFFSET
(stream_name),
AV_OPT_TYPE_STRING
, {.str = NULL}, 0, 0,
E
},
144
{
"device"
,
"set device name"
,
OFFSET
(device),
AV_OPT_TYPE_STRING
, {.str = NULL}, 0, 0,
E
},
145
{ NULL }
146
};
147
148
static
const
AVClass
pulse_muxer_class
= {
149
.
class_name
=
"Pulse muxer"
,
150
.item_name =
av_default_item_name
,
151
.option =
options
,
152
.version =
LIBAVUTIL_VERSION_INT
,
153
};
154
155
AVOutputFormat
ff_pulse_muxer
= {
156
.
name
=
"pulse"
,
157
.long_name =
NULL_IF_CONFIG_SMALL
(
"Pulse audio output"
),
158
.priv_data_size =
sizeof
(
PulseData
),
159
.audio_codec =
AV_NE
(
AV_CODEC_ID_PCM_S16BE
,
AV_CODEC_ID_PCM_S16LE
),
160
.video_codec =
AV_CODEC_ID_NONE
,
161
.write_header =
pulse_write_header
,
162
.write_packet =
pulse_write_packet
,
163
.write_trailer =
pulse_write_trailer
,
164
.get_output_timestamp =
pulse_get_output_timestamp
,
165
.flags =
AVFMT_NOFILE
|
AVFMT_ALLOW_FLUSH
,
166
.priv_class = &
pulse_muxer_class
,
167
};
Generated on Sat Jan 25 2014 19:51:58 for FFmpeg by
1.8.2