docs: document --quvi-format
[mplayer.git] / stream / stream_file.c
blobdfafb773f0b1b46478bc72b6805ba519555b5fd1
1 /*
2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "config.h"
21 #include <stdio.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <errno.h>
28 #include "osdep/io.h"
30 #include "mp_msg.h"
31 #include "stream.h"
32 #include "m_option.h"
33 #include "m_struct.h"
35 static struct stream_priv_s {
36 char* filename;
37 char *filename2;
38 } stream_priv_dflts = {
39 NULL, NULL
42 #define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f)
43 /// URL definition
44 static const m_option_t stream_opts_fields[] = {
45 {"string", ST_OFF(filename), CONF_TYPE_STRING, 0, 0 ,0, NULL},
46 {"filename", ST_OFF(filename2), CONF_TYPE_STRING, 0, 0 ,0, NULL},
47 { NULL, NULL, 0, 0, 0, 0, NULL }
49 static const struct m_struct_st stream_opts = {
50 "file",
51 sizeof(struct stream_priv_s),
52 &stream_priv_dflts,
53 stream_opts_fields
56 static int fill_buffer(stream_t *s, char* buffer, int max_len){
57 int r = read(s->fd,buffer,max_len);
58 return (r <= 0) ? -1 : r;
61 static int write_buffer(stream_t *s, char* buffer, int len) {
62 int r;
63 int wr = 0;
64 while (wr < len) {
65 r = write(s->fd,buffer,len);
66 if (r <= 0)
67 return -1;
68 wr += r;
69 buffer += r;
71 return len;
74 static int seek(stream_t *s,off_t newpos) {
75 s->pos = newpos;
76 if(lseek(s->fd,s->pos,SEEK_SET)<0) {
77 s->eof=1;
78 return 0;
80 return 1;
83 static int seek_forward(stream_t *s,off_t newpos) {
84 if(newpos<s->pos){
85 mp_msg(MSGT_STREAM,MSGL_INFO,"Cannot seek backward in linear streams!\n");
86 return 0;
88 while(s->pos<newpos){
89 int len=s->fill_buffer(s,s->buffer,STREAM_BUFFER_SIZE);
90 if(len<=0){ s->eof=1; s->buf_pos=s->buf_len=0; break; } // EOF
91 s->buf_pos=0;
92 s->buf_len=len;
93 s->pos+=len;
95 return 1;
98 static int control(stream_t *s, int cmd, void *arg) {
99 switch(cmd) {
100 case STREAM_CTRL_GET_SIZE: {
101 off_t size;
103 size = lseek(s->fd, 0, SEEK_END);
104 lseek(s->fd, s->pos, SEEK_SET);
105 if(size != (off_t)-1) {
106 *((off_t*)arg) = size;
107 return 1;
111 return STREAM_UNSUPPORTED;
114 static int open_f(stream_t *stream,int mode, void* opts, int* file_format) {
115 int f;
116 mode_t m = 0;
117 off_t len;
118 unsigned char *filename;
119 struct stream_priv_s* p = (struct stream_priv_s*)opts;
121 if(mode == STREAM_READ)
122 m = O_RDONLY;
123 else if(mode == STREAM_WRITE)
124 m = O_RDWR|O_CREAT|O_TRUNC;
125 else {
126 mp_msg(MSGT_OPEN,MSGL_ERR, "[file] Unknown open mode %d\n",mode);
127 m_struct_free(&stream_opts,opts);
128 return STREAM_UNSUPPORTED;
131 if(p->filename)
132 filename = p->filename;
133 else if(p->filename2)
134 filename = p->filename2;
135 else
136 filename = NULL;
137 if(!filename) {
138 mp_msg(MSGT_OPEN,MSGL_ERR, "[file] No filename\n");
139 m_struct_free(&stream_opts,opts);
140 return STREAM_ERROR;
143 #if HAVE_DOS_PATHS
144 // extract '/' from '/x:/path'
145 if( filename[ 0 ] == '/' && filename[ 1 ] && filename[ 2 ] == ':' )
146 filename++;
147 #endif
149 m |= O_BINARY;
151 if(!strcmp(filename,"-")){
152 if(mode == STREAM_READ) {
153 // read from stdin
154 mp_tmsg(MSGT_OPEN,MSGL_INFO,"Reading from stdin...\n");
155 f=0; // 0=stdin
156 #if HAVE_SETMODE
157 setmode(fileno(stdin),O_BINARY);
158 #endif
159 } else {
160 mp_msg(MSGT_OPEN,MSGL_INFO,"Writing to stdout\n");
161 f=1;
162 #if HAVE_SETMODE
163 setmode(fileno(stdout),O_BINARY);
164 #endif
166 } else {
167 mode_t openmode = S_IRUSR|S_IWUSR;
168 #ifndef __MINGW32__
169 openmode |= S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
170 #endif
171 f=open(filename,m, openmode);
172 if(f<0) {
173 mp_tmsg(MSGT_OPEN, MSGL_ERR, "Cannot open file '%s': %s\n", filename,
174 strerror(errno));
175 m_struct_free(&stream_opts,opts);
176 return STREAM_ERROR;
178 #ifndef __MINGW32__
179 struct stat st;
180 if (fstat(f, &st) == 0 && S_ISDIR(st.st_mode)) {
181 mp_tmsg(MSGT_OPEN,MSGL_ERR,"File is a directory: '%s'\n",filename);
182 close(f);
183 m_struct_free(&stream_opts,opts);
184 return STREAM_ERROR;
186 #endif
189 len=lseek(f,0,SEEK_END); lseek(f,0,SEEK_SET);
190 #ifdef __MINGW32__
191 // seeks on stdin incorrectly succeed on MinGW
192 if(f==0)
193 len = -1;
194 #endif
195 if(len == -1) {
196 if(mode == STREAM_READ) stream->seek = seek_forward;
197 stream->type = STREAMTYPE_STREAM; // Must be move to STREAMTYPE_FILE
198 stream->flags |= MP_STREAM_SEEK_FW;
199 } else if(len >= 0) {
200 stream->seek = seek;
201 stream->end_pos = len;
202 stream->type = STREAMTYPE_FILE;
205 mp_msg(MSGT_OPEN,MSGL_V,"[file] File size is %"PRId64" bytes\n", (int64_t)len);
207 stream->fd = f;
208 stream->fill_buffer = fill_buffer;
209 stream->write_buffer = write_buffer;
210 stream->control = control;
211 stream->read_chunk = 64*1024;
213 m_struct_free(&stream_opts,opts);
214 return STREAM_OK;
217 const stream_info_t stream_info_file = {
218 "File",
219 "file",
220 "Albeu",
221 "based on the code from ??? (probably Arpi)",
222 open_f,
223 { "file", "", NULL },
224 &stream_opts,
225 1 // Urls are an option string