blob: 6cf1301934aba549464cdbea32037aad554731fd [file] [log] [blame]
Andreas Huber7a747b82010-06-07 15:19:40 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
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
Andreas Huber6e3fa442010-09-21 13:13:15 -070017//#define LOG_NDEBUG 0
18#define LOG_TAG "APacketSource"
19#include <utils/Log.h>
20
Andreas Huber7a747b82010-06-07 15:19:40 -070021#include "APacketSource.h"
22
Andreas Huberb6723732011-02-22 16:25:00 -080023#include "ARawAudioAssembler.h"
Andreas Huber7a747b82010-06-07 15:19:40 -070024#include "ASessionDescription.h"
25
Andreas Hubereef3c332010-08-19 10:39:47 -070026#include "avc_utils.h"
27
Andreas Huberaf063a62010-08-18 10:17:18 -070028#include <ctype.h>
29
Andreas Hubera979ad62010-08-19 10:56:15 -070030#include <media/stagefright/foundation/ABitReader.h>
Andreas Huber7a747b82010-06-07 15:19:40 -070031#include <media/stagefright/foundation/ABuffer.h>
32#include <media/stagefright/foundation/ADebug.h>
33#include <media/stagefright/foundation/AMessage.h>
34#include <media/stagefright/foundation/AString.h>
35#include <media/stagefright/foundation/base64.h>
36#include <media/stagefright/foundation/hexdump.h>
Andreas Huber7a747b82010-06-07 15:19:40 -070037#include <media/stagefright/MediaDefs.h>
Andreas Hubera6be6dc2011-10-11 15:24:07 -070038#include <media/stagefright/MediaErrors.h>
Andreas Huber7a747b82010-06-07 15:19:40 -070039#include <media/stagefright/MetaData.h>
40#include <utils/Vector.h>
41
42namespace android {
43
44static bool GetAttribute(const char *s, const char *key, AString *value) {
45 value->clear();
46
47 size_t keyLen = strlen(key);
48
49 for (;;) {
Andreas Huberaf063a62010-08-18 10:17:18 -070050 while (isspace(*s)) {
51 ++s;
52 }
53
Andreas Huber7a747b82010-06-07 15:19:40 -070054 const char *colonPos = strchr(s, ';');
55
56 size_t len =
57 (colonPos == NULL) ? strlen(s) : colonPos - s;
58
59 if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
60 value->setTo(&s[keyLen + 1], len - keyLen - 1);
61 return true;
62 }
63
64 if (colonPos == NULL) {
65 return false;
66 }
67
68 s = colonPos + 1;
69 }
70}
71
72static sp<ABuffer> decodeHex(const AString &s) {
73 if ((s.size() % 2) != 0) {
74 return NULL;
75 }
76
77 size_t outLen = s.size() / 2;
78 sp<ABuffer> buffer = new ABuffer(outLen);
79 uint8_t *out = buffer->data();
80
81 uint8_t accum = 0;
82 for (size_t i = 0; i < s.size(); ++i) {
83 char c = s.c_str()[i];
84 unsigned value;
85 if (c >= '0' && c <= '9') {
86 value = c - '0';
87 } else if (c >= 'a' && c <= 'f') {
88 value = c - 'a' + 10;
89 } else if (c >= 'A' && c <= 'F') {
90 value = c - 'A' + 10;
91 } else {
92 return NULL;
93 }
94
95 accum = (accum << 4) | value;
96
97 if (i & 1) {
98 *out++ = accum;
99
100 accum = 0;
101 }
102 }
103
104 return buffer;
105}
106
Andreas Hubereef3c332010-08-19 10:39:47 -0700107static sp<ABuffer> MakeAVCCodecSpecificData(
108 const char *params, int32_t *width, int32_t *height) {
109 *width = 0;
110 *height = 0;
111
Andreas Huber7a747b82010-06-07 15:19:40 -0700112 AString val;
Andreas Huber426b6502010-08-04 14:04:31 -0700113 if (!GetAttribute(params, "profile-level-id", &val)) {
114 return NULL;
115 }
Andreas Huber7a747b82010-06-07 15:19:40 -0700116
117 sp<ABuffer> profileLevelID = decodeHex(val);
118 CHECK(profileLevelID != NULL);
119 CHECK_EQ(profileLevelID->size(), 3u);
120
121 Vector<sp<ABuffer> > paramSets;
122
123 size_t numSeqParameterSets = 0;
124 size_t totalSeqParameterSetSize = 0;
125 size_t numPicParameterSets = 0;
126 size_t totalPicParameterSetSize = 0;
127
Andreas Huber426b6502010-08-04 14:04:31 -0700128 if (!GetAttribute(params, "sprop-parameter-sets", &val)) {
129 return NULL;
130 }
131
Andreas Huber7a747b82010-06-07 15:19:40 -0700132 size_t start = 0;
133 for (;;) {
134 ssize_t commaPos = val.find(",", start);
135 size_t end = (commaPos < 0) ? val.size() : commaPos;
136
137 AString nalString(val, start, end - start);
138 sp<ABuffer> nal = decodeBase64(nalString);
139 CHECK(nal != NULL);
140 CHECK_GT(nal->size(), 0u);
141 CHECK_LE(nal->size(), 65535u);
142
143 uint8_t nalType = nal->data()[0] & 0x1f;
144 if (numSeqParameterSets == 0) {
145 CHECK_EQ((unsigned)nalType, 7u);
146 } else if (numPicParameterSets > 0) {
147 CHECK_EQ((unsigned)nalType, 8u);
148 }
149 if (nalType == 7) {
150 ++numSeqParameterSets;
151 totalSeqParameterSetSize += nal->size();
152 } else {
153 CHECK_EQ((unsigned)nalType, 8u);
154 ++numPicParameterSets;
155 totalPicParameterSetSize += nal->size();
156 }
157
158 paramSets.push(nal);
159
160 if (commaPos < 0) {
161 break;
162 }
163
164 start = commaPos + 1;
165 }
166
167 CHECK_LT(numSeqParameterSets, 32u);
168 CHECK_LE(numPicParameterSets, 255u);
169
170 size_t csdSize =
171 1 + 3 + 1 + 1
172 + 2 * numSeqParameterSets + totalSeqParameterSetSize
173 + 1 + 2 * numPicParameterSets + totalPicParameterSetSize;
174
175 sp<ABuffer> csd = new ABuffer(csdSize);
176 uint8_t *out = csd->data();
177
178 *out++ = 0x01; // configurationVersion
179 memcpy(out, profileLevelID->data(), 3);
180 out += 3;
181 *out++ = (0x3f << 2) | 1; // lengthSize == 2 bytes
182 *out++ = 0xe0 | numSeqParameterSets;
183
184 for (size_t i = 0; i < numSeqParameterSets; ++i) {
185 sp<ABuffer> nal = paramSets.editItemAt(i);
186
187 *out++ = nal->size() >> 8;
188 *out++ = nal->size() & 0xff;
189
190 memcpy(out, nal->data(), nal->size());
191
192 out += nal->size();
Andreas Hubereef3c332010-08-19 10:39:47 -0700193
194 if (i == 0) {
195 FindAVCDimensions(nal, width, height);
Steve Block6215d3f2012-01-04 20:05:49 +0000196 ALOGI("dimensions %dx%d", *width, *height);
Andreas Hubereef3c332010-08-19 10:39:47 -0700197 }
Andreas Huber7a747b82010-06-07 15:19:40 -0700198 }
199
200 *out++ = numPicParameterSets;
201
202 for (size_t i = 0; i < numPicParameterSets; ++i) {
203 sp<ABuffer> nal = paramSets.editItemAt(i + numSeqParameterSets);
204
205 *out++ = nal->size() >> 8;
206 *out++ = nal->size() & 0xff;
207
208 memcpy(out, nal->data(), nal->size());
209
210 out += nal->size();
211 }
212
Andreas Hubereef3c332010-08-19 10:39:47 -0700213 // hexdump(csd->data(), csd->size());
Andreas Huber7a747b82010-06-07 15:19:40 -0700214
215 return csd;
216}
217
218sp<ABuffer> MakeAACCodecSpecificData(const char *params) {
219 AString val;
220 CHECK(GetAttribute(params, "config", &val));
221
222 sp<ABuffer> config = decodeHex(val);
223 CHECK(config != NULL);
224 CHECK_GE(config->size(), 4u);
225
226 const uint8_t *data = config->data();
227 uint32_t x = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
228 x = (x >> 1) & 0xffff;
229
230 static const uint8_t kStaticESDS[] = {
231 0x03, 22,
232 0x00, 0x00, // ES_ID
233 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag
234
235 0x04, 17,
236 0x40, // Audio ISO/IEC 14496-3
237 0x00, 0x00, 0x00, 0x00,
238 0x00, 0x00, 0x00, 0x00,
239 0x00, 0x00, 0x00, 0x00,
240
241 0x05, 2,
242 // AudioSpecificInfo follows
243 };
244
245 sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + 2);
246 memcpy(csd->data(), kStaticESDS, sizeof(kStaticESDS));
247 csd->data()[sizeof(kStaticESDS)] = (x >> 8) & 0xff;
248 csd->data()[sizeof(kStaticESDS) + 1] = x & 0xff;
249
Andreas Hubereef3c332010-08-19 10:39:47 -0700250 // hexdump(csd->data(), csd->size());
Andreas Huber7a747b82010-06-07 15:19:40 -0700251
252 return csd;
253}
254
Andreas Hubere536f802010-08-31 14:25:36 -0700255// From mpeg4-generic configuration data.
256sp<ABuffer> MakeAACCodecSpecificData2(const char *params) {
257 AString val;
258 unsigned long objectType;
259 if (GetAttribute(params, "objectType", &val)) {
260 const char *s = val.c_str();
261 char *end;
262 objectType = strtoul(s, &end, 10);
263 CHECK(end > s && *end == '\0');
264 } else {
265 objectType = 0x40; // Audio ISO/IEC 14496-3
266 }
267
268 CHECK(GetAttribute(params, "config", &val));
269
270 sp<ABuffer> config = decodeHex(val);
271 CHECK(config != NULL);
272
273 // Make sure size fits into a single byte and doesn't have to
274 // be encoded.
275 CHECK_LT(20 + config->size(), 128u);
276
277 const uint8_t *data = config->data();
278
279 static const uint8_t kStaticESDS[] = {
280 0x03, 22,
281 0x00, 0x00, // ES_ID
282 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag
283
284 0x04, 17,
285 0x40, // Audio ISO/IEC 14496-3
286 0x00, 0x00, 0x00, 0x00,
287 0x00, 0x00, 0x00, 0x00,
288 0x00, 0x00, 0x00, 0x00,
289
290 0x05, 2,
291 // AudioSpecificInfo follows
292 };
293
294 sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + config->size());
295 uint8_t *dst = csd->data();
296 *dst++ = 0x03;
297 *dst++ = 20 + config->size();
298 *dst++ = 0x00; // ES_ID
299 *dst++ = 0x00;
300 *dst++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag
301 *dst++ = 0x04;
302 *dst++ = 15 + config->size();
303 *dst++ = objectType;
304 for (int i = 0; i < 12; ++i) { *dst++ = 0x00; }
305 *dst++ = 0x05;
306 *dst++ = config->size();
307 memcpy(dst, config->data(), config->size());
308
309 // hexdump(csd->data(), csd->size());
310
311 return csd;
312}
313
Andreas Hubera979ad62010-08-19 10:56:15 -0700314static size_t GetSizeWidth(size_t x) {
315 size_t n = 1;
316 while (x > 127) {
317 ++n;
318 x >>= 7;
319 }
320 return n;
321}
322
323static uint8_t *EncodeSize(uint8_t *dst, size_t x) {
324 while (x > 127) {
325 *dst++ = (x & 0x7f) | 0x80;
326 x >>= 7;
327 }
328 *dst++ = x;
329 return dst;
330}
331
Andreas Hubereb2f9c12011-05-19 08:37:39 -0700332static bool ExtractDimensionsMPEG4Config(
Andreas Hubera979ad62010-08-19 10:56:15 -0700333 const sp<ABuffer> &config, int32_t *width, int32_t *height) {
334 *width = 0;
335 *height = 0;
336
337 const uint8_t *ptr = config->data();
338 size_t offset = 0;
339 bool foundVOL = false;
340 while (offset + 3 < config->size()) {
341 if (memcmp("\x00\x00\x01", &ptr[offset], 3)
342 || (ptr[offset + 3] & 0xf0) != 0x20) {
343 ++offset;
344 continue;
345 }
346
347 foundVOL = true;
348 break;
349 }
350
351 if (!foundVOL) {
352 return false;
353 }
354
Andreas Hubereb2f9c12011-05-19 08:37:39 -0700355 return ExtractDimensionsFromVOLHeader(
356 &ptr[offset], config->size() - offset, width, height);
Andreas Hubera979ad62010-08-19 10:56:15 -0700357}
358
Andreas Hubereb2f9c12011-05-19 08:37:39 -0700359static sp<ABuffer> MakeMPEG4VideoCodecSpecificData(
Andreas Hubera979ad62010-08-19 10:56:15 -0700360 const char *params, int32_t *width, int32_t *height) {
361 *width = 0;
362 *height = 0;
363
364 AString val;
365 CHECK(GetAttribute(params, "config", &val));
366
367 sp<ABuffer> config = decodeHex(val);
368 CHECK(config != NULL);
369
Andreas Hubereb2f9c12011-05-19 08:37:39 -0700370 if (!ExtractDimensionsMPEG4Config(config, width, height)) {
Andreas Hubera979ad62010-08-19 10:56:15 -0700371 return NULL;
372 }
373
Steve Block6215d3f2012-01-04 20:05:49 +0000374 ALOGI("VOL dimensions = %dx%d", *width, *height);
Andreas Hubereb2f9c12011-05-19 08:37:39 -0700375
Andreas Hubera979ad62010-08-19 10:56:15 -0700376 size_t len1 = config->size() + GetSizeWidth(config->size()) + 1;
377 size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13;
378 size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3;
379
380 sp<ABuffer> csd = new ABuffer(len3);
381 uint8_t *dst = csd->data();
382 *dst++ = 0x03;
383 dst = EncodeSize(dst, len2 + 3);
384 *dst++ = 0x00; // ES_ID
385 *dst++ = 0x00;
386 *dst++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag
387
388 *dst++ = 0x04;
389 dst = EncodeSize(dst, len1 + 13);
390 *dst++ = 0x01; // Video ISO/IEC 14496-2 Simple Profile
391 for (size_t i = 0; i < 12; ++i) {
392 *dst++ = 0x00;
393 }
394
395 *dst++ = 0x05;
396 dst = EncodeSize(dst, config->size());
397 memcpy(dst, config->data(), config->size());
398 dst += config->size();
399
400 // hexdump(csd->data(), csd->size());
401
402 return csd;
403}
404
Andreas Huber7a747b82010-06-07 15:19:40 -0700405APacketSource::APacketSource(
406 const sp<ASessionDescription> &sessionDesc, size_t index)
Andreas Huber57648e42010-08-04 10:14:30 -0700407 : mInitCheck(NO_INIT),
Andreas Hubera6be6dc2011-10-11 15:24:07 -0700408 mFormat(new MetaData) {
Andreas Huber7a747b82010-06-07 15:19:40 -0700409 unsigned long PT;
410 AString desc;
411 AString params;
412 sessionDesc->getFormatType(index, &PT, &desc, &params);
413
414 int64_t durationUs;
415 if (sessionDesc->getDurationUs(&durationUs)) {
416 mFormat->setInt64(kKeyDuration, durationUs);
417 } else {
418 mFormat->setInt64(kKeyDuration, 60 * 60 * 1000000ll);
419 }
420
Andreas Huber57648e42010-08-04 10:14:30 -0700421 mInitCheck = OK;
Andreas Huber7a747b82010-06-07 15:19:40 -0700422 if (!strncmp(desc.c_str(), "H264/", 5)) {
423 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
424
425 int32_t width, height;
Andreas Huberaf063a62010-08-18 10:17:18 -0700426 if (!sessionDesc->getDimensions(index, PT, &width, &height)) {
Andreas Hubereef3c332010-08-19 10:39:47 -0700427 width = -1;
428 height = -1;
429 }
430
431 int32_t encWidth, encHeight;
432 sp<ABuffer> codecSpecificData =
433 MakeAVCCodecSpecificData(params.c_str(), &encWidth, &encHeight);
434
435 if (codecSpecificData != NULL) {
436 if (width < 0) {
437 // If no explicit width/height given in the sdp, use the dimensions
438 // extracted from the first sequence parameter set.
439 width = encWidth;
440 height = encHeight;
441 }
442
443 mFormat->setData(
444 kKeyAVCC, 0,
445 codecSpecificData->data(), codecSpecificData->size());
446 } else if (width < 0) {
Andreas Huberaf063a62010-08-18 10:17:18 -0700447 mInitCheck = ERROR_UNSUPPORTED;
448 return;
449 }
Andreas Huber7a747b82010-06-07 15:19:40 -0700450
451 mFormat->setInt32(kKeyWidth, width);
452 mFormat->setInt32(kKeyHeight, height);
Andreas Huber57648e42010-08-04 10:14:30 -0700453 } else if (!strncmp(desc.c_str(), "H263-2000/", 10)
454 || !strncmp(desc.c_str(), "H263-1998/", 10)) {
455 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
Andreas Huber7a747b82010-06-07 15:19:40 -0700456
Andreas Huber57648e42010-08-04 10:14:30 -0700457 int32_t width, height;
Andreas Huberaf063a62010-08-18 10:17:18 -0700458 if (!sessionDesc->getDimensions(index, PT, &width, &height)) {
459 mInitCheck = ERROR_UNSUPPORTED;
460 return;
461 }
Andreas Huber57648e42010-08-04 10:14:30 -0700462
463 mFormat->setInt32(kKeyWidth, width);
464 mFormat->setInt32(kKeyHeight, height);
465 } else if (!strncmp(desc.c_str(), "MP4A-LATM/", 10)) {
Andreas Huber7a747b82010-06-07 15:19:40 -0700466 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
467
468 int32_t sampleRate, numChannels;
469 ASessionDescription::ParseFormatDesc(
470 desc.c_str(), &sampleRate, &numChannels);
471
472 mFormat->setInt32(kKeySampleRate, sampleRate);
473 mFormat->setInt32(kKeyChannelCount, numChannels);
474
475 sp<ABuffer> codecSpecificData =
476 MakeAACCodecSpecificData(params.c_str());
477
478 mFormat->setData(
479 kKeyESDS, 0,
480 codecSpecificData->data(), codecSpecificData->size());
Andreas Huber57648e42010-08-04 10:14:30 -0700481 } else if (!strncmp(desc.c_str(), "AMR/", 4)) {
482 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
483
484 int32_t sampleRate, numChannels;
485 ASessionDescription::ParseFormatDesc(
486 desc.c_str(), &sampleRate, &numChannels);
487
488 mFormat->setInt32(kKeySampleRate, sampleRate);
489 mFormat->setInt32(kKeyChannelCount, numChannels);
490
491 if (sampleRate != 8000 || numChannels != 1) {
492 mInitCheck = ERROR_UNSUPPORTED;
493 }
494 } else if (!strncmp(desc.c_str(), "AMR-WB/", 7)) {
495 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
496
497 int32_t sampleRate, numChannels;
498 ASessionDescription::ParseFormatDesc(
499 desc.c_str(), &sampleRate, &numChannels);
500
501 mFormat->setInt32(kKeySampleRate, sampleRate);
502 mFormat->setInt32(kKeyChannelCount, numChannels);
503
504 if (sampleRate != 16000 || numChannels != 1) {
505 mInitCheck = ERROR_UNSUPPORTED;
506 }
Andreas Hubera979ad62010-08-19 10:56:15 -0700507 } else if (!strncmp(desc.c_str(), "MP4V-ES/", 8)) {
508 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
509
510 int32_t width, height;
511 if (!sessionDesc->getDimensions(index, PT, &width, &height)) {
512 width = -1;
513 height = -1;
514 }
515
516 int32_t encWidth, encHeight;
517 sp<ABuffer> codecSpecificData =
518 MakeMPEG4VideoCodecSpecificData(
519 params.c_str(), &encWidth, &encHeight);
520
521 if (codecSpecificData != NULL) {
522 mFormat->setData(
523 kKeyESDS, 0,
524 codecSpecificData->data(), codecSpecificData->size());
525
526 if (width < 0) {
527 width = encWidth;
528 height = encHeight;
529 }
530 } else if (width < 0) {
531 mInitCheck = ERROR_UNSUPPORTED;
532 return;
533 }
534
535 mFormat->setInt32(kKeyWidth, width);
536 mFormat->setInt32(kKeyHeight, height);
Andreas Huber04072692011-02-15 10:39:48 -0800537 } else if (!strncasecmp(desc.c_str(), "mpeg4-generic/", 14)) {
Andreas Hubere536f802010-08-31 14:25:36 -0700538 AString val;
539 if (!GetAttribute(params.c_str(), "mode", &val)
540 || (strcasecmp(val.c_str(), "AAC-lbr")
541 && strcasecmp(val.c_str(), "AAC-hbr"))) {
542 mInitCheck = ERROR_UNSUPPORTED;
543 return;
544 }
545
546 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
547
548 int32_t sampleRate, numChannels;
549 ASessionDescription::ParseFormatDesc(
550 desc.c_str(), &sampleRate, &numChannels);
551
552 mFormat->setInt32(kKeySampleRate, sampleRate);
553 mFormat->setInt32(kKeyChannelCount, numChannels);
554
555 sp<ABuffer> codecSpecificData =
556 MakeAACCodecSpecificData2(params.c_str());
557
558 mFormat->setData(
559 kKeyESDS, 0,
560 codecSpecificData->data(), codecSpecificData->size());
Andreas Huberb6723732011-02-22 16:25:00 -0800561 } else if (ARawAudioAssembler::Supports(desc.c_str())) {
562 ARawAudioAssembler::MakeFormat(desc.c_str(), mFormat);
Andreas Huber7a747b82010-06-07 15:19:40 -0700563 } else {
Andreas Huber57648e42010-08-04 10:14:30 -0700564 mInitCheck = ERROR_UNSUPPORTED;
Andreas Huber7a747b82010-06-07 15:19:40 -0700565 }
566}
567
568APacketSource::~APacketSource() {
569}
570
Andreas Huber57648e42010-08-04 10:14:30 -0700571status_t APacketSource::initCheck() const {
572 return mInitCheck;
573}
574
Andreas Huber7a747b82010-06-07 15:19:40 -0700575sp<MetaData> APacketSource::getFormat() {
576 return mFormat;
577}
578
Andreas Huber7a747b82010-06-07 15:19:40 -0700579} // namespace android