23 #include "osdep/shmem.h"
26 #include "libmpdemux/demuxer.h"
33 //#include "vcd_read_bincue.h"
36 static int (*stream_check_interrupt_cb
)(struct input_ctx
*ctx
, int time
);
37 static struct input_ctx
*stream_check_interrupt_ctx
;
39 extern const stream_info_t stream_info_vcd
;
40 extern const stream_info_t stream_info_cdda
;
41 extern const stream_info_t stream_info_netstream
;
42 extern const stream_info_t stream_info_pnm
;
43 extern const stream_info_t stream_info_asf
;
44 extern const stream_info_t stream_info_rtsp
;
45 extern const stream_info_t stream_info_rtp
;
46 extern const stream_info_t stream_info_udp
;
47 extern const stream_info_t stream_info_http1
;
48 extern const stream_info_t stream_info_http2
;
49 extern const stream_info_t stream_info_dvb
;
50 extern const stream_info_t stream_info_tv
;
51 extern const stream_info_t stream_info_radio
;
52 extern const stream_info_t stream_info_pvr
;
53 extern const stream_info_t stream_info_ftp
;
54 extern const stream_info_t stream_info_vstream
;
55 extern const stream_info_t stream_info_dvdnav
;
56 extern const stream_info_t stream_info_smb
;
57 extern const stream_info_t stream_info_sdp
;
58 extern const stream_info_t stream_info_rtsp_sip
;
60 extern const stream_info_t stream_info_cue
;
61 extern const stream_info_t stream_info_null
;
62 extern const stream_info_t stream_info_mf
;
63 extern const stream_info_t stream_info_ffmpeg
;
64 extern const stream_info_t stream_info_file
;
65 extern const stream_info_t stream_info_ifo
;
66 extern const stream_info_t stream_info_dvd
;
68 static const stream_info_t
* const auto_open_streams
[] = {
76 &stream_info_netstream
,
83 &stream_info_rtsp_sip
,
104 #ifdef CONFIG_VSTREAM
105 &stream_info_vstream
,
107 #ifdef CONFIG_LIBSMBCLIENT
111 #ifdef CONFIG_DVDREAD
118 #ifdef CONFIG_LIBAVFORMAT
128 static stream_t
*open_stream_plugin(const stream_info_t
*sinfo
, char *filename
,
129 int mode
, struct MPOpts
*options
,
130 int *file_format
, int *ret
,
131 char **redirected_url
)
135 m_struct_t
* desc
= (m_struct_t
*)sinfo
->opts
;
139 arg
= m_struct_alloc(desc
);
140 if(sinfo
->opts_url
) {
142 { "stream url", arg
, CONF_TYPE_CUSTOM_URL
, 0, 0 ,0, sinfo
->opts
};
143 if(m_option_parse(&url_opt
,"stream url",filename
,arg
,M_CONFIG_FILE
) < 0) {
144 mp_msg(MSGT_OPEN
,MSGL_ERR
, "URL parsing failed on url %s\n",filename
);
145 m_struct_free(desc
,arg
);
150 s
= new_stream(-2,-2);
152 s
->url
=strdup(filename
);
154 *ret
= sinfo
->open(s
,mode
,arg
,file_format
);
155 if((*ret
) != STREAM_OK
) {
156 #ifdef CONFIG_NETWORK
157 if (*ret
== STREAM_REDIRECTED
&& redirected_url
) {
158 if (s
->streaming_ctrl
&& s
->streaming_ctrl
->url
159 && s
->streaming_ctrl
->url
->url
)
160 *redirected_url
= strdup(s
->streaming_ctrl
->url
->url
);
162 *redirected_url
= NULL
;
164 streaming_ctrl_free(s
->streaming_ctrl
);
171 mp_msg(MSGT_OPEN
,MSGL_WARN
, "Warning streams need a type !!!!\n");
172 if(s
->flags
& MP_STREAM_SEEK
&& !s
->seek
)
173 s
->flags
&= ~MP_STREAM_SEEK
;
174 if(s
->seek
&& !(s
->flags
& MP_STREAM_SEEK
))
175 s
->flags
|= MP_STREAM_SEEK
;
179 mp_msg(MSGT_OPEN
,MSGL_V
, "STREAM: [%s] %s\n",sinfo
->name
,filename
);
180 mp_msg(MSGT_OPEN
,MSGL_V
, "STREAM: Description: %s\n",sinfo
->info
);
181 mp_msg(MSGT_OPEN
,MSGL_V
, "STREAM: Author: %s\n", sinfo
->author
);
182 mp_msg(MSGT_OPEN
,MSGL_V
, "STREAM: Comment: %s\n", sinfo
->comment
);
188 stream_t
*open_stream_full(char *filename
,int mode
, struct MPOpts
*options
,
192 const stream_info_t
* sinfo
;
194 char *redirected_url
= NULL
;
196 for(i
= 0 ; auto_open_streams
[i
] ; i
++) {
197 sinfo
= auto_open_streams
[i
];
198 if(!sinfo
->protocols
) {
199 mp_msg(MSGT_OPEN
,MSGL_WARN
, "Stream type %s has protocols == NULL, it's a bug\n", sinfo
->name
);
202 for(j
= 0 ; sinfo
->protocols
[j
] ; j
++) {
203 l
= strlen(sinfo
->protocols
[j
]);
204 // l == 0 => Don't do protocol matching (ie network and filenames)
205 if((l
== 0 && !strstr(filename
, "://")) ||
206 ((strncasecmp(sinfo
->protocols
[j
],filename
,l
) == 0) &&
207 (strncmp("://",filename
+l
,3) == 0))) {
208 *file_format
= DEMUXER_TYPE_UNKNOWN
;
209 s
= open_stream_plugin(sinfo
,filename
,mode
,options
,file_format
,&r
,
212 if(r
== STREAM_REDIRECTED
&& redirected_url
) {
213 mp_msg(MSGT_OPEN
,MSGL_V
, "[%s] open %s redirected to %s\n",
214 sinfo
->info
, filename
, redirected_url
);
215 s
= open_stream_full(redirected_url
, mode
, options
, file_format
);
216 free(redirected_url
);
219 else if(r
!= STREAM_UNSUPPORTED
) {
220 mp_tmsg(MSGT_OPEN
,MSGL_ERR
, "Failed to open %s.\n",filename
);
228 mp_msg(MSGT_OPEN
,MSGL_ERR
, "No stream found to handle url %s\n",filename
);
232 stream_t
*open_output_stream(char *filename
, struct MPOpts
*options
)
234 int file_format
; //unused
236 mp_msg(MSGT_OPEN
,MSGL_ERR
,"open_output_stream(), NULL filename, report this bug\n");
240 return open_stream_full(filename
,STREAM_WRITE
,options
,&file_format
);
243 //=================== STREAMER =========================
245 int stream_fill_buffer(stream_t
*s
){
247 if (/*s->fd == NULL ||*/ s
->eof
) { s
->buf_pos
= s
->buf_len
= 0; return 0; }
249 case STREAMTYPE_STREAM
:
250 #ifdef CONFIG_NETWORK
251 if( s
->streaming_ctrl
!=NULL
&& s
->streaming_ctrl
->streaming_read
) {
252 len
=s
->streaming_ctrl
->streaming_read(s
->fd
,s
->buffer
,STREAM_BUFFER_SIZE
, s
->streaming_ctrl
);
256 len
= s
->fill_buffer(s
, s
->buffer
, STREAM_BUFFER_SIZE
);
258 len
=read(s
->fd
,s
->buffer
,STREAM_BUFFER_SIZE
);
261 len
= demux_read_data((demux_stream_t
*)s
->priv
,s
->buffer
,STREAM_BUFFER_SIZE
);
266 len
= s
->fill_buffer
? s
->fill_buffer(s
,s
->buffer
,STREAM_BUFFER_SIZE
) : 0;
268 if(len
<=0){ s
->eof
=1; s
->buf_pos
=s
->buf_len
=0; return 0; }
272 // printf("[%d]",len);fflush(stdout);
276 int stream_write_buffer(stream_t
*s
, unsigned char *buf
, int len
) {
280 rd
= s
->write_buffer(s
, buf
, len
);
287 int stream_seek_long(stream_t
*s
,off_t pos
){
290 // if( mp_msg_test(MSGT_STREAM,MSGL_DBG3) ) printf("seek_long to 0x%X\n",(unsigned int)pos);
292 s
->buf_pos
=s
->buf_len
=0;
294 if(s
->mode
== STREAM_WRITE
) {
295 if(!s
->seek
|| !s
->seek(s
,pos
))
301 newpos
= (pos
/s
->sector_size
)*s
->sector_size
;
303 newpos
= pos
&(~((off_t
)STREAM_BUFFER_SIZE
-1));
305 if( mp_msg_test(MSGT_STREAM
,MSGL_DBG3
) ){
306 mp_msg(MSGT_STREAM
,MSGL_DBG3
, "s->pos=%"PRIX64
" newpos=%"PRIX64
" new_bufpos=%"PRIX64
" buflen=%X \n",
307 (int64_t)s
->pos
,(int64_t)newpos
,(int64_t)pos
,s
->buf_len
);
311 if(newpos
==0 || newpos
!=s
->pos
){
313 case STREAMTYPE_STREAM
:
314 //s->pos=newpos; // real seek
315 // Some streaming protocol allow to seek backward and forward
316 // A function call that return -1 can tell that the protocol
317 // doesn't support seeking.
318 #ifdef CONFIG_NETWORK
319 if(s
->seek
) { // new stream seek is much cleaner than streaming_ctrl one
320 if(!s
->seek(s
,newpos
)) {
321 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Seek failed\n");
327 if( s
->streaming_ctrl
!=NULL
&& s
->streaming_ctrl
->streaming_seek
) {
328 if( s
->streaming_ctrl
->streaming_seek( s
->fd
, pos
, s
->streaming_ctrl
)<0 ) {
329 mp_msg(MSGT_STREAM
,MSGL_INFO
,"Stream not seekable!\n");
336 mp_msg(MSGT_STREAM
,MSGL_INFO
,"Cannot seek backward in linear streams!\n");
339 while(s
->pos
<newpos
){
340 if(stream_fill_buffer(s
)<=0) break; // EOF
344 // This should at the beginning as soon as all streams are converted
348 if(!s
->seek(s
,newpos
)) {
349 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Seek failed\n");
353 // putchar('.');fflush(stdout);
355 // putchar('%');fflush(stdout);
358 while(stream_fill_buffer(s
) > 0 && pos
>= 0) {
360 s
->buf_pos
=pos
; // byte position in sector
366 // if(pos==s->buf_len) printf("XXX Seek to last byte of file -> EOF\n");
368 mp_msg(MSGT_STREAM
,MSGL_V
,"stream_seek: WARNING! Can't seek to 0x%"PRIX64
" !\n",(int64_t)(pos
+newpos
));
373 void stream_reset(stream_t
*s
){
375 s
->pos
=0; //ftell(f);
376 // s->buf_pos=s->buf_len=0;
379 if(s
->control
) s
->control(s
,STREAM_CTRL_RESET
,NULL
);
383 int stream_control(stream_t
*s
, int cmd
, void *arg
){
384 if(!s
->control
) return STREAM_UNSUPPORTED
;
385 #ifdef CONFIG_STREAM_CACHE
387 return cache_do_control(s
, cmd
, arg
);
389 return s
->control(s
, cmd
, arg
);
392 stream_t
* new_memory_stream(unsigned char* data
,int len
){
397 s
=calloc(1, sizeof(stream_t
)+len
);
399 s
->type
=STREAMTYPE_MEMORY
;
400 s
->buf_pos
=0; s
->buf_len
=len
;
401 s
->start_pos
=0; s
->end_pos
=len
;
404 memcpy(s
->buffer
,data
,len
);
408 stream_t
* new_stream(int fd
,int type
){
409 stream_t
*s
=calloc(1, sizeof(stream_t
));
410 if(s
==NULL
) return NULL
;
415 int temp
= WSAStartup(0x0202, &wsdata
); // there might be a better place for this (-> later)
416 mp_msg(MSGT_STREAM
,MSGL_V
,"WINSOCK2 init: %i\n", temp
);
422 s
->buf_pos
=s
->buf_len
=0;
423 s
->start_pos
=s
->end_pos
=0;
431 void free_stream(stream_t
*s
){
432 // printf("\n*** free_stream() called ***\n");
433 #ifdef CONFIG_STREAM_CACHE
438 if(s
->close
) s
->close(s
);
440 /* on unix we define closesocket to close
441 on windows however we have to distinguish between
442 network socket and file */
443 if(s
->url
&& strstr(s
->url
,"://"))
448 mp_msg(MSGT_STREAM
,MSGL_V
,"WINSOCK2 uninit\n");
449 WSACleanup(); // there might be a better place for this (-> later)
451 // Disabled atm, i don't like that. s->priv can be anything after all
452 // streams should destroy their priv on close
453 //if(s->priv) free(s->priv);
454 if(s
->url
) free(s
->url
);
458 stream_t
* new_ds_stream(demux_stream_t
*ds
) {
459 stream_t
* s
= new_stream(-1,STREAMTYPE_DS
);
464 void stream_set_interrupt_callback(int (*cb
)(struct input_ctx
*, int),
465 struct input_ctx
*ctx
)
467 stream_check_interrupt_cb
= cb
;
468 stream_check_interrupt_ctx
= ctx
;
471 int stream_check_interrupt(int time
) {
472 if(!stream_check_interrupt_cb
) return 0;
473 return stream_check_interrupt_cb(stream_check_interrupt_ctx
, time
);