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