• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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