-
Notifications
You must be signed in to change notification settings - Fork 4
/
sampledescription.cc
392 lines (366 loc) · 15 KB
/
sampledescription.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
//
// Created by wlanjie on 2018/3/10.
//
#include "sampledescription.h"
#include "atomfactory.h"
#include "sample_entry.h"
#include "utils.h"
#include "sl_config_descriptor.h"
#include "mp4_audio_info.h"
namespace mp4 {
SampleDescription::SampleDescription(SampleDescription::Type type,
UI32 format,
AtomParent *details) :
type(type),
format(format) {
if (details) {
for (List<Atom>::Item* item = details->getChildren().firstItem(); item; item = item->getNext()) {
Atom* atom = item->getData();
if (atom) {
Atom* clone = atom->clone();
if (clone) {
this->details.addChild(clone);
}
}
}
}
}
SampleDescription::~SampleDescription() {
}
SampleDescription *SampleDescription::clone(Result *result) {
if (result) {
*result = SUCCESS;
}
Atom* atom = toAtom();
if (atom == nullptr) {
if (result) {
*result = FAILURE;
}
return nullptr;
}
MemoryByteStream* mbs = new MemoryByteStream((UI32) atom->getSize());
atom->write(*mbs);
delete atom;
atom = nullptr;
mbs->seek(0);
AtomFactory* factory = new AtomFactory();
factory->pushContext(ATOM_TYPE_STSD);
Atom* atomClone = nullptr;
auto createAtomResult = factory->createAtomFromStream(*mbs, atomClone);
factory->popContext();
delete factory;
if (result) {
*result = createAtomResult;
}
mbs->release();
if (FAILED(createAtomResult)) {
return nullptr;
}
SampleEntry* sampleEntry = DYNAMIC_CAST(SampleEntry, atomClone);
if (sampleEntry == nullptr) {
if (result) {
*result = ERROR_INTERNAL;
delete atomClone;
}
return nullptr;
}
SampleDescription* clone = sampleEntry->toSampleDescription();
if (clone == nullptr) {
if (result) {
*result = ERROR_INTERNAL;
}
}
delete atomClone;
return clone;
}
Result SampleDescription::getCodecString(String &codec) {
char coding[5];
formatFourChars(coding, format);
codec.assign(coding, 4);
return SUCCESS;
}
Atom *SampleDescription::toAtom() const {
return new SampleEntry(format);
}
Atom *GenericVideoSampleDescription::toAtom() const {
auto* sampleEntry = new VisualSampleEntry(format, width, height, depth, compressorName.getChars());
AtomParent& details = const_cast<AtomParent&>(this->details);
for (List<Atom>::Item* item = details.getChildren().firstItem(); item; item = item->getNext()) {
Atom* child = item->getData();
sampleEntry->addChild(child->clone());
}
return SampleDescription::toAtom();
}
Atom *GenericAudioSampleDescription::toAtom() const {
auto* sampleEntry = new AudioSampleEntry(format, sampleRate << 16, sampleSize, channelCount);
AtomParent& details = const_cast<AtomParent&>(this->details);
for (List<Atom>::Item* item = details.getChildren().firstItem(); item; item = item->getNext()) {
auto* child = item->getData();
sampleEntry->addChild(child->clone());
}
return sampleEntry;
}
const char *MpegSampleDescription::getStreamTypeString(StreamType type) {
switch (type) {
case STREAM_TYPE_FORBIDDEN:
return "INVALID";
case STREAM_TYPE_OD:
return "Object Descriptor";
case STREAM_TYPE_CR:
return "CR";
case STREAM_TYPE_BIFS:
return "BIFS";
case STREAM_TYPE_VISUAL:
return "Visual";
case STREAM_TYPE_AUDIO:
return "Audio";
case STREAM_TYPE_MPEG7:
return "MPEG-7";
case STREAM_TYPE_IPMP:
return "IPMP";
case STREAM_TYPE_OCI:
return "OCI";
case STREAM_TYPE_MPEGJ:
return "MPEG-J";
default:
return "UNKNOWN";
}
}
const char *MpegSampleDescription::getObjectTypeString(OTI oti) {
switch (oti) {
case OTI_MPEG4_SYSTEM: return "MPEG-4 System";
case OTI_MPEG4_SYSTEM_COR: return "MPEG-4 System COR";
case OTI_MPEG4_VISUAL: return "MPEG-4 Video";
case OTI_MPEG4_AUDIO: return "MPEG-4 Audio";
case OTI_MPEG2_VISUAL_SIMPLE: return "MPEG-2 Video Simple Profile";
case OTI_MPEG2_VISUAL_MAIN: return "MPEG-2 Video Main Profile";
case OTI_MPEG2_VISUAL_SNR: return "MPEG-2 Video SNR";
case OTI_MPEG2_VISUAL_SPATIAL: return "MPEG-2 Video Spatial";
case OTI_MPEG2_VISUAL_HIGH: return "MPEG-2 Video High";
case OTI_MPEG2_VISUAL_422: return "MPEG-2 Video 4:2:2";
case OTI_MPEG2_AAC_AUDIO_MAIN: return "MPEG-2 Audio AAC Main Profile";
case OTI_MPEG2_AAC_AUDIO_LC: return "MPEG-2 Audio AAC Low Complexity";
case OTI_MPEG2_AAC_AUDIO_SSRP: return "MPEG-2 Audio AAC SSRP";
case OTI_MPEG2_PART3_AUDIO: return "MPEG-2 Audio Part-3";
case OTI_MPEG1_VISUAL: return "MPEG-1 Video";
case OTI_MPEG1_AUDIO: return "MPEG-1 Audio";
case OTI_JPEG: return "JPEG";
case OTI_JPEG2000: return "JPEG-2000";
case OTI_EVRC_VOICE: return "EVRC Voice";
case OTI_SMV_VOICE: return "SMV Voice";
case OTI_3GPP2_CMF: return "3GPP2 CMF";
case OTI_SMPTE_VC1: return "SMPTE VC1 Video";
case OTI_DIRAC_VIDEO: return "Dirac Video";
case OTI_AC3_AUDIO: return "AC3 Audio";
case OTI_EAC3_AUDIO: return "E-AC3 Audio";
case OTI_DRA_AUDIO: return "DRA Audio";
case OTI_G719_AUDIO: return "G.719 Audio";
case OTI_DTS_AUDIO: return "DTS Audio";
case OTI_DTS_HIRES_AUDIO: return "DTS High Resolution Audio";
case OTI_DTS_MASTER_AUDIO: return "DTS Master Audio";
case OTI_DTS_EXPRESS_AUDIO: return "DTS Express/LBR Audio";
case OTI_13K_VOICE: return "13K Voice";
default: return "UNKNOWN";
}
}
MpegSampleDescription::MpegSampleDescription(UI32 format, Esds *esds) :
SampleDescription(TYPE_MPEG, format, nullptr),
streamType(0),
objectTypeId(0),
bufferSize(0),
maxBitRate(0),
avgBitRate(0) {
if (esds) {
const auto* esDesc = esds->getEsDescriptor();
if (!esDesc) {
return;
}
const auto* dcDesc = esDesc->getDecoderConfigDescription();
if (dcDesc) {
streamType = dcDesc->getStreamType();
objectTypeId = dcDesc->getObjectTypeIndication();
bufferSize = dcDesc->getBufferSize();
maxBitRate = dcDesc->getMaxBitRate();
avgBitRate = dcDesc->getAvgBitRate();
const auto* dsiDesc = dcDesc->getDecoderSpecificInfoDescriptor();
if (dsiDesc) {
decoderInfo.setData(dsiDesc->getDecoderSpecificInfo().getData(),
dsiDesc->getDecoderSpecificInfo().getDataSize());
}
}
}
}
MpegSampleDescription::MpegSampleDescription(UI32 format,
UI08 streamType,
UI08 oti,
const DataBuffer *decoderInfo,
UI32 bufferSize,
UI32 maxBitRate,
UI32 avgBitRate) :
SampleDescription(TYPE_MPEG, format, nullptr),
streamType(streamType),
objectTypeId(oti),
bufferSize(bufferSize),
maxBitRate(maxBitRate),
avgBitRate(avgBitRate) {
if (decoderInfo) {
this->decoderInfo.setData(decoderInfo->getData(), decoderInfo->getDataSize());
}
}
EsDescriptor *MpegSampleDescription::createEsDescriptor() const {
auto* desc = new EsDescriptor(0);
DecoderSpecificInfoDescriptor* dsiDesc = nullptr;
if (decoderInfo.getDataSize() != 0) {
dsiDesc = new DecoderSpecificInfoDescriptor(decoderInfo);
}
auto* decoderConfig = new DecoderConfigDescriptor(streamType, objectTypeId, bufferSize, maxBitRate, avgBitRate, dsiDesc);
desc->addSubDescriptor(decoderConfig);
desc->addSubDescriptor(new SLConfigDescriptor());
return desc;
}
const char * MpegAudioSampleDescription::getMpeg4AudioObjectTypeString(MpegAudioSampleDescription::Mpeg4AudioObjectType type) {
switch (type) {
case MPEG4_AUDIO_OBJECT_TYPE_AAC_MAIN:
return "AAC Main Profile";
case MPEG4_AUDIO_OBJECT_TYPE_AAC_LC:
return "AAC Low Complexity";
case MPEG4_AUDIO_OBJECT_TYPE_AAC_SSR:
return "AAC Scalable Sample Rate";
case MPEG4_AUDIO_OBJECT_TYPE_AAC_LTP:
return "AAC Long Term Predictor";
case MPEG4_AUDIO_OBJECT_TYPE_SBR:
return "Spectral Band Replication";
case MPEG4_AUDIO_OBJECT_TYPE_AAC_SCALABLE:
return "AAC Scalable";
case MPEG4_AUDIO_OBJECT_TYPE_TWINVQ:
return "Twin VQ";
case MPEG4_AUDIO_OBJECT_TYPE_CELP:
return "CELP";
case MPEG4_AUDIO_OBJECT_TYPE_HVXC:
return "HVXC";
case MPEG4_AUDIO_OBJECT_TYPE_TTSI:
return "TTSI";
case MPEG4_AUDIO_OBJECT_TYPE_MAIN_SYNTHETIC:
return "Main Synthetic";
case MPEG4_AUDIO_OBJECT_TYPE_WAVETABLE_SYNTHESIS:
return "Wavetable Synthesis";
case MPEG4_AUDIO_OBJECT_TYPE_GENERAL_MIDI:
return "General MIDI";
case MPEG4_AUDIO_OBJECT_TYPE_ALGORITHMIC_SYNTHESIS:
return "Algorithmic Synthesis";
case MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_LC:
return "Error Resilient AAC Low Complexity";
case MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_LTP:
return "Error Resilient AAC Long Term Prediction";
case MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_SCALABLE:
return "Error Resilient AAC Scalable";
case MPEG4_AUDIO_OBJECT_TYPE_ER_TWINVQ:
return "Error Resilient Twin VQ";
case MPEG4_AUDIO_OBJECT_TYPE_ER_BSAC:
return "Error Resilient Bit Sliced Arithmetic Coding";
case MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_LD:
return "Error Resilient AAC Low Delay";
case MPEG4_AUDIO_OBJECT_TYPE_ER_CELP:
return "Error Resilient CELP";
case MPEG4_AUDIO_OBJECT_TYPE_ER_HVXC:
return "Error Resilient HVXC";
case MPEG4_AUDIO_OBJECT_TYPE_ER_HILN:
return "Error Resilient HILN";
case MPEG4_AUDIO_OBJECT_TYPE_ER_PARAMETRIC:
return "Error Resilient Parametric";
case MPEG4_AUDIO_OBJECT_TYPE_SSC:
return "SSC";
case MPEG4_AUDIO_OBJECT_TYPE_PS:
return "Parametric Stereo";
case MPEG4_AUDIO_OBJECT_TYPE_MPEG_SURROUND:
return "MPEG Surround";
case MPEG4_AUDIO_OBJECT_TYPE_LAYER_1:
return "MPEG Layer 1";
case MPEG4_AUDIO_OBJECT_TYPE_LAYER_2:
return "MPEG Layer 2";
case MPEG4_AUDIO_OBJECT_TYPE_LAYER_3:
return "MPEG Layer 3";
case MPEG4_AUDIO_OBJECT_TYPE_DST:
return "Direct Stream Transfer";
case MPEG4_AUDIO_OBJECT_TYPE_ALS:
return "ALS Lossless Coding";
case MPEG4_AUDIO_OBJECT_TYPE_SLS:
return "SLS Scalable Lossless Coding";
case MPEG4_AUDIO_OBJECT_TYPE_SLS_NON_CORE:
return "SLS Scalable Lossless Coding (Non Core)";
case MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_ELD:
return "Error Resilient AAC ELD";
case MPEG4_AUDIO_OBJECT_TYPE_SMR_SIMPLE:
return "SMR Simple";
case MPEG4_AUDIO_OBJECT_TYPE_SMR_MAIN:
return "SMR Main";
default:
return "UNKNOWN";
}
}
MpegAudioSampleDescription::MpegAudioSampleDescription(UI32 sampleRate,
UI16 sampleSize,
UI16 channelCount,
Esds *esds) :
MpegSampleDescription(ATOM_TYPE_MP4A, esds),
AudioSampleDescription(sampleRate, sampleSize, channelCount) {
}
MpegAudioSampleDescription::MpegAudioSampleDescription(MpegSampleDescription::OTI oti,
UI32 sampleRate,
UI16 sampleSize,
UI16 channelCount,
const DataBuffer *decoderInfo,
UI32 bufferSize,
UI32 maxBitRate,
UI32 avgBitRate) :
MpegSampleDescription(ATOM_TYPE_MP4A, STREAM_TYPE_AUDIO, oti, decoderInfo, bufferSize, maxBitRate, avgBitRate),
AudioSampleDescription(sampleRate, sampleSize, channelCount) {
}
Result MpegAudioSampleDescription::getCodecString(String &codec) {
char coding[5];
formatFourChars(coding, getFormat());
char workspace[64];
workspace[0] = 0;
if (getFormat() == SAMPLE_FORMAT_MP4A) {
if (getObjectTypeId() == OTI_MPEG4_AUDIO) {
Mpeg4AudioObjectType object_type = getMpeg4AudioObjectType();
if (object_type == MPEG4_AUDIO_OBJECT_TYPE_AAC_LC) {
const DataBuffer& dsi = getDecoderInfo();
if (dsi.getDataSize()) {
Mp4AudioDecoderConfig decConfig;
Result result = decConfig.parse(dsi.getData(), dsi.getDataSize());
if (SUCCEEDED(result)) {
if (decConfig.Extension.psPresent) {
object_type = MPEG4_AUDIO_OBJECT_TYPE_PS;
} else if (decConfig.Extension.sbrPresent) {
object_type = MPEG4_AUDIO_OBJECT_TYPE_SBR;
}
}
}
}
FormatString(workspace, sizeof(workspace), "%s.%02X.%d", coding, (int)getObjectTypeId(), object_type);
} else {
FormatString(workspace, sizeof(workspace), "%s.%02X", coding, (int)getObjectTypeId());
}
}
codec = workspace;
return SUCCESS;
}
MpegAudioSampleDescription::Mpeg4AudioObjectType MpegAudioSampleDescription::getMpeg4AudioObjectType() const {
if (objectTypeId == OTI_MPEG4_AUDIO &&
decoderInfo.getDataSize() >= 1) {
UI08 type = decoderInfo.getData()[0] >> 3;
if (type == 31) {
if (decoderInfo.getDataSize() < 2) {
return 0;
}
type = 32 + (((decoderInfo.getData()[0] & 0x07) << 3) | ((decoderInfo.getData()[1] & 0xE0) >> 5));
}
return type;
}
return 0;
}
Atom *MpegAudioSampleDescription::toAtom() const {
return new Mp4aSampleEntry(sampleRate << 16, sampleSize, channelCount, createEsDescriptor());
}
}