1 /* GStreamer
2 * Copyright (C) 2008-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 /* Implementation of SMPTE 386M - Mapping Type-D10 essence data into the MXF
21 * Generic Container
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <gst/gst.h>
29 #include <gst/audio/audio.h>
30 #include <string.h>
31
32 #include "mxfd10.h"
33
34 #include "mxfmpeg.h"
35 #include "mxfessence.h"
36
37 GST_DEBUG_CATEGORY_EXTERN (mxf_debug);
38 #define GST_CAT_DEFAULT mxf_debug
39
40 typedef struct
41 {
42 guint width, channels;
43 } MXFD10AudioMappingData;
44
45 static gboolean
mxf_is_d10_essence_track(const MXFMetadataTimelineTrack * track)46 mxf_is_d10_essence_track (const MXFMetadataTimelineTrack * track)
47 {
48 guint i;
49
50 g_return_val_if_fail (track != NULL, FALSE);
51
52 if (track->parent.descriptor == NULL)
53 return FALSE;
54
55 for (i = 0; i < track->parent.n_descriptor; i++) {
56 MXFMetadataFileDescriptor *d = track->parent.descriptor[i];
57 MXFUL *key;
58
59 if (!d)
60 continue;
61
62 key = &d->essence_container;
63 /* SMPTE 386M 5.1 */
64 if (mxf_is_generic_container_essence_container_label (key) &&
65 key->u[12] == 0x02 && key->u[13] == 0x01 &&
66 (key->u[14] >= 0x01 && key->u[14] <= 0x06) &&
67 (key->u[15] == 0x01 || key->u[15] == 0x02 || key->u[15] == 0x7f))
68 return TRUE;
69 }
70
71 return FALSE;
72 }
73
74 static GstFlowReturn
mxf_d10_picture_handle_essence_element(const MXFUL * key,GstBuffer * buffer,GstCaps * caps,MXFMetadataTimelineTrack * track,gpointer mapping_data,GstBuffer ** outbuf)75 mxf_d10_picture_handle_essence_element (const MXFUL * key, GstBuffer * buffer,
76 GstCaps * caps,
77 MXFMetadataTimelineTrack * track,
78 gpointer mapping_data, GstBuffer ** outbuf)
79 {
80 *outbuf = buffer;
81
82 /* SMPTE 386M 5.2.1 */
83 if (key->u[12] != 0x05 || key->u[13] != 0x01 || key->u[14] != 0x01) {
84 GST_ERROR ("Invalid D10 picture essence element");
85 return GST_FLOW_ERROR;
86 }
87
88 if (mxf_mpeg_is_mpeg2_keyframe (buffer))
89 GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
90 else
91 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
92
93 return GST_FLOW_OK;
94 }
95
96 static GstFlowReturn
mxf_d10_sound_handle_essence_element(const MXFUL * key,GstBuffer * buffer,GstCaps * caps,MXFMetadataTimelineTrack * track,gpointer mapping_data,GstBuffer ** outbuf)97 mxf_d10_sound_handle_essence_element (const MXFUL * key, GstBuffer * buffer,
98 GstCaps * caps,
99 MXFMetadataTimelineTrack * track,
100 gpointer mapping_data, GstBuffer ** outbuf)
101 {
102 guint i, j, nsamples;
103 const guint8 *indata;
104 guint8 *outdata;
105 GstMapInfo map;
106 GstMapInfo outmap;
107 MXFD10AudioMappingData *data = mapping_data;
108
109 g_return_val_if_fail (data != NULL, GST_FLOW_ERROR);
110 g_return_val_if_fail (data->channels != 0
111 && data->width != 0, GST_FLOW_ERROR);
112
113 /* SMPTE 386M 5.3.1 */
114 if (key->u[12] != 0x06 || key->u[13] != 0x01 || key->u[14] != 0x10) {
115 GST_ERROR ("Invalid D10 sound essence element");
116 return GST_FLOW_ERROR;
117 }
118
119 gst_buffer_map (buffer, &map, GST_MAP_READ);
120
121 /* Now transform raw AES3 into raw audio, see SMPTE 331M */
122 if (map.size < 4 || (map.size - 4) % 32 != 0) {
123 gst_buffer_unmap (buffer, &map);
124 GST_ERROR ("Invalid D10 sound essence buffer size");
125 return GST_FLOW_ERROR;
126 }
127
128 nsamples = ((map.size - 4) / 4) / 8;
129
130 *outbuf = gst_buffer_new_and_alloc (nsamples * data->width * data->channels);
131 gst_buffer_copy_into (*outbuf, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
132 gst_buffer_map (*outbuf, &outmap, GST_MAP_WRITE);
133
134 indata = map.data;
135 outdata = outmap.data;
136
137 /* Skip 32 bit header */
138 indata += 4;
139
140 for (i = 0; i < nsamples; i++) {
141 for (j = 0; j < data->channels; j++) {
142 guint32 in = GST_READ_UINT32_LE (indata);
143
144 /* Remove first 4 and last 4 bits as they only
145 * contain status data. Shift the 24 bit samples
146 * to the correct width afterwards. */
147 if (data->width == 2) {
148 in = (in >> 12) & 0xffff;
149 GST_WRITE_UINT16_LE (outdata, in);
150 } else if (data->width == 3) {
151 in = (in >> 4) & 0xffffff;
152 GST_WRITE_UINT24_LE (outdata, in);
153 }
154 indata += 4;
155 outdata += data->width;
156 }
157 /* There are always 8 channels but only the first
158 * ones contain valid data, skip the others */
159 indata += 4 * (8 - data->channels);
160 }
161
162 gst_buffer_unmap (*outbuf, &outmap);
163 gst_buffer_unmap (buffer, &map);
164 gst_buffer_unref (buffer);
165
166 return GST_FLOW_OK;
167 }
168
169 static MXFEssenceWrapping
mxf_d10_get_track_wrapping(const MXFMetadataTimelineTrack * track)170 mxf_d10_get_track_wrapping (const MXFMetadataTimelineTrack * track)
171 {
172 return MXF_ESSENCE_WRAPPING_FRAME_WRAPPING;
173 }
174
175 static GstCaps *
mxf_d10_create_caps(MXFMetadataTimelineTrack * track,GstTagList ** tags,gboolean * intra_only,MXFEssenceElementHandleFunc * handler,gpointer * mapping_data)176 mxf_d10_create_caps (MXFMetadataTimelineTrack * track, GstTagList ** tags,
177 gboolean * intra_only, MXFEssenceElementHandleFunc * handler,
178 gpointer * mapping_data)
179 {
180 MXFMetadataGenericPictureEssenceDescriptor *p = NULL;
181 MXFMetadataGenericSoundEssenceDescriptor *s = NULL;
182 guint i;
183 GstCaps *caps = NULL;
184
185 g_return_val_if_fail (track != NULL, NULL);
186
187 if (track->parent.descriptor == NULL) {
188 GST_ERROR ("No descriptor found for this track");
189 return NULL;
190 }
191
192 for (i = 0; i < track->parent.n_descriptor; i++) {
193 if (!track->parent.descriptor[i])
194 continue;
195
196 if (MXF_IS_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR (track->parent.
197 descriptor[i])) {
198 p = (MXFMetadataGenericPictureEssenceDescriptor *) track->
199 parent.descriptor[i];
200 break;
201 } else if (MXF_IS_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (track->parent.
202 descriptor[i])) {
203 s = (MXFMetadataGenericSoundEssenceDescriptor *) track->
204 parent.descriptor[i];
205 break;
206 }
207 }
208
209 if (!s && !p) {
210 GST_ERROR ("No descriptor found for this track");
211 return NULL;
212 }
213
214 if (!*tags)
215 *tags = gst_tag_list_new_empty ();
216
217 if (s) {
218 MXFD10AudioMappingData *data;
219 GstAudioFormat audio_format;
220
221 if (s->channel_count == 0 ||
222 s->channel_count > 8 ||
223 s->quantization_bits == 0 ||
224 s->audio_sampling_rate.n == 0 || s->audio_sampling_rate.d == 0) {
225 GST_ERROR ("Invalid descriptor");
226 return NULL;
227 }
228
229 if (s->quantization_bits != 16 && s->quantization_bits != 24) {
230 GST_ERROR ("Invalid width %u", s->quantization_bits);
231 return NULL;
232 }
233
234 /* FIXME: set channel layout */
235
236 audio_format =
237 gst_audio_format_build_integer (s->quantization_bits != 8,
238 G_LITTLE_ENDIAN, s->quantization_bits, s->quantization_bits);
239 caps =
240 mxf_metadata_generic_sound_essence_descriptor_create_caps (s,
241 &audio_format);
242
243 *handler = mxf_d10_sound_handle_essence_element;
244
245 data = g_new0 (MXFD10AudioMappingData, 1);
246 data->width = s->quantization_bits / 8;
247 data->channels = s->channel_count;
248 *mapping_data = data;
249
250 gst_tag_list_add (*tags, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
251 "SMPTE D-10 Audio", NULL);
252
253 *intra_only = TRUE;
254 } else if (p) {
255 caps =
256 gst_caps_new_simple ("video/mpeg", "systemstream", G_TYPE_BOOLEAN,
257 FALSE, "mpegversion", G_TYPE_INT, 2, NULL);
258 mxf_metadata_generic_picture_essence_descriptor_set_caps (p, caps);
259
260 *handler = mxf_d10_picture_handle_essence_element;
261 gst_tag_list_add (*tags, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
262 "SMPTE D-10 Video", NULL);
263
264 /* Does not allow temporal reordering */
265 *intra_only = TRUE;
266 }
267
268 return caps;
269 }
270
271 static const MXFEssenceElementHandler mxf_d10_essence_element_handler = {
272 mxf_is_d10_essence_track,
273 mxf_d10_get_track_wrapping,
274 mxf_d10_create_caps
275 };
276
277 void
mxf_d10_init(void)278 mxf_d10_init (void)
279 {
280 mxf_essence_element_handler_register (&mxf_d10_essence_element_handler);
281 }
282