REF_DEBUG: Install refcounter.py to $(ASTDATADIR)/scripts
[asterisk/asterisk.git] / formats / format_h264.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 h264 data.
22  * \arg File name extension: h264
23  * \ingroup formats
24  * \arg See \ref AstVideo
25  */
26
27 /*** MODULEINFO
28         <support_level>core</support_level>
29  ***/
30  
31 #include "asterisk.h"
32
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34
35 #include "asterisk/mod_format.h"
36 #include "asterisk/module.h"
37 #include "asterisk/endian.h"
38 #include "asterisk/format_cache.h"
39
40 /* Some Ideas for this code came from makeh264e.c by Jeffrey Chilton */
41
42 /* Portions of the conversion code are by guido@sienanet.it */
43 /*! \todo Check this buf size estimate, it may be totally wrong for large frame video */
44
45 #define FRAME_ENDED     0x8000
46
47 #define BUF_SIZE        4096    /* Two Real h264 Frames */
48 struct h264_desc {
49         unsigned int lastts;
50 };
51
52 static int h264_open(struct ast_filestream *s)
53 {
54         unsigned int ts;
55         if (fread(&ts, 1, sizeof(ts), s->f) < sizeof(ts)) {
56                 ast_log(LOG_WARNING, "Empty file!\n");
57                 return -1;
58         }
59         return 0;
60 }
61
62 static struct ast_frame *h264_read(struct ast_filestream *s, int *whennext)
63 {
64         int res;
65         int mark = 0;
66         unsigned short len;
67         unsigned int ts;
68         struct h264_desc *fs = (struct h264_desc *)s->_private;
69
70         /* Send a frame from the file to the appropriate channel */
71         if ((res = fread(&len, 1, sizeof(len), s->f)) < 1)
72                 return NULL;
73         len = ntohs(len);
74         mark = (len & FRAME_ENDED) ? 1 : 0;
75         len &= 0x7fff;
76         if (len > BUF_SIZE) {
77                 ast_log(LOG_WARNING, "Length %d is too long\n", len);
78                 len = BUF_SIZE; /* XXX truncate */
79         }
80         AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, len);
81         if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
82                 if (res)
83                         ast_log(LOG_WARNING, "Short read (%d of %d) (%s)!\n", res, len, strerror(errno));
84                 return NULL;
85         }
86         s->fr.samples = fs->lastts;
87         s->fr.datalen = len;
88         s->fr.subclass.frame_ending = mark;
89         if ((res = fread(&ts, 1, sizeof(ts), s->f)) == sizeof(ts)) {
90                 fs->lastts = ntohl(ts);
91                 *whennext = fs->lastts * 4/45;
92         } else
93                 *whennext = 0;
94         return &s->fr;
95 }
96
97 static int h264_write(struct ast_filestream *s, struct ast_frame *f)
98 {
99         int res;
100         unsigned int ts;
101         unsigned short len;
102         int mark;
103
104         mark = f->subclass.frame_ending ? FRAME_ENDED : 0;
105         ts = htonl(f->samples);
106         if ((res = fwrite(&ts, 1, sizeof(ts), s->f)) != sizeof(ts)) {
107                 ast_log(LOG_WARNING, "Bad write (%d/4): %s\n", res, strerror(errno));
108                 return -1;
109         }
110         len = htons(f->datalen | mark);
111         if ((res = fwrite(&len, 1, sizeof(len), s->f)) != sizeof(len)) {
112                 ast_log(LOG_WARNING, "Bad write (%d/2): %s\n", res, strerror(errno));
113                 return -1;
114         }
115         if ((res = fwrite(f->data.ptr, 1, f->datalen, s->f)) != f->datalen) {
116                 ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
117                 return -1;
118         }
119         return 0;
120 }
121
122 static int h264_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
123 {
124         /* No way Jose */
125         return -1;
126 }
127
128 static int h264_trunc(struct ast_filestream *fs)
129 {
130         int fd;
131         off_t cur;
132
133         if ((fd = fileno(fs->f)) < 0) {
134                 ast_log(AST_LOG_WARNING, "Unable to determine file descriptor for h264 filestream %p: %s\n", fs, strerror(errno));
135                 return -1;
136         }
137         if ((cur = ftello(fs->f)) < 0) {
138                 ast_log(AST_LOG_WARNING, "Unable to determine current position in h264 filestream %p: %s\n", fs, strerror(errno));
139                 return -1;
140         }
141         /* Truncate file to current length */
142         return ftruncate(fd, cur);
143 }
144
145 static off_t h264_tell(struct ast_filestream *fs)
146 {
147         off_t offset = ftell(fs->f);
148         return offset; /* XXX totally bogus, needs fixing */
149 }
150
151 static struct ast_format_def h264_f = {
152         .name = "h264",
153         .exts = "h264",
154         .open = h264_open,
155         .write = h264_write,
156         .seek = h264_seek,
157         .trunc = h264_trunc,
158         .tell = h264_tell,
159         .read = h264_read,
160         .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
161         .desc_size = sizeof(struct h264_desc),
162 };
163
164 static int load_module(void)
165 {
166         h264_f.format = ast_format_h264;
167         if (ast_format_def_register(&h264_f))
168                 return AST_MODULE_LOAD_FAILURE;
169         return AST_MODULE_LOAD_SUCCESS;
170 }
171
172 static int unload_module(void)
173 {
174         return ast_format_def_unregister(h264_f.name);
175 }
176
177 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw H.264 data",
178         .support_level = AST_MODULE_SUPPORT_CORE,
179         .load = load_module,
180         .unload = unload_module,
181         .load_pri = AST_MODPRI_APP_DEPEND
182 );