• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

benrr101 / node-taglib-sharp / 48391054

29 Oct 2023 04:39AM UTC coverage: 92.535% (-1.4%) from 93.934%
48391054

push

appveyor

benrr101
Merge branch 'release/v5.2.0'

3244 of 4129 branches covered (0.0%)

Branch coverage included in aggregate %.

2177 of 2177 new or added lines in 61 files covered. (100.0%)

26728 of 28261 relevant lines covered (94.58%)

423.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

4.88
/src/mpeg4/boxes/appleElementaryStreamDescriptor.ts
1
import FullBox from "./fullBox";
1✔
2
import Mpeg4BoxHeader from "../mpeg4BoxHeader";
3
import {ByteVector, StringType} from "../../byteVector";
1✔
4
import {DescriptorTag} from "../descriptorTag";
1✔
5
import {DescriptorTagReader} from "../descriptorTagReader";
1✔
6
import {File} from "../../file";
7
import {NumberUtils} from "../../utils";
1✔
8

9
/**
10
 * This class extends {@link FullBox} to provide an implementation of an Apple ElementaryStreamDescriptor.
11
 * This box may appear as a child of a {@link IsoAudioSampleEntry} and provided further information about an audio stream.
12
 */
13
export default class AppleElementaryStreamDescriptor extends FullBox {
1✔
14
    private _dependsOnEsId: number;
15
    private _streamDependenceFlag: boolean;
16
    private _ocrStreamFlag: boolean;
17
    private _ocrEsId: number;
18
    private _urlFlag: boolean;
19
    private _urlLength: number;
20
    private _urlString: string;
21
    private _upStream: boolean;
22
    private _maximumBitrate: number;
23
    private _averageBitrate: number;
24
    private _streamId: number;
25
    private _streamPriority: number;
26
    private _objectTypeId: number;
27
    private _streamType: number;
28
    private _bufferSizeDB: number;
29
    private _decoderConfig: ByteVector;
30

31
    /**
32
     * Private constructor to force construction via static functions.
33
     */
34
    private constructor() {
35
        super();
×
36
    }
37

38
    /**
39
     * Constructs and initializes a new instance of {@link AppleElementaryStreamDescriptor} with a provided
40
     * header and handler by reading the contents from a specified file.
41
     * @param header A {@link Mpeg4BoxHeader} object containing the header to use for the new instance.
42
     * @param file A {@link File} object to read the contents of the box from.
43
     * @param handlerType Type of the handler box object containing the handler that applies to the
44
     *     new instance, or undefined if no handler applies.
45
     */
46
    public static fromFile(
47
        header: Mpeg4BoxHeader,
48
        file: File,
49
        handlerType: ByteVector
50
    ): AppleElementaryStreamDescriptor {
51
        // ES_Descriptor Specifications
52
        // Section 7.2.6.5 http://ecee.colorado.edu/~ecen5653/ecen5653/papers/ISO%2014496-1%202004.PDF
53

54
        const instance = new AppleElementaryStreamDescriptor();
×
55
        instance.initializeFromHeaderFileAndHandler(header, file, handlerType);
×
56
        const boxData = file.readBlock(instance.dataSize);
×
57
        instance._decoderConfig = ByteVector.empty();
×
58
        const reader = new DescriptorTagReader(boxData);
×
59

60
        // Elementary Stream Descriptor Tag
61
        if (boxData.get(reader.increaseOffset(1)) !== DescriptorTag.ES_DescrTag) {
×
62
            throw new Error("Invalid Elementary Stream Descriptor, missing tag.");
×
63
        }
64

65
        // We have a descriptor tag. Check that the remainder of the tag is at least
66
        // [
67
        //   Base (3 bytes) +
68
        //   DecoderConfigDescriptor (15 bytes) +
69
        //   SLConfigDescriptor (3 bytes) + OtherDescriptors
70
        // ] bytes long
71
        const esLength = reader.readLength();
×
72
        let minEsLength = 3 + 15 + 3; // Base minimum length
×
73

74
        if (esLength < minEsLength) {
×
75
            throw new Error("Insufficient data present.");
×
76
        }
77

78
        instance._streamId = boxData.subarray(reader.offset, 2).toUshort();
×
79
        reader.increaseOffset(2); // Done with ES_ID
×
80

81
        // 1st bit
82
        const flagByte = boxData.get(reader.offset);
×
83
        instance._streamDependenceFlag = NumberUtils.uintAnd(NumberUtils.uintRShift(flagByte, 7),0x1) === 0x1;
×
84

85
        // 2nd bit
86
        instance._urlFlag = NumberUtils.uintAnd(NumberUtils.uintRShift(flagByte, 6), 0x1) === 0x1;
×
87

88
        // 3rd bit
89
        instance._ocrStreamFlag = NumberUtils.uintAnd(NumberUtils.uintRShift(flagByte, 5), 0x1) === 0x1;
×
90

91
        // Last 5 bits and we're done with this byte
92
        instance._streamPriority = NumberUtils.uintAnd(flagByte, 0x1f);
×
93

94
        reader.increaseOffset(1);
×
95

96
        if (instance._streamDependenceFlag) {
×
97
            minEsLength += 2; // We need 2 more bytes
×
98

99
            if (esLength < minEsLength) {
×
100
                throw new Error("Insufficient data present.");
×
101
            }
102

103
            instance._dependsOnEsId = boxData.subarray(reader.offset, 2).toUshort();
×
104
            reader.increaseOffset(2); // Done with stream dependence
×
105
        }
106

107
        if (instance._urlFlag) {
×
108
            minEsLength += 2; // We need 1 more byte
×
109

110
            if (esLength < minEsLength) {
×
111
                throw new Error("Insufficient data present.");
×
112
            }
113

114
            instance._urlLength = boxData.get(reader.increaseOffset(1)); // URL Length
×
115
            minEsLength += instance._urlLength; // We need URLength more bytes
×
116

117
            if (esLength < minEsLength) {
×
118
                throw new Error("Insufficient data present.");
×
119
            }
120

121
            // URL name
122
            instance._urlString = boxData.subarray(reader.offset, instance._urlLength).toString(StringType.UTF8);
×
123
            reader.increaseOffset(instance._urlLength);
×
124
        }
125

126
        if (instance._ocrStreamFlag) {
×
127
            minEsLength += 2; // We need 2 more bytes
×
128

129
            if (esLength < minEsLength) {
×
130
                throw new Error("Insufficient data present.");
×
131
            }
132

133
            instance._ocrEsId = boxData.subarray(reader.offset, 2).toUshort();
×
134
            reader.increaseOffset(2); // Done with OCR
×
135
        }
136

137
        // Loop through all trailing Descriptors Tags
138
        while (reader.offset < instance.dataSize) {
×
139
            const tag = boxData.get(reader.increaseOffset(1));
×
140
            let length: number;
141
            switch (tag) {
×
142
                case DescriptorTag.DecoderConfigDescrTag: // DecoderConfigDescriptor
×
143
                    /**
144
                     * Check that the remainder of the tag is at least 13 bytes long
145
                     * (13 + DecoderSpecificInfo[] + profileLevelIndicationIndexDescriptor[])
146
                     */
147
                    if (reader.readLength() < 13) {
×
148
                        throw new Error("Could not read data. Too small.");
×
149
                    }
150

151
                    // Read a lot of good info.
152
                    instance._objectTypeId = boxData.get(reader.offset);
×
153
                    reader.increaseOffset(1);
×
154

155
                    // First 6 bits
156
                    const streamByte = boxData.get(reader.offset);
×
157
                    instance._streamType = NumberUtils.uintRShift(streamByte, 2);
×
158

159
                    // 7th bit and we're done with the stream bits
160
                    instance._upStream = NumberUtils.uintAnd(NumberUtils.uintRShift(streamByte, 1), 0x1) === 0x1;
×
161
                    reader.increaseOffset(1);
×
162

163
                    instance._bufferSizeDB = boxData.subarray(reader.offset, 3).toUint();
×
164
                    reader.increaseOffset(3); // Done with bufferSizeDB
×
165

166
                    const maximumBitrate = boxData.subarray(reader.offset, 4).toUint();
×
167
                    instance._maximumBitrate = AppleElementaryStreamDescriptor.calculateBitRate(maximumBitrate);
×
168
                    reader.increaseOffset(4); // Done with maxBitrate
×
169

170
                    const averageBitrate = boxData.subarray(reader.offset, 4).toUint();
×
171
                    instance._averageBitrate = AppleElementaryStreamDescriptor.calculateBitRate(averageBitrate);
×
172
                    reader.increaseOffset(4); // Done with avgBitrate
×
173

174
                    // If there's a DecoderSpecificInfo[] array at the end it'll pick it up in the while loop
175
                    break;
×
176

177
                case DescriptorTag.DecSpecificInfoTag: // DecoderSpecificInfo
178
                    // The rest of the info is decoder specific.
179
                    length = reader.readLength();
×
180

181
                    instance._decoderConfig = boxData.subarray(reader.offset, length);
×
182
                    reader.increaseOffset(length); // We're done with the config
×
183
                    break;
×
184

185
                case DescriptorTag.SLConfigDescrTag: // SLConfigDescriptor
186
                    // The rest of the info is SL specific.
187
                    length = reader.readLength();
×
188

189
                    // Skip the rest of the descriptor as reported in the length so we can move onto the next one
190
                    reader.increaseOffset(length);
×
191
                    break;
×
192

193
                case DescriptorTag.Forbidden_00:
194
                case DescriptorTag.Forbidden_FF:
195
                    throw new Error("Invalid Descriptor tag.");
×
196
                default:
197
                    /**
198
                     * TODO: Should we handle other optional descriptor tags?
199
                     * ExtensionDescriptor extDescr[0 .. 255];
200
                     * LanguageDescriptor langDescr[0 .. 1];
201
                     * IPI_DescPointer ipiPtr[0 .. 1];
202
                     * IP_IdentificationDataSet ipIDS[0 .. 1];
203
                     * QoS_Descriptor qosDescr[0 .. 1];
204
                     */
205
                    // Every descriptor starts with a length
206
                    length = reader.readLength();
×
207

208
                    // Skip the rest of the descriptor as reported in the length so we can move onto the next one
209
                    reader.increaseOffset(length);
×
210

211
                    break;
×
212
            }
213
        }
214

215
        return instance;
×
216
    }
217

218
    /**
219
     * Gets the maximum average the stream described by the current instance.
220
     */
221
    public get averageBitrate(): number { return this._averageBitrate; }
×
222

223
    /**
224
     * Gets the buffer size DB value the stream described by the current instance.
225
     */
226
    public get bufferSizeDB(): number { return this._bufferSizeDB; }
×
227

228
    /**
229
     * Gets the decoder config data of stream described by the current instance.
230
     */
231
    public get decoderConfig(): ByteVector { return this._decoderConfig; }
×
232

233
    /**
234
     * Gets the ES_ID of another elementary stream on which this elementary stream depends
235
     */
236
    public get dependsOnEsId(): number { return this._dependsOnEsId; }
×
237

238
    /**
239
     * Gets the maximum bitrate the stream described by the current instance.
240
     */
241
    public get maximumBitrate(): number { return this._maximumBitrate; }
×
242

243
    /**
244
     * Gets the object type ID of the stream described by the current instance.
245
     */
246
    public get objectTypeId(): number { return this._objectTypeId; }
×
247

248
    /**
249
     * Gets the OCR ES_ID
250
     */
251
    public get ocrEsId(): number { return this._ocrEsId; }
×
252

253
    /**
254
     * Gets the OCR Stream Flag
255
     */
256
    public get ocrStreamFlag(): boolean { return this._ocrStreamFlag; }
×
257

258
    /**
259
     * Gets a value indicating that a dependsOn_ES_ID will follow
260
     */
261
    public get streamDependenceFlag(): boolean { return this._streamDependenceFlag; }
×
262

263
    /**
264
     * Gets the ID of the stream described by the current instance.
265
     */
266
    public get streamId(): number { return this._streamId; }
×
267

268
    /**
269
     * Gets the type of stream described by the current instance.
270
     */
271
    public get streamType(): number { return this._streamType; }
×
272

273
    /**
274
     * Gets the priority of the stream described by the current instance.
275
     */
276
    public get streamPriority(): number { return this._streamPriority; }
×
277

278
    /**
279
     * Gets a value indicating that this stream is used for upstream information
280
     */
281
    public get upStream(): boolean { return this._upStream; }
×
282

283
    /**
284
     * Gets a value indicating that a URL string will follow
285
     */
286
    public get urlFlag(): boolean { return this._urlFlag; }
×
287

288
    /**
289
     * Gets the length of URL String
290
     */
291
    public get urlLength(): number { return this._urlLength; }
×
292

293
    /**
294
     * Gets the URL string that points to the location of an SL-packetized stream by name.
295
     */
296
    public get urlString(): string { return this._urlString; }
×
297

298
    private static calculateBitRate(bitrate: number): number {
299
        return bitrate / 1000;
×
300
    }
301
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc