16
|
1 |
/* Quicktime muxer plugin for GStreamer
|
|
2 |
* Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
|
|
3 |
* Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
|
|
4 |
*
|
|
5 |
* This library is free software; you can redistribute it and/or
|
|
6 |
* modify it under the terms of the GNU Library General Public
|
|
7 |
* License as published by the Free Software Foundation; either
|
|
8 |
* version 2 of the License, or (at your option) any later version.
|
|
9 |
*
|
|
10 |
* This library 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 GNU
|
|
13 |
* Library General Public License for more details.
|
|
14 |
*
|
|
15 |
* You should have received a copy of the GNU Library General Public
|
|
16 |
* License along with this library; if not, write to the
|
|
17 |
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
18 |
* Boston, MA 02111-1307, USA.
|
|
19 |
*/
|
|
20 |
/*
|
|
21 |
* Unless otherwise indicated, Source Code is licensed under MIT license.
|
|
22 |
* See further explanation attached in License Statement (distributed in the file
|
|
23 |
* LICENSE).
|
|
24 |
*
|
|
25 |
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
26 |
* this software and associated documentation files (the "Software"), to deal in
|
|
27 |
* the Software without restriction, including without limitation the rights to
|
|
28 |
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
29 |
* of the Software, and to permit persons to whom the Software is furnished to do
|
|
30 |
* so, subject to the following conditions:
|
|
31 |
*
|
|
32 |
* The above copyright notice and this permission notice shall be included in all
|
|
33 |
* copies or substantial portions of the Software.
|
|
34 |
*
|
|
35 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
36 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
37 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
38 |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
39 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
40 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
41 |
* SOFTWARE.
|
|
42 |
*/
|
|
43 |
|
|
44 |
#include "gstqtmuxmap.h"
|
|
45 |
#include "fourcc.h"
|
|
46 |
#include "ftypcc.h"
|
|
47 |
|
|
48 |
/* static info related to various format */
|
|
49 |
|
|
50 |
#define COMMON_VIDEO_CAPS \
|
|
51 |
"width = (int) [ 16, 4096 ], " \
|
|
52 |
"height = (int) [ 16, 4096 ], " \
|
|
53 |
"framerate = (fraction) [ 0, MAX ]"
|
|
54 |
|
|
55 |
#define COMMON_VIDEO_CAPS_NO_FRAMERATE \
|
|
56 |
"width = (int) [ 16, 4096 ], " \
|
|
57 |
"height = (int) [ 16, 4096 ] "
|
|
58 |
|
|
59 |
#define H263_CAPS \
|
|
60 |
"video/x-h263, " \
|
|
61 |
COMMON_VIDEO_CAPS
|
|
62 |
|
|
63 |
#define H264_CAPS \
|
|
64 |
"video/x-h264, " \
|
|
65 |
COMMON_VIDEO_CAPS
|
|
66 |
|
|
67 |
#define MPEG4V_CAPS \
|
|
68 |
"video/mpeg, " \
|
|
69 |
"mpegversion = (int) 4, "\
|
|
70 |
"systemstream = (boolean) false, " \
|
|
71 |
COMMON_VIDEO_CAPS "; " \
|
|
72 |
"video/x-divx, " \
|
|
73 |
"divxversion = (int) 5, "\
|
|
74 |
COMMON_VIDEO_CAPS
|
|
75 |
|
|
76 |
#define COMMON_AUDIO_CAPS(c, r) \
|
|
77 |
"channels = (int) [ 1, " G_STRINGIFY (c) " ], " \
|
|
78 |
"rate = (int) [ 1, " G_STRINGIFY (r) " ]"
|
|
79 |
|
|
80 |
#define PCM_CAPS \
|
|
81 |
"audio/x-raw-int, " \
|
|
82 |
"width = (int) 8, " \
|
|
83 |
"depth = (int) 8, " \
|
|
84 |
COMMON_AUDIO_CAPS (2, MAX) ", " \
|
|
85 |
"signed = (boolean) { true, false }; " \
|
|
86 |
"audio/x-raw-int, " \
|
|
87 |
"width = (int) 16, " \
|
|
88 |
"depth = (int) 16, " \
|
|
89 |
"endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, " \
|
|
90 |
COMMON_AUDIO_CAPS (2, MAX) ", " \
|
|
91 |
"signed = (boolean) true " \
|
|
92 |
|
|
93 |
#define PCM_CAPS_FULL \
|
|
94 |
PCM_CAPS "; " \
|
|
95 |
"audio/x-raw-int, " \
|
|
96 |
"width = (int) 24, " \
|
|
97 |
"depth = (int) 24, " \
|
|
98 |
"endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, " \
|
|
99 |
COMMON_AUDIO_CAPS (2, MAX) ", " \
|
|
100 |
"signed = (boolean) true; " \
|
|
101 |
"audio/x-raw-int, " \
|
|
102 |
"width = (int) 32, " \
|
|
103 |
"depth = (int) 32, " \
|
|
104 |
"endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, " \
|
|
105 |
COMMON_AUDIO_CAPS (2, MAX) ", " \
|
|
106 |
"signed = (boolean) true "
|
|
107 |
|
|
108 |
#define MP3_CAPS \
|
|
109 |
"audio/mpeg, " \
|
|
110 |
"mpegversion = (int) 1, " \
|
|
111 |
"layer = (int) 3, " \
|
|
112 |
COMMON_AUDIO_CAPS (2, MAX)
|
|
113 |
|
|
114 |
#define AAC_CAPS \
|
|
115 |
"audio/mpeg, " \
|
|
116 |
"mpegversion = (int) 4, " \
|
|
117 |
COMMON_AUDIO_CAPS (8, MAX)
|
|
118 |
|
|
119 |
#define AMR_CAPS \
|
|
120 |
"audio/AMR, " \
|
|
121 |
"rate = (int) 8000, " \
|
|
122 |
"channels = [ 1, 2 ]; " \
|
|
123 |
"audio/AMR-WB, " \
|
|
124 |
"rate = (int) 16000, " \
|
|
125 |
"channels = [ 1, 2 ] "
|
|
126 |
|
|
127 |
/* FIXME 0.11 - take a look at bugs #580005 and #340375 */
|
|
128 |
GstQTMuxFormatProp gst_qt_mux_format_list[] = {
|
|
129 |
/* original QuickTime format; see Apple site (e.g. qtff.pdf) */
|
|
130 |
{
|
|
131 |
GST_QT_MUX_FORMAT_QT,
|
|
132 |
"qtmux",
|
|
133 |
"QuickTime",
|
|
134 |
"GstQTMux",
|
|
135 |
GST_STATIC_CAPS ("video/quicktime, variant = (string) apple"),
|
|
136 |
GST_STATIC_CAPS ("video/x-raw-rgb, "
|
|
137 |
COMMON_VIDEO_CAPS "; "
|
|
138 |
"video/x-raw-yuv, "
|
|
139 |
"format = (fourcc) UYVY, "
|
|
140 |
COMMON_VIDEO_CAPS "; "
|
|
141 |
MPEG4V_CAPS "; "
|
|
142 |
H263_CAPS "; "
|
|
143 |
H264_CAPS "; "
|
|
144 |
"video/x-dv, "
|
|
145 |
"systemstream = (boolean) false, "
|
|
146 |
COMMON_VIDEO_CAPS "; "
|
|
147 |
"image/jpeg, "
|
|
148 |
COMMON_VIDEO_CAPS_NO_FRAMERATE "; "
|
|
149 |
"video/x-qt-part, " COMMON_VIDEO_CAPS),
|
|
150 |
GST_STATIC_CAPS (PCM_CAPS_FULL "; "
|
|
151 |
MP3_CAPS " ; "
|
|
152 |
AAC_CAPS " ; "
|
|
153 |
"audio/x-alaw, " COMMON_AUDIO_CAPS (2, MAX) "; " AMR_CAPS)
|
|
154 |
}
|
|
155 |
,
|
|
156 |
/* ISO 14496-14: mp42 as ISO base media extension
|
|
157 |
* (supersedes original ISO 144996-1 mp41) */
|
|
158 |
{
|
|
159 |
GST_QT_MUX_FORMAT_MP4,
|
|
160 |
"mp4mux",
|
|
161 |
"MP4",
|
|
162 |
"GstMP4Mux",
|
|
163 |
GST_STATIC_CAPS ("video/quicktime, variant = (string) iso"),
|
|
164 |
GST_STATIC_CAPS (MPEG4V_CAPS "; " H264_CAPS ";"
|
|
165 |
"video/x-mp4-part," COMMON_VIDEO_CAPS),
|
|
166 |
GST_STATIC_CAPS (MP3_CAPS "; " AAC_CAPS)
|
|
167 |
}
|
|
168 |
,
|
|
169 |
/* 3GPP Technical Specification 26.244 V7.3.0
|
|
170 |
* (extended in 3GPP2 File Formats for Multimedia Services) */
|
|
171 |
{
|
|
172 |
GST_QT_MUX_FORMAT_3GP,
|
|
173 |
"gppmux",
|
|
174 |
"3GPP",
|
|
175 |
"GstGPPMux",
|
|
176 |
GST_STATIC_CAPS ("video/quicktime, variant = (string) 3gpp"),
|
|
177 |
GST_STATIC_CAPS (H263_CAPS "; " MPEG4V_CAPS "; " H264_CAPS),
|
|
178 |
GST_STATIC_CAPS (AMR_CAPS "; " MP3_CAPS "; " AAC_CAPS)
|
|
179 |
}
|
|
180 |
,
|
|
181 |
/* ISO 15444-3: Motion-JPEG-2000 (also ISO base media extension) */
|
|
182 |
{
|
|
183 |
GST_QT_MUX_FORMAT_MJ2,
|
|
184 |
"mj2mux",
|
|
185 |
"MJ2",
|
|
186 |
"GstMJ2Mux",
|
|
187 |
GST_STATIC_CAPS ("video/mj2"),
|
|
188 |
GST_STATIC_CAPS ("image/x-j2c, " COMMON_VIDEO_CAPS),
|
|
189 |
GST_STATIC_CAPS (PCM_CAPS)
|
|
190 |
}
|
|
191 |
,
|
|
192 |
{
|
|
193 |
GST_QT_MUX_FORMAT_NONE,
|
|
194 |
}
|
|
195 |
,
|
|
196 |
};
|
|
197 |
|
|
198 |
/* pretty static, but may turn out needed a few times */
|
|
199 |
AtomsTreeFlavor
|
|
200 |
gst_qt_mux_map_format_to_flavor (GstQTMuxFormat format)
|
|
201 |
{
|
|
202 |
if (format == GST_QT_MUX_FORMAT_QT)
|
|
203 |
return ATOMS_TREE_FLAVOR_MOV;
|
|
204 |
else if (format == GST_QT_MUX_FORMAT_3GP)
|
|
205 |
return ATOMS_TREE_FLAVOR_3GP;
|
|
206 |
else
|
|
207 |
return ATOMS_TREE_FLAVOR_ISOM;
|
|
208 |
}
|
|
209 |
|
|
210 |
static void
|
|
211 |
gst_qt_mux_map_check_tracks (AtomMOOV * moov, gint * _video, gint * _audio,
|
|
212 |
gboolean * _has_h264)
|
|
213 |
{
|
|
214 |
GList *it;
|
|
215 |
gint video = 0, audio = 0;
|
|
216 |
gboolean has_h264 = FALSE;
|
|
217 |
|
|
218 |
for (it = moov->traks; it != NULL; it = g_list_next (it)) {
|
|
219 |
AtomTRAK *track = it->data;
|
|
220 |
|
|
221 |
if (track->is_video) {
|
|
222 |
video++;
|
|
223 |
if (track->is_h264)
|
|
224 |
has_h264 = TRUE;
|
|
225 |
} else
|
|
226 |
audio++;
|
|
227 |
}
|
|
228 |
|
|
229 |
if (_video)
|
|
230 |
*_video = video;
|
|
231 |
if (_audio)
|
|
232 |
*_audio = audio;
|
|
233 |
if (_has_h264)
|
|
234 |
*_has_h264 = has_h264;
|
|
235 |
}
|
|
236 |
|
|
237 |
/* pretty static, but possibly dynamic format info */
|
|
238 |
|
|
239 |
/* notes:
|
|
240 |
* - avc1 brand is not used, since the specific extensions indicated by it
|
|
241 |
* are not used (e.g. sample groupings, etc)
|
|
242 |
* - TODO: maybe even more 3GPP brand fine-tuning ??
|
|
243 |
* (but that might need ftyp rewriting at the end) */
|
|
244 |
void
|
|
245 |
gst_qt_mux_map_format_to_header (GstQTMuxFormat format, GstBuffer ** _prefix,
|
|
246 |
guint32 * _major, guint32 * _version, GList ** _compatible, AtomMOOV * moov,
|
|
247 |
GstClockTime longest_chunk, gboolean faststart)
|
|
248 |
{
|
|
249 |
static guint32 qt_brands[] = { 0 };
|
|
250 |
static guint32 mp4_brands[] = { FOURCC_mp41, FOURCC_isom, FOURCC_iso2, 0 };
|
|
251 |
static guint32 gpp_brands[] = { FOURCC_isom, FOURCC_iso2, 0 };
|
|
252 |
static guint32 mjp2_brands[] = { FOURCC_isom, FOURCC_iso2, 0 };
|
|
253 |
static guint8 mjp2_prefix[] =
|
|
254 |
{ 0, 0, 0, 12, 'j', 'P', ' ', ' ', 0x0D, 0x0A, 0x87, 0x0A };
|
|
255 |
guint32 *comp = NULL;
|
|
256 |
guint32 major = 0, version = 0;
|
|
257 |
GstBuffer *prefix = NULL;
|
|
258 |
GList *result = NULL;
|
|
259 |
|
|
260 |
g_return_if_fail (_prefix != NULL);
|
|
261 |
g_return_if_fail (_major != NULL);
|
|
262 |
g_return_if_fail (_version != NULL);
|
|
263 |
g_return_if_fail (_compatible != NULL);
|
|
264 |
|
|
265 |
switch (format) {
|
|
266 |
case GST_QT_MUX_FORMAT_QT:
|
|
267 |
major = FOURCC_qt__;
|
|
268 |
comp = qt_brands;
|
|
269 |
version = 0x20050300;
|
|
270 |
break;
|
|
271 |
case GST_QT_MUX_FORMAT_MP4:
|
|
272 |
major = FOURCC_mp42;
|
|
273 |
comp = mp4_brands;
|
|
274 |
break;
|
|
275 |
case GST_QT_MUX_FORMAT_3GP:
|
|
276 |
{
|
|
277 |
gint video, audio;
|
|
278 |
gboolean has_h264;
|
|
279 |
|
|
280 |
gst_qt_mux_map_check_tracks (moov, &video, &audio, &has_h264);
|
|
281 |
/* only track restriction really matters for Basic Profile */
|
|
282 |
if (video <= 1 && audio <= 1) {
|
|
283 |
/* it seems only newer spec knows about H264 */
|
|
284 |
major = has_h264 ? FOURCC_3gp6 : FOURCC_3gp4;
|
|
285 |
version = has_h264 ? 0x100 : 0x200;
|
|
286 |
} else {
|
|
287 |
major = FOURCC_3gg6;
|
|
288 |
version = 0x100;
|
|
289 |
}
|
|
290 |
comp = gpp_brands;
|
|
291 |
|
|
292 |
/*
|
|
293 |
* We assume that we have chunks in dts order
|
|
294 |
*/
|
|
295 |
if (faststart && longest_chunk <= GST_SECOND) {
|
|
296 |
/* add progressive download profile */
|
|
297 |
result = g_list_append (result, GUINT_TO_POINTER (FOURCC_3gr6));
|
|
298 |
}
|
|
299 |
break;
|
|
300 |
}
|
|
301 |
case GST_QT_MUX_FORMAT_MJ2:
|
|
302 |
major = FOURCC_mjp2;
|
|
303 |
comp = mjp2_brands;
|
|
304 |
version = 0;
|
|
305 |
prefix = gst_buffer_new_and_alloc (sizeof (mjp2_prefix));
|
|
306 |
memcpy (GST_BUFFER_DATA (prefix), mjp2_prefix, GST_BUFFER_SIZE (prefix));
|
|
307 |
break;
|
|
308 |
default:
|
|
309 |
g_assert_not_reached ();
|
|
310 |
break;
|
|
311 |
}
|
|
312 |
|
|
313 |
/* convert list to list, hm */
|
|
314 |
while (comp && *comp != 0) {
|
|
315 |
/* order matters over efficiency */
|
|
316 |
result = g_list_append (result, GUINT_TO_POINTER (*comp));
|
|
317 |
comp++;
|
|
318 |
}
|
|
319 |
|
|
320 |
*_major = major;
|
|
321 |
*_version = version;
|
|
322 |
*_prefix = prefix;
|
|
323 |
*_compatible = result;
|
|
324 |
|
|
325 |
/* TODO 3GPP may include mp42 as compatible if applicable */
|
|
326 |
/* TODO 3GPP major brand 3gp7 if at most 1 video and audio track */
|
|
327 |
}
|