Asterisk - The Open Source Telephony Project  21.4.1
asterisk-opus-a959f072d3f364be983dd27e6e250b038aaef747/formats/format_vp8.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2014, Lorenzo Miniero
5  *
6  * Lorenzo Miniero <lorenzo@meetecho.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 VP8 data.
22  *
23  * \author Lorenzo Miniero <lorenzo@meetecho.com>
24  *
25  * \note Basically a "clone" of the H.264 passthrough format
26  *
27  * \arg File name extension: VP8
28  * \ingroup formats
29  * \arg See \ref AstVideo
30  */
31 
32 /*** MODULEINFO
33  <support_level>core</support_level>
34 ***/
35 
36 #include "asterisk.h"
37 
38 #if defined(ASTERISK_REGISTER_FILE)
39 ASTERISK_REGISTER_FILE()
40 #elif defined(ASTERISK_FILE_VERSION)
41 ASTERISK_FILE_VERSION(__FILE__, "$Revision: $")
42 #endif
43 
44 #include <netinet/in.h> /* for htonl, htons, ntohl, ntohs */
45 #include <sys/time.h> /* for timeval = ast_filestream->ast_frame.delivery */
46 
47 #include "asterisk/format_cache.h" /* for ast_format_vp8 */
48 #include "asterisk/frame.h" /* for ast_frame, AST_FRIENDLY_OFFSET */
49 #include "asterisk/logger.h" /* for ast_log, LOG_WARNING */
50 #include "asterisk/mod_format.h" /* for ast_filestream, ast_format_def */
51 #include "asterisk/module.h"
52 
53 /* VP8 passthrough */
54 #define FRAME_ENDED 0x8000
55 
56 #define BUF_SIZE 4096
57 struct vp8_desc {
58  unsigned int lastts;
59 };
60 
61 static int vp8_open(struct ast_filestream *s)
62 {
63  unsigned int ts;
64 
65  if (fread(&ts, 1, sizeof(ts), s->f) < sizeof(ts)) {
66  ast_log(LOG_WARNING, "Empty file!\n");
67  return -1;
68  }
69 
70  return 0;
71 }
72 
73 static struct ast_frame *vp8_read(struct ast_filestream *s, int *whennext)
74 {
75  int res;
76  int mark = 0;
77  unsigned short len;
78  unsigned int ts;
79  struct vp8_desc *fs = (struct vp8_desc *) s->_private;
80 
81  /* Send a frame from the file to the appropriate channel */
82  if ((res = fread(&len, 1, sizeof(len), s->f)) < 1) {
83  return NULL;
84  }
85 
86  len = ntohs(len);
87  mark = (len & FRAME_ENDED) ? 1 : 0;
88  len &= 0x7fff;
89  if (len > BUF_SIZE) {
90  ast_log(LOG_WARNING, "Length %d is too long\n", len);
91  len = BUF_SIZE; /* XXX truncate */
92  }
93  s->fr.mallocd = 0;
95  if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
96  if (res) {
97  ast_log(LOG_WARNING, "Short read (%d of %d) (%s)!\n", res, len, strerror(errno));
98  }
99  return NULL;
100  }
101  s->fr.samples = fs->lastts;
102  s->fr.datalen = len;
103  s->fr.subclass.frame_ending = mark;
104  s->fr.delivery.tv_sec = 0;
105  s->fr.delivery.tv_usec = 0;
106  if ((res = fread(&ts, 1, sizeof(ts), s->f)) == sizeof(ts)) {
107  fs->lastts = ntohl(ts);
108  *whennext = fs->lastts * 4 / 45;
109  } else {
110  *whennext = 0;
111  }
112  return &s->fr;
113 }
114 
115 static int vp8_write(struct ast_filestream *s, struct ast_frame *f)
116 {
117  int res;
118  unsigned int ts;
119  unsigned short len;
120  int mark;
121 
122  if (f->frametype != AST_FRAME_VIDEO) {
123  ast_log(LOG_WARNING, "Asked to write non-video frame!\n");
124  return -1;
125  }
126 
127  mark = f->subclass.frame_ending ? FRAME_ENDED : 0;
128  ts = htonl(f->samples);
129  if ((res = fwrite(&ts, 1, sizeof(ts), s->f)) != sizeof(ts)) {
130  ast_log(LOG_WARNING, "Bad write (%d/4): %s\n", res, strerror(errno));
131  return -1;
132  }
133 
134  len = htons(f->datalen | mark);
135  if ((res = fwrite(&len, 1, sizeof(len), s->f)) != sizeof(len)) {
136  ast_log(LOG_WARNING, "Bad write (%d/2): %s\n", res, strerror(errno));
137  return -1;
138  }
139 
140  if ((res = fwrite(f->data.ptr, 1, f->datalen, s->f)) != f->datalen) {
141  ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
142  return -1;
143  }
144 
145  return 0;
146 }
147 
148 static int vp8_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
149 {
150  /* No way Jose */
151  return -1;
152 }
153 
154 static int vp8_trunc(struct ast_filestream *fs)
155 {
156  int fd;
157  off_t cur;
158 
159  if ((fd = fileno(fs->f)) < 0) {
160  ast_log(LOG_WARNING, "Unable to determine file descriptor for VP8 filestream %p: %s\n", fs, strerror(errno));
161  return -1;
162  }
163 
164  if ((cur = ftello(fs->f)) < 0) {
165  ast_log(LOG_WARNING, "Unable to determine current position in VP8 filestream %p: %s\n", fs, strerror(errno));
166  return -1;
167  }
168 
169  /* Truncate file to current length */
170  return ftruncate(fd, cur);
171 }
172 
173 static off_t vp8_tell(struct ast_filestream *fs)
174 {
175  off_t offset = ftell(fs->f);
176  return offset; /* XXX totally bogus, needs fixing */
177 }
178 
179 static struct ast_format_def vp8_f = {
180  .name = "VP8",
181  .exts = "vp8",
182  .open = vp8_open,
183  .write = vp8_write,
184  .seek = vp8_seek,
185  .trunc = vp8_trunc,
186  .tell = vp8_tell,
187  .read = vp8_read,
188  .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
189  .desc_size = sizeof(struct vp8_desc),
190 };
191 
192 static int load_module(void)
193 {
194  vp8_f.format = ast_format_vp8;
195  if (ast_format_def_register(&vp8_f)) {
197  }
198 
200 }
201 
202 static int unload_module(void)
203 {
204  return ast_format_def_unregister(vp8_f.name);
205 }
206 
207 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw VP8 data",
208  .load = load_module,
209  .unload = unload_module,
210  .load_pri = AST_MODPRI_APP_DEPEND
211  );
struct ast_format * ast_format_vp8
Built-in cached vp8 format.
Definition: format_cache.c:191
Asterisk main include file. File version handling, generic pbx functions.
Each supported file format is described by the following structure.
Definition: mod_format.h:43
struct ast_frame_subclass subclass
Header for providers of file and format handling routines. Clients of these routines should include "...
int ast_format_def_unregister(const char *name)
Unregisters a file format.
Definition: file.c:162
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
Asterisk internal frame definitions.
struct ast_frame fr
frame produced by read, typically
Definition: mod_format.h:122
#define FRAME_ENDED
Definition: format_h264.c:43
struct ast_format * format
Definition: mod_format.h:48
void * _private
Definition: mod_format.h:124
#define AST_FRAME_SET_BUFFER(fr, _base, _ofs, _datalen)
char name[80]
Definition: mod_format.h:44
union ast_frame::@224 data
Module could not be loaded properly.
Definition: module.h:102
Support for logging to various files, console and syslog Configuration in file logger.conf.
struct timeval delivery
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition: mod_format.h:101
Data structure associated with a single frame of data.
enum ast_frame_type frametype
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
Media Format Cache API.