1 #include "output-drv.hpp"
9 class audio_dyncall_null
: public audio_dyncall_base
11 void operator()(short left
, short right
)
16 class audio_end_dyncall_null
: public audio_end_dyncall_base
23 class video_dyncall_null
: public video_dyncall_base
25 void operator()(uint64_t timestamp
, const uint8_t* raw_rgbx_data
)
30 class subtitle_dyncall_null
: public subtitle_dyncall_base
32 void operator()(uint64_t basetime
, uint64_t duration
, const uint8_t* text
)
37 audio_settings::audio_settings(uint32_t _rate
)
42 uint32_t audio_settings::get_rate() const
47 audio_dyncall_base::~audio_dyncall_base()
51 audio_end_dyncall_base::~audio_end_dyncall_base()
55 video_settings::video_settings(uint32_t _width
, uint32_t _height
, uint32_t _rate_num
, uint32_t _rate_denum
)
60 rate_denum
= _rate_denum
;
63 uint32_t video_settings::get_width() const
68 uint32_t video_settings::get_height() const
73 uint32_t video_settings::get_rate_num() const
78 uint32_t video_settings::get_rate_denum() const
83 video_dyncall_base::~video_dyncall_base()
87 subtitle_settings::subtitle_settings()
91 subtitle_dyncall_base::~subtitle_dyncall_base()
95 const audio_settings
& output_driver::get_audio_settings()
100 const video_settings
& output_driver::get_video_settings()
105 const subtitle_settings
& output_driver::get_subtitle_settings()
110 output_driver::output_driver()
111 : asettings(0), vsettings(0, 0, 0, 0), ssettings()
113 audio_handler
= new audio_dyncall_null();
114 audio_end_handler
= new audio_end_dyncall_null();
115 video_handler
= new video_dyncall_null();
116 subtitle_handler
= new subtitle_dyncall_null();
119 output_driver::~output_driver()
121 delete audio_handler
;
122 delete audio_end_handler
;
123 delete video_handler
;
124 delete subtitle_handler
;
127 void output_driver::do_audio_callback(short left
, short right
)
129 (*audio_handler
)(left
, right
);
132 void output_driver::do_audio_end_callback()
134 (*audio_end_handler
)();
137 void output_driver::do_video_callback(uint64_t timestamp
, const uint8_t* raw_rgbx_data
)
139 (*video_handler
)(timestamp
, raw_rgbx_data
);
142 void output_driver::do_subtitle_callback(uint64_t basetime
, uint64_t duration
, const uint8_t* text
)
144 (*subtitle_handler
)(basetime
, duration
, text
);
147 void output_driver::set_audio_settings(audio_settings a
)
152 void output_driver::set_video_settings(video_settings v
)
157 void output_driver::set_subtitle_settings(subtitle_settings s
)
162 std::map
<std::string
, output_driver_factory
*>* output_driver_factory::factories
;
164 output_driver_factory::~output_driver_factory()
168 output_driver_factory::output_driver_factory(const std::string
& type
)
171 factories
= new std::map
<std::string
, output_driver_factory
*>();
172 (*factories
)[type
] = this;
175 output_driver
& output_driver_factory::make_by_type(const std::string
& type
, const std::string
& name
,
176 const std::string
& parameters
)
178 if(!factories
|| !factories
->count(type
))
179 throw std::runtime_error("Unknown output driver type");
180 return (*factories
)[type
]->make(type
, name
, parameters
);
185 std::list
<output_driver
*> drivers
;
186 audio_settings
asettings(0);
187 video_settings
vsettings(0, 0, 0, 0);
188 subtitle_settings ssettings
;
189 dedup
dedupper(0, 0, 0);
192 void distribute_audio_callback(short left
, short right
)
194 for(std::list
<output_driver
*>::iterator i
= drivers
.begin(); i
!= drivers
.end(); ++i
)
195 (*i
)->do_audio_callback(left
, right
);
197 void distribute_video_callback(uint64_t timestamp
, const uint8_t* raw_rgbx_data
)
199 for(std::list
<output_driver
*>::iterator i
= drivers
.begin(); i
!= drivers
.end(); ++i
)
200 (*i
)->do_video_callback(timestamp
, raw_rgbx_data
);
203 void distribute_subtitle_callback(uint64_t basetime
, uint64_t duration
, const uint8_t* text
)
205 for(std::list
<output_driver
*>::iterator i
= drivers
.begin(); i
!= drivers
.end(); ++i
)
206 (*i
)->do_subtitle_callback(basetime
, duration
, text
);
209 void set_audio_parameters(audio_settings a
)
214 void set_video_parameters(video_settings v
)
219 void set_subtitle_parameters(subtitle_settings s
)
224 void add_output_driver(const std::string
& type
, const std::string
& name
, const std::string
& parameters
)
226 output_driver
& driver
= output_driver_factory::make_by_type(type
, name
, parameters
);
227 drivers
.push_back(&driver
);
228 driver
.set_audio_settings(asettings
);
229 driver
.set_video_settings(vsettings
);
230 driver
.set_subtitle_settings(ssettings
);
234 void close_output_drivers()
236 for(std::list
<output_driver
*>::iterator i
= drivers
.begin(); i
!= drivers
.end(); ++i
)
237 (*i
)->do_audio_end_callback();
238 for(std::list
<output_driver
*>::iterator i
= drivers
.begin(); i
!= drivers
.end(); ++i
)
243 void distribute_audio_callback(npair
<short> sample
)
245 distribute_audio_callback(sample
.get_x(), sample
.get_y());
248 void distribute_subtitle_callback(struct packet
& p
)
250 uint64_t basetime
= p
.rp_timestamp
;
251 uint64_t duration
= 0;
252 uint8_t* text
= NULL
;
253 if(p
.rp_major
!= 4 || p
.rp_minor
!= 0 || p
.rp_payload
.size() < 8)
254 return; //Bad subtitle packet.
255 for(size_t i
= 0; i
< 8; i
++)
256 duration
|= ((uint64_t)p
.rp_payload
[i
] << (56 - 8 * i
));
257 text
= &p
.rp_payload
[8];
258 distribute_subtitle_callback(basetime
, duration
, text
);
261 std::string
get_output_driver_list()
264 if(!output_driver_factory::factories
)
267 std::map
<std::string
, output_driver_factory
*>& f
= *output_driver_factory::factories
;
268 for(std::map
<std::string
, output_driver_factory
*>::iterator i
= f
.begin(); i
!= f
.end(); ++i
) {
272 c
= c
+ " " + i
->first
;
278 std::string
expand_arguments_common(std::string opts
, std::string commaexpand
, std::string equalsexpand
)
282 std::ostringstream ret
;
283 for(size_t i
= 0; i
< opts
.length(); i
++) {
288 ret
<< " " << commaexpand
;
310 void I420_convert_common(const uint8_t* raw_rgbx_data
, uint32_t width
, uint32_t height
, bool uvswap
,
311 void (*writer
)(T target
, const uint8_t* buffer
, size_t bufsize
), T target
)
313 size_t framesize
= 4 * (size_t)width
* height
;
314 std::vector
<unsigned char> tmp(framesize
* 3 / 8);
315 size_t primarysize
= framesize
/ 4;
317 size_t offs2
= primarysize
/ 4;
319 std::swap(offs1
, offs2
);
320 Convert32To_I420Frame(raw_rgbx_data
, &tmp
[0], framesize
/ 4, width
);
321 writer(target
, &tmp
[0], primarysize
);
322 writer(target
, &tmp
[primarysize
+ offs1
], primarysize
/ 4);
323 writer(target
, &tmp
[primarysize
+ offs2
], primarysize
/ 4);
326 void writer_stdio(FILE* target
, const uint8_t* buffer
, size_t bufsize
)
329 if((r
= fwrite(buffer
, 1, bufsize
, target
)) < bufsize
) {
330 std::stringstream str
;
331 str
<< "Error writing frame to output (requested " << bufsize
<< ", got " << r
<< ")";
332 throw std::runtime_error(str
.str());
336 void writer_iostream(std::ostream
* target
, const uint8_t* buffer
, size_t bufsize
)
338 target
->write((const char*)buffer
, bufsize
);
340 std::stringstream str
;
341 str
<< "Error writing frame to output (requested " << bufsize
<< ")";
342 throw std::runtime_error(str
.str());
347 void I420_convert_common(const uint8_t* raw_rgbx_data
, uint32_t width
, uint32_t height
, FILE* out
, bool uvswap
)
349 I420_convert_common(raw_rgbx_data
, width
, height
, uvswap
, writer_stdio
, out
);
352 void I420_convert_common(const uint8_t* raw_rgbx_data
, uint32_t width
, uint32_t height
, std::ostream
& out
,
355 I420_convert_common(raw_rgbx_data
, width
, height
, uvswap
, writer_iostream
, &out
);