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

benrr101 / node-taglib-sharp / 51161498

13 Dec 2024 04:24AM UTC coverage: 92.554%. Remained the same
51161498

push

appveyor

benrr101
Merge branch 'release/v6.0.1' into develop

3251 of 4131 branches covered (78.7%)

Branch coverage included in aggregate %.

26753 of 28287 relevant lines covered (94.58%)

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

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

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

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

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

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

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

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

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

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

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

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

95
        reader.increaseOffset(1);
×
96

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

212
                    break;
×
213
            }
214
        }
215

216
        return instance;
×
217
    }
218

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

299
    private static calculateBitRate(bitrate: number): number {
300
        return bitrate / 1000;
×
301
    }
302
}
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

© 2025 Coveralls, Inc