]> git.vomp.tv Git - vompclient.git/blob - mediafile.cc
Vogel Media Player 2008-11-28
[vompclient.git] / mediafile.cc
1 /*
2     Copyright 2004-2005 Chris Tallon, Andreas Vogel
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP 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
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include "mediafile.h"
22 #include "media.h"
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <dirent.h>
26 #include <iostream>
27 #include "log.h"
28
29
30
31
32 MediaFile::MediaFile(ULONG pid){
33   providerid=pid;
34 }
35
36 MediaFile::~MediaFile(){
37   };
38
39
40
41 static struct mtype{
42    const char* extension;
43    ULONG type;
44    } mediatypes[]= {
45      {".mp3",MEDIA_TYPE_AUDIO},
46      {".MP3",MEDIA_TYPE_AUDIO},
47      {".jpg",MEDIA_TYPE_PICTURE},
48      {".JPG",MEDIA_TYPE_PICTURE},
49      {".jpeg",MEDIA_TYPE_PICTURE},
50      {".JPEG",MEDIA_TYPE_PICTURE},
51      {".mpg",MEDIA_TYPE_VIDEO},
52      {".MPG",MEDIA_TYPE_VIDEO}
53      };
54 //#define NUMTYPES (sizeof(mediatypes)/sizeof(mtype))
55 #define NUMTYPES 8
56
57 //helper from vdr tools.c
58 bool endswith(const char *s, const char *p)
59 {
60   const char *se = s + strlen(s) - 1;
61   const char *pe = p + strlen(p) - 1;
62   while (pe >= p) {
63         if (*pe-- != *se-- || (se < s && pe >= p))
64            return false;
65         }
66   return true;
67 }
68
69 MediaList* MediaFile::getRootList() {
70   //has to be implemented in the derived class
71   return NULL;
72 }
73
74 ULONG MediaFile::getMediaType(const char * filename) {
75  for (ULONG i=0;i<NUMTYPES;i++) {
76       if (endswith(filename,mediatypes[i].extension)) {
77         return mediatypes[i].type;
78         }
79      }
80  return MEDIA_TYPE_UNKNOWN;
81 }
82
83
84 Media * MediaFile::createMedia(const char * dirname, const char * filename, bool withURI) {
85   Media * rt=NULL;
86   char *buffer;
87   asprintf(&buffer, "%s/%s", dirname, filename);
88   struct stat st;
89   ULONG mtype=MEDIA_TYPE_UNKNOWN;
90   if (stat(buffer, &st) == 0) {
91     if (S_ISDIR(st.st_mode)) {
92        mtype=MEDIA_TYPE_DIR;
93     }
94     else {
95        mtype=getMediaType(filename);
96     }
97   }
98   //only consider entries we accept by type here
99   if (mtype != MEDIA_TYPE_UNKNOWN) {
100     rt =new Media();
101     rt->setMediaType(mtype);
102     rt->setFileName(filename);
103     rt->setTime(st.st_mtime);
104     Log::getInstance()->log("Media",Log::DEBUG,"created Media %s, type=%d",filename,mtype);
105     if (withURI) {
106       MediaURI u(providerid,buffer,NULL);
107       rt->setURI(&u);
108     }
109   }
110   free(buffer);
111   return rt;
112 }
113
114 MediaList* MediaFile::getMediaList(const MediaURI * parent){
115   ULONG mediaType=parent->getAllowedTypes();
116   Log::getInstance()->log("MediaFile::getMediaList",Log::DEBUG,"parent %s,types=0x%0lx",parent->getName(),mediaType);
117   MediaList *rt=NULL;
118   rt=new MediaList(parent);
119   const char *dirname=parent->getName();
120   //open the directory and read out the entries
121   DIR *d=opendir(dirname);
122   struct dirent *e;
123   union { // according to "The GNU C Library Reference Manual"
124     struct dirent d;
125     char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
126     } u;
127
128   while (d != NULL && (readdir_r(d,&u.d,&e) == 0) && e != NULL) {
129     const char * fname=e->d_name;
130     if ( fname == NULL) continue;
131     if (strcmp(fname,".") == 0) continue;
132     if (strcmp(fname,"..") == 0) continue;
133     Media *m=createMedia(dirname,fname);
134     if (m && ( m->getMediaType() & mediaType)) {
135       Log::getInstance()->log("Media",Log::DEBUG,"added entry %s, type=%d",fname,m->getMediaType());
136       rt->push_back(m);
137     }
138     else {
139       if (m) delete m;
140     }
141   }
142   if (d != NULL) closedir(d);
143   return rt;
144   }
145
146
147 int MediaFile::openMedium(ULONG channel, const MediaURI * uri, ULLONG * size, ULONG xsize, ULONG ysize) {
148   Log::getInstance()->log("Media::openMedium",Log::DEBUG,"fn=%s,chan=%u",uri->getName(),channel);
149   *size=0;
150   if (channel <0 || channel >= NUMCHANNELS) return -1;
151   struct ChannelInfo *info=&channels[channel];
152   if (info->file) info->reset();
153   FILE *fp=fopen(uri->getName(),"r");
154   if (! fp) {
155     Log::getInstance()->log("Media::openMedium",Log::ERR,"unable to open file fn=%s,chan=%u",uri->getName(),channel);
156     return -1;
157   }
158   struct stat st;
159   ULLONG mysize=0;
160   if ( fstat(fileno(fp),&st) == 0) mysize=st.st_size;
161   if (mysize == 0) {
162     Log::getInstance()->log("Media::openMedium",Log::ERR,"unable to open file fn=%s,chan=%u",uri->getName(),channel);
163     fclose(fp);
164     return -1;
165   }
166   info->setFilename(uri->getName());
167   info->file=fp;
168   info->size=mysize;
169   *size=mysize;
170   info->provider=providerid;
171   return 0;
172 }
173
174
175 int MediaFile::getMediaBlock(ULONG channel, ULLONG offset, ULONG len, ULONG * outlen,
176         unsigned char ** buffer) {
177   Log::getInstance()->log("Media::getMediaBlock",Log::DEBUG,"chan=%u,offset=%llu,len=%lu",channel,offset,len);
178   *outlen=0;
179   if (channel <0 || channel >= NUMCHANNELS) return -1;
180   struct ChannelInfo *info=&channels[channel];
181   if (! info->file) {
182     Log::getInstance()->log("Media::getMediaBlock",Log::ERR,"not open chan=%u",channel);
183     return -1;
184   }
185   ULLONG cpos=ftell(info->file);
186   if (offset != cpos) {
187     fseek(info->file,offset-cpos,SEEK_CUR);
188   }
189   if (offset != (ULLONG)ftell(info->file)) {
190     Log::getInstance()->log("Client", Log::DEBUG, "getMediaBlock pos = %llu not available", offset);
191     return -1;
192   }
193   if (*buffer == NULL) *buffer=(UCHAR *)malloc(len);
194   if (*buffer == NULL) {
195     Log::getInstance()->log("Media::getMediaBlock",Log::ERR,"uanble to allocate buffer");
196     return -1;
197   }
198   ULONG amount=fread(*buffer,1,len,info->file);
199   Log::getInstance()->log("Media::getMediaBlock",Log::DEBUG,"readlen=%lu",amount);
200   *outlen=amount;
201   return 0;
202 }
203
204
205 int MediaFile::closeMediaChannel(ULONG channel){
206   Log::getInstance()->log("Media::closeMediaChannel",Log::DEBUG,"chan=%u",channel);
207   if (channel <0 || channel >= NUMCHANNELS) return -1;
208   struct ChannelInfo *info=&channels[channel];
209   info->reset();
210   return 0;
211 }
212
213 //TODO: fill in more info
214 int MediaFile::getMediaInfo(ULONG channel, MediaInfo * result){
215   Log::getInstance()->log("Media::getMediaInfo",Log::DEBUG,"chan=%u",channel);
216   if (channel <0 || channel >= NUMCHANNELS) return -1;
217   struct ChannelInfo *info=&channels[channel];
218   if (! info->file) return -1;
219   result->size=info->size;
220   result->canPosition=true;
221   return 0;
222 }