1/*
2 * Copyright 2011 castLabs, Berlin
3 *
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.googlecode.mp4parser.boxes.mp4.objectdescriptors;
18
19import com.coremedia.iso.IsoTypeReader;
20
21import java.io.IOException;
22import java.lang.reflect.Modifier;
23import java.nio.ByteBuffer;
24import java.util.HashMap;
25import java.util.HashSet;
26import java.util.Map;
27import java.util.Set;
28import java.util.logging.Level;
29import java.util.logging.Logger;
30
31/* class tag values of 14496-1
320x00 Forbidden
330x01 ObjectDescrTag
340x02 InitialObjectDescrTag
350x03 ES_DescrTag
360x04 DecoderConfigDescrTag
370x05 DecSpecificInfoTag
380x06 SLConfigDescrTag
390x07 ContentIdentDescrTag
400x08 SupplContentIdentDescrTag
410x09 IPI_DescrPointerTag
420x0A IPMP_DescrPointerTag
430x0B IPMP_DescrTag
440x0C QoS_DescrTag
450x0D RegistrationDescrTag
460x0E ES_ID_IncTag
470x0F ES_ID_RefTag
480x10 MP4_IOD_Tag
490x11 MP4_OD_Tag
500x12 IPL_DescrPointerRefTag
510x13 ExtensionProfileLevelDescrTag
520x14 profileLevelIndicationIndexDescrTag
530x15-0x3F Reserved for ISO use
540x40 ContentClassificationDescrTag
550x41 KeyWordDescrTag
560x42 RatingDescrTag
570x43 LanguageDescrTag
580x44 ShortTextualDescrTag
590x45 ExpandedTextualDescrTag
600x46 ContentCreatorNameDescrTag
610x47 ContentCreationDateDescrTag
620x48 OCICreatorNameDescrTag
630x49 OCICreationDateDescrTag
640x4A SmpteCameraPositionDescrTag
650x4B SegmentDescrTag
660x4C MediaTimeDescrTag
670x4D-0x5F Reserved for ISO use (OCI extensions)
680x60 IPMP_ToolsListDescrTag
690x61 IPMP_ToolTag
700x62 M4MuxTimingDescrTag
710x63 M4MuxCodeTableDescrTag
720x64 ExtSLConfigDescrTag
730x65 M4MuxBufferSizeDescrTag
740x66 M4MuxIdentDescrTag
750x67 DependencyPointerTag
760x68 DependencyMarkerTag
770x69 M4MuxChannelDescrTag
780x6A-0xBF Reserved for ISO use
790xC0-0xFE User private
800xFF Forbidden
81 */
82
83/* objectTypeIndication as of 14496-1
840x00 Forbidden
850x01 Systems ISO/IEC 14496-1 a
860x02 Systems ISO/IEC 14496-1 b
870x03 Interaction Stream
880x04 Systems ISO/IEC 14496-1 Extended BIFS Configuration c
890x05 Systems ISO/IEC 14496-1 AFX d
900x06 Font Data Stream
910x07 Synthesized Texture Stream
920x08 Streaming Text Stream
930x09-0x1F reserved for ISO use
940x20 Visual ISO/IEC 14496-2 e
950x21 Visual ITU-T Recommendation H.264 | ISO/IEC 14496-10 f
960x22 Parameter Sets for ITU-T Recommendation H.264 | ISO/IEC 14496-10 f
970x23-0x3F reserved for ISO use
980x40 Audio ISO/IEC 14496-3 g
990x41-0x5F reserved for ISO use
1000x60 Visual ISO/IEC 13818-2 Simple Profile
1010x61 Visual ISO/IEC 13818-2 Main Profile
1020x62 Visual ISO/IEC 13818-2 SNR Profile
1030x63 Visual ISO/IEC 13818-2 Spatial Profile
1040x64 Visual ISO/IEC 13818-2 High Profile
1050x65 Visual ISO/IEC 13818-2 422 Profile
1060x66 Audio ISO/IEC 13818-7 Main Profile
1070x67 Audio ISO/IEC 13818-7 LowComplexity Profile
1080x68 Audio ISO/IEC 13818-7 Scaleable Sampling Rate Profile
1090x69 Audio ISO/IEC 13818-3
1100x6A Visual ISO/IEC 11172-2
1110x6B Audio ISO/IEC 11172-3
1120x6C Visual ISO/IEC 10918-1
1130x6D reserved for registration authority
1140x6E Visual ISO/IEC 15444-1
1150x6F - 0x9F reserved for ISO use
1160xA0 - 0xBF reserved for registration authority i
1170xC0 - 0xE0 user private
1180xE1 reserved for registration authority i
1190xE2 - 0xFE user private
1200xFF no object type specified h
121 */
122public class ObjectDescriptorFactory {
123    protected static Logger log = Logger.getLogger(ObjectDescriptorFactory.class.getName());
124
125    protected static Map<Integer, Map<Integer, Class<? extends BaseDescriptor>>> descriptorRegistry = new HashMap<Integer, Map<Integer, Class<? extends BaseDescriptor>>>();
126
127    static {
128        Set<Class<? extends BaseDescriptor>> annotated = new HashSet<Class<? extends BaseDescriptor>>();
129
130        annotated.add(DecoderSpecificInfo.class);
131        annotated.add(SLConfigDescriptor.class);
132        annotated.add(BaseDescriptor.class);
133        annotated.add(ExtensionDescriptor.class);
134        annotated.add(ObjectDescriptorBase.class);
135        annotated.add(ProfileLevelIndicationDescriptor.class);
136        annotated.add(AudioSpecificConfig.class);
137        annotated.add(ExtensionProfileLevelDescriptor.class);
138        annotated.add(ESDescriptor.class);
139        annotated.add(DecoderConfigDescriptor.class);
140        //annotated.add(ObjectDescriptor.class);
141
142        for (Class<? extends BaseDescriptor> clazz : annotated) {
143            final Descriptor descriptor = clazz.getAnnotation(Descriptor.class);
144            final int[] tags = descriptor.tags();
145            final int objectTypeInd = descriptor.objectTypeIndication();
146
147            Map<Integer, Class<? extends BaseDescriptor>> tagMap = descriptorRegistry.get(objectTypeInd);
148            if (tagMap == null) {
149                tagMap = new HashMap<Integer, Class<? extends BaseDescriptor>>();
150            }
151            for (int tag : tags) {
152                tagMap.put(tag, clazz);
153            }
154            descriptorRegistry.put(objectTypeInd, tagMap);
155        }
156    }
157
158    public static BaseDescriptor createFrom(int objectTypeIndication, ByteBuffer bb) throws IOException {
159        int tag = IsoTypeReader.readUInt8(bb);
160
161        Map<Integer, Class<? extends BaseDescriptor>> tagMap = descriptorRegistry.get(objectTypeIndication);
162        if (tagMap == null) {
163            tagMap = descriptorRegistry.get(-1);
164        }
165        Class<? extends BaseDescriptor> aClass = tagMap.get(tag);
166
167//    if (tag == 0x00) {
168//      log.warning("Found illegal tag 0x00! objectTypeIndication " + Integer.toHexString(objectTypeIndication) +
169//              " and tag " + Integer.toHexString(tag) + " using: " + aClass);
170//      aClass = BaseDescriptor.class;
171//    }
172
173        BaseDescriptor baseDescriptor;
174        if (aClass == null || aClass.isInterface() || Modifier.isAbstract(aClass.getModifiers())) {
175            log.warning("No ObjectDescriptor found for objectTypeIndication " + Integer.toHexString(objectTypeIndication) +
176                    " and tag " + Integer.toHexString(tag) + " found: " + aClass);
177            baseDescriptor = new UnknownDescriptor();
178        } else {
179            try {
180                baseDescriptor = aClass.newInstance();
181            } catch (Exception e) {
182                log.log(Level.SEVERE, "Couldn't instantiate BaseDescriptor class " + aClass + " for objectTypeIndication " + objectTypeIndication + " and tag " + tag, e);
183                throw new RuntimeException(e);
184            }
185        }
186        baseDescriptor.parse(tag, bb);
187        return baseDescriptor;
188    }
189}
190