update MANY more files with proper copyright/license info (thanks Ian!)
[asterisk/asterisk.git] / formats / format_h263.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*
20  *
21  * Save to raw, headerless h263 data.
22  * 
23  */
24  
25 #include <unistd.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <stdlib.h>
29 #include <sys/time.h>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <string.h>
33
34 #include "asterisk.h"
35
36 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37
38 #include "asterisk/lock.h"
39 #include "asterisk/channel.h"
40 #include "asterisk/file.h"
41 #include "asterisk/logger.h"
42 #include "asterisk/sched.h"
43 #include "asterisk/module.h"
44 #include "asterisk/endian.h"
45
46 /* Some Ideas for this code came from makeh263e.c by Jeffrey Chilton */
47
48 /* Portions of the conversion code are by guido@sienanet.it */
49
50 struct ast_filestream {
51         void *reserved[AST_RESERVED_POINTERS];
52         /* Believe it or not, we must decode/recode to account for the
53            weird MS format */
54         /* This is what a filestream means to us */
55         int fd; /* Descriptor */
56         unsigned int lastts;
57         struct ast_frame fr;                            /* Frame information */
58         char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
59         char empty;                                                     /* Empty character */
60         unsigned char h263[4096];                               /* Two Real h263 Frames */
61 };
62
63
64 AST_MUTEX_DEFINE_STATIC(h263_lock);
65 static int glistcnt = 0;
66
67 static char *name = "h263";
68 static char *desc = "Raw h263 data";
69 static char *exts = "h263";
70
71 static struct ast_filestream *h263_open(int fd)
72 {
73         /* We don't have any header to read or anything really, but
74            if we did, it would go here.  We also might want to check
75            and be sure it's a valid file.  */
76         struct ast_filestream *tmp;
77         unsigned int ts;
78         int res;
79         if ((res = read(fd, &ts, sizeof(ts))) < sizeof(ts)) {
80                 ast_log(LOG_WARNING, "Empty file!\n");
81                 return NULL;
82         }
83                 
84         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
85                 memset(tmp, 0, sizeof(struct ast_filestream));
86                 if (ast_mutex_lock(&h263_lock)) {
87                         ast_log(LOG_WARNING, "Unable to lock h263 list\n");
88                         free(tmp);
89                         return NULL;
90                 }
91                 tmp->fd = fd;
92                 tmp->fr.data = tmp->h263;
93                 tmp->fr.frametype = AST_FRAME_VIDEO;
94                 tmp->fr.subclass = AST_FORMAT_H263;
95                 /* datalen will vary for each frame */
96                 tmp->fr.src = name;
97                 tmp->fr.mallocd = 0;
98                 glistcnt++;
99                 ast_mutex_unlock(&h263_lock);
100                 ast_update_use_count();
101         }
102         return tmp;
103 }
104
105 static struct ast_filestream *h263_rewrite(int fd, const char *comment)
106 {
107         /* We don't have any header to read or anything really, but
108            if we did, it would go here.  We also might want to check
109            and be sure it's a valid file.  */
110         struct ast_filestream *tmp;
111         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
112                 memset(tmp, 0, sizeof(struct ast_filestream));
113                 if (ast_mutex_lock(&h263_lock)) {
114                         ast_log(LOG_WARNING, "Unable to lock h263 list\n");
115                         free(tmp);
116                         return NULL;
117                 }
118                 tmp->fd = fd;
119                 glistcnt++;
120                 ast_mutex_unlock(&h263_lock);
121                 ast_update_use_count();
122         } else
123                 ast_log(LOG_WARNING, "Out of memory\n");
124         return tmp;
125 }
126
127 static void h263_close(struct ast_filestream *s)
128 {
129         if (ast_mutex_lock(&h263_lock)) {
130                 ast_log(LOG_WARNING, "Unable to lock h263 list\n");
131                 return;
132         }
133         glistcnt--;
134         ast_mutex_unlock(&h263_lock);
135         ast_update_use_count();
136         close(s->fd);
137         free(s);
138         s = NULL;
139 }
140
141 static struct ast_frame *h263_read(struct ast_filestream *s, int *whennext)
142 {
143         int res;
144         int mark=0;
145         unsigned short len;
146         unsigned int ts;
147         /* Send a frame from the file to the appropriate channel */
148         s->fr.frametype = AST_FRAME_VIDEO;
149         s->fr.subclass = AST_FORMAT_H263;
150         s->fr.offset = AST_FRIENDLY_OFFSET;
151         s->fr.mallocd = 0;
152         s->fr.data = s->h263;
153         if ((res = read(s->fd, &len, sizeof(len))) < 1) {
154                 return NULL;
155         }
156         len = ntohs(len);
157         if (len & 0x8000) {
158                 mark = 1;
159         }
160         len &= 0x7fff;
161         if (len > sizeof(s->h263)) {
162                 ast_log(LOG_WARNING, "Length %d is too long\n", len);
163         }
164         if ((res = read(s->fd, s->h263, len)) != len) {
165                 if (res)
166                         ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
167                 return NULL;
168         }
169         s->fr.samples = s->lastts;
170         s->fr.datalen = len;
171         s->fr.subclass |= mark;
172         s->fr.delivery.tv_sec = 0;
173         s->fr.delivery.tv_usec = 0;
174         if ((res = read(s->fd, &ts, sizeof(ts))) == sizeof(ts)) {
175                 s->lastts = ntohl(ts);
176                 *whennext = s->lastts * 4/45;
177         } else
178                 *whennext = 0;
179         return &s->fr;
180 }
181
182 static int h263_write(struct ast_filestream *fs, struct ast_frame *f)
183 {
184         int res;
185         unsigned int ts;
186         unsigned short len;
187         int subclass;
188         int mark=0;
189         if (f->frametype != AST_FRAME_VIDEO) {
190                 ast_log(LOG_WARNING, "Asked to write non-video frame!\n");
191                 return -1;
192         }
193         subclass = f->subclass;
194         if (subclass & 0x1)
195                 mark=0x8000;
196         subclass &= ~0x1;
197         if (subclass != AST_FORMAT_H263) {
198                 ast_log(LOG_WARNING, "Asked to write non-h263 frame (%d)!\n", f->subclass);
199                 return -1;
200         }
201         ts = htonl(f->samples);
202         if ((res = write(fs->fd, &ts, sizeof(ts))) != sizeof(ts)) {
203                         ast_log(LOG_WARNING, "Bad write (%d/4): %s\n", res, strerror(errno));
204                         return -1;
205         }
206         len = htons(f->datalen | mark);
207         if ((res = write(fs->fd, &len, sizeof(len))) != sizeof(len)) {
208                         ast_log(LOG_WARNING, "Bad write (%d/2): %s\n", res, strerror(errno));
209                         return -1;
210         }
211         if ((res = write(fs->fd, f->data, f->datalen)) != f->datalen) {
212                         ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
213                         return -1;
214         }
215         return 0;
216 }
217
218 static char *h263_getcomment(struct ast_filestream *s)
219 {
220         return NULL;
221 }
222
223 static int h263_seek(struct ast_filestream *fs, long sample_offset, int whence)
224 {
225         /* No way Jose */
226         return -1;
227 }
228
229 static int h263_trunc(struct ast_filestream *fs)
230 {
231         /* Truncate file to current length */
232         if (ftruncate(fs->fd, lseek(fs->fd, 0, SEEK_CUR)) < 0)
233                 return -1;
234         return 0;
235 }
236
237 static long h263_tell(struct ast_filestream *fs)
238 {
239         off_t offset;
240         offset = lseek(fs->fd, 0, SEEK_CUR);
241         return (offset/20)*160;
242 }
243
244 int load_module()
245 {
246         return ast_format_register(name, exts, AST_FORMAT_H263,
247                                                                 h263_open,
248                                                                 h263_rewrite,
249                                                                 h263_write,
250                                                                 h263_seek,
251                                                                 h263_trunc,
252                                                                 h263_tell,
253                                                                 h263_read,
254                                                                 h263_close,
255                                                                 h263_getcomment);
256                                                                 
257                                                                 
258 }
259
260 int unload_module()
261 {
262         return ast_format_unregister(name);
263 }       
264
265 int usecount()
266 {
267         return glistcnt;
268 }
269
270 char *description()
271 {
272         return desc;
273 }
274
275
276 char *key()
277 {
278         return ASTERISK_GPL_KEY;
279 }