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