1 /*
2 * tvheadend, generic muxing utils
3 * Copyright (C) 2012 John Törnblom
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <htmlui://www.gnu.org/licenses/>.
17 */
18
19 #include <string.h>
20 #include <fcntl.h>
21
22 #include "tvheadend.h"
23 #include "service.h"
24 #include "muxer.h"
25 #include "muxer/muxer_mkv.h"
26 #include "muxer/muxer_pass.h"
27 #include "muxer/muxer_audioes.h"
28 #if CONFIG_LIBAV
29 #include "muxer/muxer_libav.h"
30 #endif
31
32 /* Newer platforms such as FreeBSD 11.1 support fdatasync so only alias on older systems */
33 #ifndef CONFIG_FDATASYNC
34 #if defined(PLATFORM_DARWIN)
35 #define fdatasync(fd) fcntl(fd, F_FULLFSYNC)
36 #elif defined(PLATFORM_FREEBSD)
37 #define fdatasync(fd) fsync(fd)
38 #endif
39 #endif
40
41 /**
42 * Mime type for containers containing only audio
43 */
44 static struct strtab container_audio_mime[] = {
45 { "application/octet-stream", MC_UNKNOWN },
46 { "audio/x-matroska", MC_MATROSKA },
47 { "audio/x-matroska", MC_AVMATROSKA },
48 { "audio/webm", MC_WEBM },
49 { "audio/webm", MC_AVWEBM },
50 { "audio/mp2t", MC_MPEGTS },
51 { "audio/mpeg", MC_MPEGPS },
52 { "audio/mpeg", MC_MPEG2AUDIO },
53 { "audio/ac3", MC_AC3 },
54 { "audio/aac", MC_AAC },
55 { "audio/mp4", MC_MP4A },
56 { "audio/ogg", MC_VORBIS },
57 { "audio/mp4", MC_AVMP4 },
58 { "application/octet-stream", MC_PASS },
59 { "application/octet-stream", MC_RAW },
60 };
61
62
63 /**
64 * Mime type for containers
65 */
66 static struct strtab container_video_mime[] = {
67 { "application/octet-stream", MC_UNKNOWN },
68 { "video/x-matroska", MC_MATROSKA },
69 { "video/x-matroska", MC_AVMATROSKA },
70 { "video/webm", MC_WEBM },
71 { "video/webm", MC_AVWEBM },
72 { "video/mp2t", MC_MPEGTS },
73 { "video/mpeg", MC_MPEGPS },
74 { "video/mp4", MC_AVMP4 },
75 { "application/octet-stream", MC_PASS },
76 { "application/octet-stream", MC_RAW },
77 };
78
79
80 /**
81 * Name of the container
82 */
83 static struct strtab container_name[] = {
84 { "unknown", MC_UNKNOWN },
85 { "matroska", MC_MATROSKA },
86 { "webm", MC_WEBM },
87 { "mpegts", MC_MPEGTS },
88 { "mpegps", MC_MPEGPS },
89 { "pass", MC_PASS },
90 { "raw", MC_RAW },
91 { "avmatroska", MC_AVMATROSKA },
92 { "avwebm", MC_AVWEBM },
93 { "avmp4", MC_AVMP4 },
94 { "mp2", MC_MPEG2AUDIO },
95 { "ac3", MC_AC3 },
96 { "aac", MC_AAC },
97 { "mp4a", MC_MP4A },
98 { "oga", MC_VORBIS },
99 };
100
101
102 /**
103 * filename suffix of audio-only streams
104 */
105 static struct strtab container_audio_file_suffix[] = {
106 { "bin", MC_UNKNOWN },
107 { "mka", MC_MATROSKA },
108 { "webm", MC_WEBM },
109 { "ts", MC_MPEGTS },
110 { "mpeg", MC_MPEGPS },
111 { "bin", MC_PASS },
112 { "bin", MC_RAW },
113 { "mka", MC_AVMATROSKA },
114 { "webm", MC_AVWEBM },
115 { "mp4", MC_AVMP4 },
116 { "mp2", MC_MPEG2AUDIO },
117 { "ac3", MC_AC3 },
118 { "aac", MC_AAC },
119 { "mp4a", MC_MP4A },
120 { "oga", MC_VORBIS },
121 };
122
123
124 /**
125 * filename suffix of video streams
126 */
127 static struct strtab container_video_file_suffix[] = {
128 { "bin", MC_UNKNOWN },
129 { "mkv", MC_MATROSKA },
130 { "webm", MC_WEBM },
131 { "ts", MC_MPEGTS },
132 { "mpeg", MC_MPEGPS },
133 { "bin", MC_PASS },
134 { "bin", MC_RAW },
135 { "mkv", MC_AVMATROSKA },
136 { "webm", MC_AVWEBM },
137 { "mp4", MC_AVMP4 },
138 };
139
140
141 /**
142 * Get the mime type for a container
143 */
144 const char*
muxer_container_type2mime(muxer_container_type_t mc,int video)145 muxer_container_type2mime(muxer_container_type_t mc, int video)
146 {
147 const char *str;
148
149 if(video)
150 str = val2str(mc, container_video_mime);
151 else
152 str = val2str(mc, container_audio_mime);
153
154 if(!str)
155 str = val2str(MC_UNKNOWN, container_video_mime);
156
157 return str;
158 }
159
160
161 /**
162 * Get the mime type for a filename
163 */
164 const char*
muxer_container_filename2mime(const char * filename,int video)165 muxer_container_filename2mime(const char *filename, int video)
166 {
167 int mc = MC_UNKNOWN;
168 const char *suffix;
169
170 if(filename) {
171 suffix = strrchr(filename, '.');
172 if (suffix == NULL)
173 suffix = filename;
174 else
175 suffix++;
176 if(video)
177 mc = str2val(suffix, container_video_file_suffix);
178 else
179 mc = str2val(suffix, container_audio_file_suffix);
180 }
181
182 return muxer_container_type2mime(mc, 1);
183 }
184
185
186 /**
187 * Get the suffix used in file names
188 */
189 const char*
muxer_container_suffix(muxer_container_type_t mc,int video)190 muxer_container_suffix(muxer_container_type_t mc, int video)
191 {
192 const char *str;
193 if(video)
194 str = val2str(mc, container_video_file_suffix);
195 else
196 str = val2str(mc, container_audio_file_suffix);
197
198 if(!str)
199 str = val2str(MC_UNKNOWN, container_video_file_suffix);
200
201 return str;
202 }
203
204
205 /**
206 * Convert a container type to a string
207 */
208 const char*
muxer_container_type2txt(muxer_container_type_t mc)209 muxer_container_type2txt(muxer_container_type_t mc)
210 {
211 const char *str;
212
213 str = val2str(mc, container_name);
214 if(!str)
215 return "unknown";
216
217 return str;
218 }
219
220
221 /**
222 * Convert a container name to a container type
223 */
224 muxer_container_type_t
muxer_container_txt2type(const char * str)225 muxer_container_txt2type(const char *str)
226 {
227 muxer_container_type_t mc;
228
229 if(!str)
230 return MC_UNKNOWN;
231
232 mc = str2val(str, container_name);
233 if(mc == -1)
234 return MC_UNKNOWN;
235
236 return mc;
237 }
238
239
240 /**
241 * Convert a mime-string to a container type
242 */
243 muxer_container_type_t
muxer_container_mime2type(const char * str)244 muxer_container_mime2type(const char *str)
245 {
246 muxer_container_type_t mc;
247
248 if(!str)
249 return MC_UNKNOWN;
250
251 mc = str2val(str, container_video_mime);
252 if(mc == -1)
253 mc = str2val(str, container_audio_mime);
254
255 if(mc == -1)
256 return MC_UNKNOWN;
257
258 return mc;
259 }
260
261
262 /**
263 * Create a new muxer
264 */
265 muxer_t*
muxer_create(const muxer_config_t * m_cfg)266 muxer_create(const muxer_config_t *m_cfg)
267 {
268 muxer_t *m;
269
270 assert(m_cfg);
271
272 m = pass_muxer_create(m_cfg);
273
274 if(!m)
275 m = mkv_muxer_create(m_cfg);
276
277 if(!m)
278 m = audioes_muxer_create(m_cfg);
279
280 #if CONFIG_LIBAV
281 if(!m)
282 m = lav_muxer_create(m_cfg);
283 #endif
284
285 if(!m) {
286 tvherror(LS_MUXER, "Can't find a muxer that supports '%s' container",
287 muxer_container_type2txt(m_cfg->m_type));
288 return NULL;
289 }
290
291 memcpy(&m->m_config, m_cfg, sizeof(muxer_config_t));
292
293 return m;
294 }
295
296 /**
297 * Figure out the file suffix by looking at the mime type
298 */
299 const char*
muxer_suffix(muxer_t * m,const struct streaming_start * ss)300 muxer_suffix(muxer_t *m, const struct streaming_start *ss)
301 {
302 const char *mime;
303 muxer_container_type_t mc;
304 int video;
305
306 if(!m || !ss)
307 return NULL;
308
309 mime = m->m_mime(m, ss);
310 video = memcmp("audio", mime, 5);
311 mc = muxer_container_mime2type(mime);
312
313 return muxer_container_suffix(mc, video);
314 }
315
316 /**
317 * cache type conversions
318 */
319 static struct strtab cache_types[] = {
320 { "Unknown", MC_CACHE_UNKNOWN },
321 { "System", MC_CACHE_SYSTEM },
322 { "Do not keep", MC_CACHE_DONTKEEP },
323 { "Sync", MC_CACHE_SYNC },
324 { "Sync + Do not keep", MC_CACHE_SYNCDONTKEEP }
325 };
326
327 const char*
muxer_cache_type2txt(muxer_cache_type_t c)328 muxer_cache_type2txt(muxer_cache_type_t c)
329 {
330 return val2str(c, cache_types);
331 }
332
333 muxer_cache_type_t
muxer_cache_txt2type(const char * str)334 muxer_cache_txt2type(const char *str)
335 {
336 int r = str2val(str, cache_types);
337 if (r < 0)
338 r = MC_CACHE_UNKNOWN;
339 return r;
340 }
341
342 /**
343 * cache scheme
344 */
345 void
muxer_cache_update(muxer_t * m,int fd,off_t pos,size_t size)346 muxer_cache_update(muxer_t *m, int fd, off_t pos, size_t size)
347 {
348 switch (m->m_config.m_cache) {
349 case MC_CACHE_UNKNOWN:
350 case MC_CACHE_SYSTEM:
351 break;
352 case MC_CACHE_SYNC:
353 fdatasync(fd);
354 break;
355 case MC_CACHE_SYNCDONTKEEP:
356 fdatasync(fd);
357 /* fall through */
358 case MC_CACHE_DONTKEEP:
359 #if defined(PLATFORM_DARWIN)
360 fcntl(fd, F_NOCACHE, 1);
361 #elif !ENABLE_ANDROID
362 posix_fadvise(fd, pos, size, POSIX_FADV_DONTNEED);
363 #endif
364 break;
365 default:
366 abort();
367 }
368 }
369
370 /**
371 * Get a list of supported cache schemes
372 */
373 int
muxer_cache_list(htsmsg_t * array)374 muxer_cache_list(htsmsg_t *array)
375 {
376 htsmsg_t *mc;
377 int c;
378 const char *s;
379
380 for (c = 0; c <= MC_CACHE_LAST; c++) {
381 mc = htsmsg_create_map();
382 s = muxer_cache_type2txt(c);
383 htsmsg_add_u32(mc, "index", c);
384 htsmsg_add_str(mc, "description", s);
385 htsmsg_add_msg(array, NULL, mc);
386 }
387
388 return c;
389 }
390