| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 24 |
|
|---|
| 25 |
|
|---|
| 26 |
|
|---|
| 27 |
|
|---|
| 28 |
#ifdef HAVE_CONFIG_H |
|---|
| 29 |
# include "config.h" |
|---|
| 30 |
#endif |
|---|
| 31 |
|
|---|
| 32 |
#include <vlc_common.h> |
|---|
| 33 |
#include <vlc_block.h> |
|---|
| 34 |
#include <vlc_sout.h> |
|---|
| 35 |
|
|---|
| 36 |
|
|---|
| 37 |
#ifdef HAVE_LIBAVFORMAT_AVFORMAT_H |
|---|
| 38 |
# include <libavformat/avformat.h> |
|---|
| 39 |
#elif defined(HAVE_FFMPEG_AVFORMAT_H) |
|---|
| 40 |
# include <ffmpeg/avformat.h> |
|---|
| 41 |
#endif |
|---|
| 42 |
|
|---|
| 43 |
#include "avformat.h" |
|---|
| 44 |
#include "../../codec/avcodec/fourcc.h" |
|---|
| 45 |
#include "../../codec/avcodec/avutil.h" |
|---|
| 46 |
|
|---|
| 47 |
|
|---|
| 48 |
|
|---|
| 49 |
static const char *const ppsz_mux_options[] = { |
|---|
| 50 |
"mux", NULL |
|---|
| 51 |
}; |
|---|
| 52 |
|
|---|
| 53 |
|
|---|
| 54 |
|
|---|
| 55 |
|
|---|
| 56 |
struct sout_mux_sys_t |
|---|
| 57 |
{ |
|---|
| 58 |
ByteIOContext io; |
|---|
| 59 |
int io_buffer_size; |
|---|
| 60 |
uint8_t *io_buffer; |
|---|
| 61 |
|
|---|
| 62 |
AVFormatContext *oc; |
|---|
| 63 |
URLContext url; |
|---|
| 64 |
URLProtocol prot; |
|---|
| 65 |
|
|---|
| 66 |
bool b_write_header; |
|---|
| 67 |
bool b_error; |
|---|
| 68 |
|
|---|
| 69 |
int64_t i_initial_dts; |
|---|
| 70 |
}; |
|---|
| 71 |
|
|---|
| 72 |
|
|---|
| 73 |
|
|---|
| 74 |
|
|---|
| 75 |
static int Control ( sout_mux_t *, int, va_list ); |
|---|
| 76 |
static int AddStream( sout_mux_t *, sout_input_t * ); |
|---|
| 77 |
static int DelStream( sout_mux_t *, sout_input_t * ); |
|---|
| 78 |
static int Mux ( sout_mux_t * ); |
|---|
| 79 |
|
|---|
| 80 |
static int IOWrite( void *opaque, uint8_t *buf, int buf_size ); |
|---|
| 81 |
static offset_t IOSeek( void *opaque, offset_t offset, int whence ); |
|---|
| 82 |
|
|---|
| 83 |
|
|---|
| 84 |
|
|---|
| 85 |
|
|---|
| 86 |
int OpenMux( vlc_object_t *p_this ) |
|---|
| 87 |
{ |
|---|
| 88 |
AVOutputFormat *file_oformat; |
|---|
| 89 |
sout_mux_t *p_mux = (sout_mux_t*)p_this; |
|---|
| 90 |
sout_mux_sys_t *p_sys; |
|---|
| 91 |
AVFormatParameters params, *ap = ¶ms; |
|---|
| 92 |
char *psz_mux; |
|---|
| 93 |
|
|---|
| 94 |
|
|---|
| 95 |
av_register_all(); |
|---|
| 96 |
av_log_set_callback( LibavutilCallback ); |
|---|
| 97 |
|
|---|
| 98 |
config_ChainParse( p_mux, "ffmpeg-", ppsz_mux_options, p_mux->p_cfg ); |
|---|
| 99 |
|
|---|
| 100 |
|
|---|
| 101 |
psz_mux = var_GetNonEmptyString( p_mux, "ffmpeg-mux" ); |
|---|
| 102 |
if( psz_mux ) |
|---|
| 103 |
{ |
|---|
| 104 |
file_oformat = guess_format( psz_mux, NULL, NULL ); |
|---|
| 105 |
} |
|---|
| 106 |
else |
|---|
| 107 |
{ |
|---|
| 108 |
file_oformat = |
|---|
| 109 |
guess_format(NULL, p_mux->p_access->psz_path, NULL); |
|---|
| 110 |
} |
|---|
| 111 |
if (!file_oformat) |
|---|
| 112 |
{ |
|---|
| 113 |
msg_Err( p_mux, "unable for find a suitable output format" ); |
|---|
| 114 |
return VLC_EGENERIC; |
|---|
| 115 |
} |
|---|
| 116 |
|
|---|
| 117 |
|
|---|
| 118 |
p_mux->pf_control = Control; |
|---|
| 119 |
p_mux->pf_addstream = AddStream; |
|---|
| 120 |
p_mux->pf_delstream = DelStream; |
|---|
| 121 |
p_mux->pf_mux = Mux; |
|---|
| 122 |
p_mux->p_sys = p_sys = malloc( sizeof( sout_mux_sys_t ) ); |
|---|
| 123 |
|
|---|
| 124 |
p_sys->oc = av_alloc_format_context(); |
|---|
| 125 |
p_sys->oc->oformat = file_oformat; |
|---|
| 126 |
|
|---|
| 127 |
|
|---|
| 128 |
p_sys->io_buffer_size = 32768; |
|---|
| 129 |
p_sys->io_buffer = malloc( p_sys->io_buffer_size ); |
|---|
| 130 |
p_sys->url.priv_data = p_mux; |
|---|
| 131 |
p_sys->url.prot = &p_sys->prot; |
|---|
| 132 |
p_sys->url.prot->name = "VLC I/O wrapper"; |
|---|
| 133 |
p_sys->url.prot->url_open = 0; |
|---|
| 134 |
p_sys->url.prot->url_read = 0; |
|---|
| 135 |
p_sys->url.prot->url_write = |
|---|
| 136 |
(int (*) (URLContext *, unsigned char *, int))IOWrite; |
|---|
| 137 |
p_sys->url.prot->url_seek = |
|---|
| 138 |
(offset_t (*) (URLContext *, offset_t, int))IOSeek; |
|---|
| 139 |
p_sys->url.prot->url_close = 0; |
|---|
| 140 |
p_sys->url.prot->next = 0; |
|---|
| 141 |
init_put_byte( &p_sys->io, p_sys->io_buffer, p_sys->io_buffer_size, |
|---|
| 142 |
1, &p_sys->url, NULL, IOWrite, IOSeek ); |
|---|
| 143 |
|
|---|
| 144 |
memset( ap, 0, sizeof(*ap) ); |
|---|
| 145 |
if( av_set_parameters( p_sys->oc, ap ) < 0 ) |
|---|
| 146 |
{ |
|---|
| 147 |
msg_Err( p_mux, "invalid encoding parameters" ); |
|---|
| 148 |
av_free( p_sys->oc ); |
|---|
| 149 |
free( p_sys->io_buffer ); |
|---|
| 150 |
free( p_sys ); |
|---|
| 151 |
return VLC_EGENERIC; |
|---|
| 152 |
} |
|---|
| 153 |
|
|---|
| 154 |
#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(0<<8)+0) |
|---|
| 155 |
p_sys->oc->pb = &p_sys->io; |
|---|
| 156 |
#else |
|---|
| 157 |
p_sys->oc->pb = p_sys->io; |
|---|
| 158 |
#endif |
|---|
| 159 |
p_sys->oc->nb_streams = 0; |
|---|
| 160 |
|
|---|
| 161 |
p_sys->b_write_header = true; |
|---|
| 162 |
p_sys->b_error = false; |
|---|
| 163 |
p_sys->i_initial_dts = 0; |
|---|
| 164 |
|
|---|
| 165 |
return VLC_SUCCESS; |
|---|
| 166 |
} |
|---|
| 167 |
|
|---|
| 168 |
|
|---|
| 169 |
|
|---|
| 170 |
|
|---|
| 171 |
void CloseMux( vlc_object_t *p_this ) |
|---|
| 172 |
{ |
|---|
| 173 |
sout_mux_t *p_mux = (sout_mux_t*)p_this; |
|---|
| 174 |
sout_mux_sys_t *p_sys = p_mux->p_sys; |
|---|
| 175 |
unsigned int i; |
|---|
| 176 |
|
|---|
| 177 |
if( av_write_trailer( p_sys->oc ) < 0 ) |
|---|
| 178 |
{ |
|---|
| 179 |
msg_Err( p_mux, "could not write trailer" ); |
|---|
| 180 |
} |
|---|
| 181 |
|
|---|
| 182 |
for( i = 0 ; i < p_sys->oc->nb_streams; i++ ) |
|---|
| 183 |
{ |
|---|
| 184 |
if( p_sys->oc->streams[i]->codec->extradata ) |
|---|
| 185 |
av_free( p_sys->oc->streams[i]->codec->extradata ); |
|---|
| 186 |
av_free( p_sys->oc->streams[i]->codec ); |
|---|
| 187 |
av_free( p_sys->oc->streams[i] ); |
|---|
| 188 |
} |
|---|
| 189 |
av_free( p_sys->oc ); |
|---|
| 190 |
|
|---|
| 191 |
free( p_sys->io_buffer ); |
|---|
| 192 |
free( p_sys ); |
|---|
| 193 |
} |
|---|
| 194 |
|
|---|
| 195 |
|
|---|
| 196 |
|
|---|
| 197 |
|
|---|
| 198 |
static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) |
|---|
| 199 |
{ |
|---|
| 200 |
sout_mux_sys_t *p_sys = p_mux->p_sys; |
|---|
| 201 |
AVCodecContext *codec; |
|---|
| 202 |
AVStream *stream; |
|---|
| 203 |
int i_codec_id, i_aspect_num, i_aspect_den; |
|---|
| 204 |
|
|---|
| 205 |
msg_Dbg( p_mux, "adding input" ); |
|---|
| 206 |
|
|---|
| 207 |
if( !GetFfmpegCodec( p_input->p_fmt->i_codec, 0, &i_codec_id, 0 ) ) |
|---|
| 208 |
{ |
|---|
| 209 |
msg_Dbg( p_mux, "couldn't find codec for fourcc '%4.4s'", |
|---|
| 210 |
(char *)&p_input->p_fmt->i_codec ); |
|---|
| 211 |
return VLC_EGENERIC; |
|---|
| 212 |
} |
|---|
| 213 |
|
|---|
| 214 |
p_input->p_sys = malloc( sizeof( int ) ); |
|---|
| 215 |
*((int *)p_input->p_sys) = p_sys->oc->nb_streams; |
|---|
| 216 |
|
|---|
| 217 |
stream = av_new_stream( p_sys->oc, p_sys->oc->nb_streams); |
|---|
| 218 |
if( !stream ) |
|---|
| 219 |
{ |
|---|
| 220 |
free( p_input->p_sys ); |
|---|
| 221 |
return VLC_EGENERIC; |
|---|
| 222 |
} |
|---|
| 223 |
codec = stream->codec; |
|---|
| 224 |
|
|---|
| 225 |
|
|---|
| 226 |
codec->opaque = (void*)p_mux; |
|---|
| 227 |
|
|---|
| 228 |
switch( p_input->p_fmt->i_cat ) |
|---|
| 229 |
{ |
|---|
| 230 |
case AUDIO_ES: |
|---|
| 231 |
codec->codec_type = CODEC_TYPE_AUDIO; |
|---|
| 232 |
codec->channels = p_input->p_fmt->audio.i_channels; |
|---|
| 233 |
codec->sample_rate = p_input->p_fmt->audio.i_rate; |
|---|
| 234 |
codec->time_base = (AVRational){1, codec->sample_rate}; |
|---|
| 235 |
break; |
|---|
| 236 |
|
|---|
| 237 |
case VIDEO_ES: |
|---|
| 238 |
if( !p_input->p_fmt->video.i_frame_rate || |
|---|
| 239 |
!p_input->p_fmt->video.i_frame_rate_base ) |
|---|
| 240 |
{ |
|---|
| 241 |
msg_Warn( p_mux, "Missing frame rate, assuming 25fps" ); |
|---|
| 242 |
p_input->p_fmt->video.i_frame_rate = 25; |
|---|
| 243 |
p_input->p_fmt->video.i_frame_rate_base = 1; |
|---|
| 244 |
} |
|---|
| 245 |
codec->codec_type = CODEC_TYPE_VIDEO; |
|---|
| 246 |
codec->width = p_input->p_fmt->video.i_width; |
|---|
| 247 |
codec->height = p_input->p_fmt->video.i_height; |
|---|
| 248 |
av_reduce( &i_aspect_num, &i_aspect_den, |
|---|
| 249 |
p_input->p_fmt->video.i_aspect, |
|---|
| 250 |
VOUT_ASPECT_FACTOR, 1 << 30 ); |
|---|
| 251 |
av_reduce( &codec->sample_aspect_ratio.num, |
|---|
| 252 |
&codec->sample_aspect_ratio.den, |
|---|
| 253 |
i_aspect_num * (int64_t)codec->height, |
|---|
| 254 |
i_aspect_den * (int64_t)codec->width, 1 << 30 ); |
|---|
| 255 |
codec->time_base.den = p_input->p_fmt->video.i_frame_rate; |
|---|
| 256 |
codec->time_base.num = p_input->p_fmt->video.i_frame_rate_base; |
|---|
| 257 |
break; |
|---|
| 258 |
|
|---|
| 259 |
default: |
|---|
| 260 |
msg_Warn( p_mux, "Unhandled ES category" ); |
|---|
| 261 |
} |
|---|
| 262 |
|
|---|
| 263 |
codec->bit_rate = p_input->p_fmt->i_bitrate; |
|---|
| 264 |
#if LIBAVFORMAT_VERSION_INT >= ((51<<16)+(8<<8)+0) |
|---|
| 265 |
codec->codec_tag = av_codec_get_tag( p_sys->oc->oformat->codec_tag, i_codec_id ); |
|---|
| 266 |
if( !codec->codec_tag && i_codec_id == CODEC_ID_MP2 ) |
|---|
| 267 |
{ |
|---|
| 268 |
i_codec_id = CODEC_ID_MP3; |
|---|
| 269 |
codec->codec_tag = av_codec_get_tag( p_sys->oc->oformat->codec_tag, i_codec_id ); |
|---|
| 270 |
} |
|---|
| 271 |
#else |
|---|
| 272 |
# warning "WARNING!!!!!!!" |
|---|
| 273 |
# warning "Using libavformat muxing with versions older than 51.8.0 (r7593) might produce broken files." |
|---|
| 274 |
|
|---|
| 275 |
if( i_codec_id == CODEC_ID_MP2 ) |
|---|
| 276 |
i_codec_id = CODEC_ID_MP3; |
|---|
| 277 |
codec->codec_tag = p_input->p_fmt->i_codec; |
|---|
| 278 |
#endif |
|---|
| 279 |
codec->codec_id = i_codec_id; |
|---|
| 280 |
|
|---|
| 281 |
if( p_input->p_fmt->i_extra ) |
|---|
| 282 |
{ |
|---|
| 283 |
codec->extradata_size = p_input->p_fmt->i_extra; |
|---|
| 284 |
codec->extradata = av_malloc( p_input->p_fmt->i_extra ); |
|---|
| 285 |
memcpy( codec->extradata, p_input->p_fmt->p_extra, |
|---|
| 286 |
p_input->p_fmt->i_extra ); |
|---|
| 287 |
} |
|---|
| 288 |
|
|---|
| 289 |
return VLC_SUCCESS; |
|---|
| 290 |
} |
|---|
| 291 |
|
|---|
| 292 |
|
|---|
| 293 |
|
|---|
| 294 |
|
|---|
| 295 |
static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input ) |
|---|
| 296 |
{ |
|---|
| 297 |
msg_Dbg( p_mux, "removing input" ); |
|---|
| 298 |
free( p_input->p_sys ); |
|---|
| 299 |
return VLC_SUCCESS; |
|---|
| 300 |
} |
|---|
| 301 |
|
|---|
| 302 |
|
|---|
| 303 |
|
|---|
| 304 |
|
|---|
| 305 |
static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts ) |
|---|
| 306 |
{ |
|---|
| 307 |
mtime_t i_dts; |
|---|
| 308 |
int i_stream, i; |
|---|
| 309 |
|
|---|
| 310 |
for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ ) |
|---|
| 311 |
{ |
|---|
| 312 |
block_fifo_t *p_fifo; |
|---|
| 313 |
|
|---|
| 314 |
p_fifo = p_mux->pp_inputs[i]->p_fifo; |
|---|
| 315 |
|
|---|
| 316 |
|
|---|
| 317 |
if( p_mux->pp_inputs[i]->p_fmt->i_cat == SPU_ES && |
|---|
| 318 |
block_FifoCount( p_fifo ) == 0 ) continue; |
|---|
| 319 |
|
|---|
| 320 |
if( block_FifoCount( p_fifo ) ) |
|---|
| 321 |
{ |
|---|
| 322 |
block_t *p_buf; |
|---|
| 323 |
|
|---|
| 324 |
p_buf = block_FifoShow( p_fifo ); |
|---|
| 325 |
if( i_stream < 0 || p_buf->i_dts < i_dts ) |
|---|
| 326 |
{ |
|---|
| 327 |
i_dts = p_buf->i_dts; |
|---|
| 328 |
i_stream = i; |
|---|
| 329 |
} |
|---|
| 330 |
} |
|---|
| 331 |
else return -1; |
|---|
| 332 |
|
|---|
| 333 |
} |
|---|
| 334 |
if( pi_stream ) *pi_stream = i_stream; |
|---|
| 335 |
if( pi_dts ) *pi_dts = i_dts; |
|---|
| 336 |
if( !p_mux->p_sys->i_initial_dts ) p_mux->p_sys->i_initial_dts = i_dts; |
|---|
| 337 |
return i_stream; |
|---|
| 338 |
} |
|---|
| 339 |
|
|---|
| 340 |
static int MuxBlock( sout_mux_t *p_mux, sout_input_t *p_input ) |
|---|
| 341 |
{ |
|---|
| 342 |
sout_mux_sys_t *p_sys = p_mux->p_sys; |
|---|
| 343 |
block_t *p_data = block_FifoGet( p_input->p_fifo ); |
|---|
| 344 |
int i_stream = *((int *)p_input->p_sys); |
|---|
| 345 |
AVStream *p_stream = p_sys->oc->streams[i_stream]; |
|---|
| 346 |
AVPacket pkt; |
|---|
| 347 |
|
|---|
| 348 |
memset( &pkt, 0, sizeof(AVPacket) ); |
|---|
| 349 |
|
|---|
| 350 |
av_init_packet(&pkt); |
|---|
| 351 |
pkt.data = p_data->p_buffer; |
|---|
| 352 |
pkt.size = p_data->i_buffer; |
|---|
| 353 |
pkt.stream_index = i_stream; |
|---|
| 354 |
|
|---|
| 355 |
if( p_data->i_flags & BLOCK_FLAG_TYPE_I ) pkt.flags |= PKT_FLAG_KEY; |
|---|
| 356 |
|
|---|
| 357 |
|
|---|
| 358 |
p_data->i_dts -= p_mux->p_sys->i_initial_dts; |
|---|
| 359 |
p_data->i_pts -= p_mux->p_sys->i_initial_dts; |
|---|
| 360 |
|
|---|
| 361 |
if( p_data->i_pts > 0 ) |
|---|
| 362 |
pkt.pts = p_data->i_pts * p_stream->time_base.den / |
|---|
| 363 |
INT64_C(1000000) / p_stream->time_base.num; |
|---|
| 364 |
if( p_data->i_dts > 0 ) |
|---|
| 365 |
pkt.dts = p_data->i_dts * p_stream->time_base.den / |
|---|
| 366 |
INT64_C(1000000) / p_stream->time_base.num; |
|---|
| 367 |
|
|---|
| 368 |
|
|---|
| 369 |
p_stream->cur_dts = ( p_data->i_dts * p_stream->time_base.den / |
|---|
| 370 |
INT64_C(1000000) / p_stream->time_base.num ) - 1; |
|---|
| 371 |
|
|---|
| 372 |
if( av_write_frame( p_sys->oc, &pkt ) < 0 ) |
|---|
| 373 |
{ |
|---|
| 374 |
msg_Err( p_mux, "could not write frame (pts: %"PRId64", dts: %"PRId64") " |
|---|
| 375 |
"(pkt pts: %"PRId64", dts: %"PRId64")", |
|---|
| 376 |
p_data->i_pts, p_data->i_dts, pkt.pts, pkt.dts ); |
|---|
| 377 |
block_Release( p_data ); |
|---|
| 378 |
return VLC_EGENERIC; |
|---|
| 379 |
} |
|---|
| 380 |
|
|---|
| 381 |
block_Release( p_data ); |
|---|
| 382 |
return VLC_SUCCESS; |
|---|
| 383 |
} |
|---|
| 384 |
|
|---|
| 385 |
|
|---|
| 386 |
|
|---|
| 387 |
|
|---|
| 388 |
static int Mux( sout_mux_t *p_mux ) |
|---|
| 389 |
{ |
|---|
| 390 |
sout_mux_sys_t *p_sys = p_mux->p_sys; |
|---|
| 391 |
int i_stream; |
|---|
| 392 |
|
|---|
| 393 |
if( p_sys->b_error ) return VLC_EGENERIC; |
|---|
| 394 |
|
|---|
| 395 |
if( p_sys->b_write_header ) |
|---|
| 396 |
{ |
|---|
| 397 |
msg_Dbg( p_mux, "writing header" ); |
|---|
| 398 |
|
|---|
| 399 |
if( av_write_header( p_sys->oc ) < 0 ) |
|---|
| 400 |
{ |
|---|
| 401 |
msg_Err( p_mux, "could not write header" ); |
|---|
| 402 |
p_sys->b_write_header = false; |
|---|
| 403 |
p_sys->b_error = true; |
|---|
| 404 |
return VLC_EGENERIC; |
|---|
| 405 |
} |
|---|
| 406 |
|
|---|
| 407 |
#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(0<<8)+0) |
|---|
| 408 |
put_flush_packet( p_sys->oc->pb ); |
|---|
| 409 |
#else |
|---|
| 410 |
put_flush_packet( &p_sys->oc->pb ); |
|---|
| 411 |
#endif |
|---|
| 412 |
p_sys->b_write_header = false; |
|---|
| 413 |
} |
|---|
| 414 |
|
|---|
| 415 |
for( ;; ) |
|---|
| 416 |
{ |
|---|
| 417 |
if( MuxGetStream( p_mux, &i_stream, 0 ) < 0 ) return VLC_SUCCESS; |
|---|
| 418 |
MuxBlock( p_mux, p_mux->pp_inputs[i_stream] ); |
|---|
| 419 |
} |
|---|
| 420 |
|
|---|
| 421 |
return VLC_SUCCESS; |
|---|
| 422 |
} |
|---|
| 423 |
|
|---|
| 424 |
|
|---|
| 425 |
|
|---|
| 426 |
|
|---|
| 427 |
static int Control( sout_mux_t *p_mux, int i_query, va_list args ) |
|---|
| 428 |
{ |
|---|
| 429 |
bool *pb_bool; |
|---|
| 430 |
|
|---|
| 431 |
switch( i_query ) |
|---|
| 432 |
{ |
|---|
| 433 |
case MUX_CAN_ADD_STREAM_WHILE_MUXING: |
|---|
| 434 |
pb_bool = (bool*)va_arg( args, bool * ); |
|---|
| 435 |
*pb_bool = false; |
|---|
| 436 |
return VLC_SUCCESS; |
|---|
| 437 |
|
|---|
| 438 |
case MUX_GET_ADD_STREAM_WAIT: |
|---|
| 439 |
pb_bool = (bool*)va_arg( args, bool * ); |
|---|
| 440 |
*pb_bool = true; |
|---|
| 441 |
return VLC_SUCCESS; |
|---|
| 442 |
|
|---|
| 443 |
case MUX_GET_MIME: |
|---|
| 444 |
{ |
|---|
| 445 |
char **ppsz = (char**)va_arg( args, char ** ); |
|---|
| 446 |
*ppsz = strdup( p_mux->p_sys->oc->oformat->mime_type ); |
|---|
| 447 |
return VLC_SUCCESS; |
|---|
| 448 |
} |
|---|
| 449 |
|
|---|
| 450 |
default: |
|---|
| 451 |
return VLC_EGENERIC; |
|---|
| 452 |
} |
|---|
| 453 |
} |
|---|
| 454 |
|
|---|
| 455 |
|
|---|
| 456 |
|
|---|
| 457 |
|
|---|
| 458 |
static int IOWrite( void *opaque, uint8_t *buf, int buf_size ) |
|---|
| 459 |
{ |
|---|
| 460 |
URLContext *p_url = opaque; |
|---|
| 461 |
sout_mux_t *p_mux = p_url->priv_data; |
|---|
| 462 |
int i_ret; |
|---|
| 463 |
|
|---|
| 464 |
#ifdef AVFORMAT_DEBUG |
|---|
| 465 |
msg_Dbg( p_mux, "IOWrite %i bytes", buf_size ); |
|---|
| 466 |
#endif |
|---|
| 467 |
|
|---|
| 468 |
block_t *p_buf = block_New( p_mux->p_sout, buf_size ); |
|---|
| 469 |
if( buf_size > 0 ) memcpy( p_buf->p_buffer, buf, buf_size ); |
|---|
| 470 |
|
|---|
| 471 |
if( p_mux->p_sys->b_write_header ) |
|---|
| 472 |
p_buf->i_flags |= BLOCK_FLAG_HEADER; |
|---|
| 473 |
|
|---|
| 474 |
i_ret = sout_AccessOutWrite( p_mux->p_access, p_buf ); |
|---|
| 475 |
return i_ret ? i_ret : -1; |
|---|
| 476 |
} |
|---|
| 477 |
|
|---|
| 478 |
static offset_t IOSeek( void *opaque, offset_t offset, int whence ) |
|---|
| 479 |
{ |
|---|
| 480 |
URLContext *p_url = opaque; |
|---|
| 481 |
sout_mux_t *p_mux = p_url->priv_data; |
|---|
| 482 |
int64_t i_absolute; |
|---|
| 483 |
|
|---|
| 484 |
#ifdef AVFORMAT_DEBUG |
|---|
| 485 |
msg_Dbg( p_mux, "IOSeek offset: %"PRId64", whence: %i", offset, whence ); |
|---|
| 486 |
#endif |
|---|
| 487 |
|
|---|
| 488 |
switch( whence ) |
|---|
| 489 |
{ |
|---|
| 490 |
case SEEK_SET: |
|---|
| 491 |
i_absolute = offset; |
|---|
| 492 |
break; |
|---|
| 493 |
case SEEK_CUR: |
|---|
| 494 |
case SEEK_END: |
|---|
| 495 |
default: |
|---|
| 496 |
return -1; |
|---|
| 497 |
} |
|---|
| 498 |
|
|---|
| 499 |
if( sout_AccessOutSeek( p_mux->p_access, i_absolute ) ) |
|---|
| 500 |
{ |
|---|
| 501 |
return -1; |
|---|
| 502 |
} |
|---|
| 503 |
|
|---|
| 504 |
return 0; |
|---|
| 505 |
} |
|---|