mp4atom.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884
  1. /*
  2. * The contents of this file are subject to the Mozilla Public
  3. * License Version 1.1 (the "License"); you may not use this file
  4. * except in compliance with the License. You may obtain a copy of
  5. * the License at http://www.mozilla.org/MPL/
  6. *
  7. * Software distributed under the License is distributed on an "AS
  8. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9. * implied. See the License for the specific language governing
  10. * rights and limitations under the License.
  11. *
  12. * The Original Code is MPEG4IP.
  13. *
  14. * The Initial Developer of the Original Code is Cisco Systems Inc.
  15. * Portions created by Cisco Systems Inc. are
  16. * Copyright (C) Cisco Systems Inc. 2001 - 2004. All Rights Reserved.
  17. *
  18. * 3GPP features implementation is based on 3GPP's TS26.234-v5.60,
  19. * and was contributed by Ximpo Group Ltd.
  20. *
  21. * Portions created by Ximpo Group Ltd. are
  22. * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved.
  23. *
  24. * Portions created by Adnecto d.o.o. are
  25. * Copyright (C) Adnecto d.o.o. 2005. All Rights Reserved
  26. *
  27. * Contributor(s):
  28. * Dave Mackie [email protected]
  29. * Alix Marchandise-Franquet [email protected]
  30. * Ximpo Group Ltd. [email protected]
  31. * Danijel Kopcinovic [email protected]
  32. */
  33. #include "mp4common.h"
  34. #include "atoms.h"
  35. MP4AtomInfo::MP4AtomInfo(const char* name, bool mandatory, bool onlyOne)
  36. {
  37. m_name = name;
  38. m_mandatory = mandatory;
  39. m_onlyOne = onlyOne;
  40. m_count = 0;
  41. }
  42. MP4Atom::MP4Atom(const char* type)
  43. {
  44. SetType(type);
  45. m_unknownType = FALSE;
  46. m_pFile = NULL;
  47. m_start = 0;
  48. m_end = 0;
  49. m_size = 0;
  50. m_pParentAtom = NULL;
  51. m_depth = 0xFF;
  52. memset(m_extendedType, 0, sizeof(m_extendedType));
  53. }
  54. MP4Atom::~MP4Atom()
  55. {
  56. u_int32_t i;
  57. for (i = 0; i < m_pProperties.Size(); i++) {
  58. delete m_pProperties[i];
  59. }
  60. for (i = 0; i < m_pChildAtomInfos.Size(); i++) {
  61. delete m_pChildAtomInfos[i];
  62. }
  63. for (i = 0; i < m_pChildAtoms.Size(); i++) {
  64. delete m_pChildAtoms[i];
  65. }
  66. }
  67. MP4Atom* MP4Atom::CreateAtom(const char* type)
  68. {
  69. MP4Atom* pAtom = NULL;
  70. if (type == NULL) {
  71. pAtom = new MP4RootAtom();
  72. } else {
  73. switch((uint8_t)type[0]) {
  74. case 'a':
  75. if (ATOMID(type) == ATOMID("avc1")) {
  76. pAtom = new MP4Avc1Atom();
  77. } else if (ATOMID(type) == ATOMID("avcC")) {
  78. pAtom = new MP4AvcCAtom();
  79. } else if (ATOMID(type) == ATOMID("alis")) {
  80. pAtom = new MP4UrlAtom("alis");
  81. } else if (ATOMID(type) == ATOMID("alaw")) {
  82. pAtom = new MP4SoundAtom(type);
  83. } else if (ATOMID(type) == ATOMID("alac")) {
  84. pAtom = new MP4SoundAtom(type);
  85. } else if (ATOMID(type) == ATOMID("albm")) {
  86. pAtom = new MP4Meta3Atom(type);
  87. }
  88. break;
  89. case 'c':
  90. if (ATOMID(type) == ATOMID("chap")) {
  91. pAtom = new MP4TrefTypeAtom(type);
  92. } else if (ATOMID(type) == ATOMID("chpl")) {
  93. pAtom = new MP4ChplAtom();
  94. }
  95. break;
  96. case 'd':
  97. if (ATOMID(type) == ATOMID("d263")) {
  98. pAtom = new MP4D263Atom();
  99. } else if (ATOMID(type) == ATOMID("damr")) {
  100. pAtom = new MP4DamrAtom();
  101. } else if (ATOMID(type) == ATOMID("dref")) {
  102. pAtom = new MP4DrefAtom();
  103. } else if (ATOMID(type) == ATOMID("dpnd")) {
  104. pAtom = new MP4TrefTypeAtom(type);
  105. } else if (ATOMID(type) == ATOMID("data")) { /* Apple iTunes */
  106. pAtom = new MP4DataAtom();
  107. }
  108. break;
  109. case 'e':
  110. if (ATOMID(type) == ATOMID("elst")) {
  111. pAtom = new MP4ElstAtom();
  112. } else if (ATOMID(type) == ATOMID("enca")) {
  113. pAtom = new MP4EncaAtom();
  114. } else if (ATOMID(type) == ATOMID("encv")) {
  115. pAtom = new MP4EncvAtom();
  116. }
  117. break;
  118. case 'f':
  119. if (ATOMID(type) == ATOMID("free")) {
  120. pAtom = new MP4FreeAtom();
  121. } else if (ATOMID(type) == ATOMID("ftyp")) {
  122. pAtom = new MP4FtypAtom();
  123. }
  124. break;
  125. case 'g':
  126. if (ATOMID(type) == ATOMID("gmin")) {
  127. pAtom = new MP4GminAtom();
  128. }/* else if (ATOMID(type) == ATOMID("gnre")) { // TODO: benski look at atom_rtp for implementation of two atom types with same name
  129. pAtom = new MP4Meta3Atom(type);
  130. } */
  131. break;
  132. case 'h':
  133. if (ATOMID(type) == ATOMID("hdlr")) {
  134. pAtom = new MP4HdlrAtom();
  135. } else if (ATOMID(type) == ATOMID("hint")) {
  136. pAtom = new MP4TrefTypeAtom(type);
  137. } else if (ATOMID(type) == ATOMID("hnti")) {
  138. pAtom = new MP4HntiAtom();
  139. } else if (ATOMID(type) == ATOMID("hinf")) {
  140. pAtom = new MP4HinfAtom();
  141. } else if (ATOMID(type) == ATOMID("h263")) {
  142. pAtom = new MP4VideoAtom("h263");
  143. } else if (ATOMID(type) == ATOMID("href")) {
  144. pAtom = new MP4HrefAtom();
  145. }
  146. break;
  147. case 'i':
  148. if (ATOMID(type) == ATOMID("ipir")) {
  149. pAtom = new MP4TrefTypeAtom(type);
  150. } else if (ATOMID(type) == ATOMID("ima4")) {
  151. pAtom = new MP4SoundAtom("ima4");
  152. }
  153. break;
  154. case 'j':
  155. if (ATOMID(type) == ATOMID("jpeg")) {
  156. pAtom = new MP4VideoAtom("jpeg");
  157. }
  158. break;
  159. case 'm':
  160. if (ATOMID(type) == ATOMID("mdhd")) {
  161. pAtom = new MP4MdhdAtom();
  162. } else if (ATOMID(type) == ATOMID("mvhd")) {
  163. pAtom = new MP4MvhdAtom();
  164. } else if (ATOMID(type) == ATOMID("mdat")) {
  165. pAtom = new MP4MdatAtom();
  166. } else if (ATOMID(type) == ATOMID("mpod")) {
  167. pAtom = new MP4TrefTypeAtom(type);
  168. } else if (ATOMID(type) == ATOMID("mp4a")) {
  169. pAtom = new MP4SoundAtom("mp4a");
  170. } else if (ATOMID(type) == ATOMID("mp4s")) {
  171. pAtom = new MP4Mp4sAtom();
  172. } else if (ATOMID(type) == ATOMID("mp4v")) {
  173. pAtom = new MP4Mp4vAtom();
  174. } else if (ATOMID(type) == ATOMID("mean")) { // iTunes
  175. pAtom = new MP4Meta1Atom(type);
  176. }
  177. break;
  178. case 'n':
  179. if (ATOMID(type) == ATOMID("name")) { // iTunes
  180. pAtom = new MP4Meta1Atom(type);
  181. }
  182. break;
  183. case 'o':
  184. if (ATOMID(type) == ATOMID("ohdr")) {
  185. pAtom = new MP4OhdrAtom();
  186. }
  187. break;
  188. case 'p':
  189. if (ATOMID(type) == ATOMID("perf")) {
  190. pAtom = new MP4Meta3Atom(type);
  191. }
  192. break;
  193. case 'r':
  194. if (ATOMID(type) == ATOMID("rtp ")) {
  195. pAtom = new MP4RtpAtom();
  196. } else if (ATOMID(type) == ATOMID("raw ")) {
  197. pAtom = new MP4VideoAtom("raw ");
  198. }
  199. break;
  200. case 's':
  201. if (ATOMID(type) == ATOMID("s263")) {
  202. pAtom = new MP4S263Atom();
  203. } else if (ATOMID(type) == ATOMID("samr")) {
  204. pAtom = new MP4AmrAtom("samr");
  205. } else if (ATOMID(type) == ATOMID("sawb")) {
  206. pAtom = new MP4AmrAtom("sawb");
  207. } else if (ATOMID(type) == ATOMID("stbl")) {
  208. pAtom = new MP4StblAtom();
  209. } else if (ATOMID(type) == ATOMID("stsd")) {
  210. pAtom = new MP4StsdAtom();
  211. } else if (ATOMID(type) == ATOMID("stsz")) {
  212. pAtom = new MP4StszAtom();
  213. } else if (ATOMID(type) == ATOMID("stsc")) {
  214. pAtom = new MP4StscAtom();
  215. } else if (ATOMID(type) == ATOMID("stz2")) {
  216. pAtom = new MP4Stz2Atom();
  217. } else if (ATOMID(type) == ATOMID("stdp")) {
  218. pAtom = new MP4StdpAtom();
  219. } else if (ATOMID(type) == ATOMID("sdp ")) {
  220. pAtom = new MP4SdpAtom();
  221. } else if (ATOMID(type) == ATOMID("sync")) {
  222. pAtom = new MP4TrefTypeAtom(type);
  223. } else if (ATOMID(type) == ATOMID("skip")) {
  224. pAtom = new MP4FreeAtom();
  225. pAtom->SetType("skip");
  226. } else if (ATOMID(type) == ATOMID("sowt")) {
  227. pAtom = new MP4SoundAtom("sowt");
  228. }
  229. break;
  230. case 't':
  231. if (ATOMID(type) == ATOMID("text")) {
  232. pAtom = new MP4TextAtom();
  233. } else if (ATOMID(type) == ATOMID("tkhd")) {
  234. pAtom = new MP4TkhdAtom();
  235. } else if (ATOMID(type) == ATOMID("tfhd")) {
  236. pAtom = new MP4TfhdAtom();
  237. } else if (ATOMID(type) == ATOMID("trun")) {
  238. pAtom = new MP4TrunAtom();
  239. } else if (ATOMID(type) == ATOMID("twos")) {
  240. pAtom = new MP4SoundAtom("twos");
  241. } else if (ATOMID(type) == ATOMID("titl")) {
  242. pAtom = new MP4Meta3Atom(type);
  243. }
  244. break;
  245. case 'u':
  246. if (ATOMID(type) == ATOMID("udta")) {
  247. pAtom = new MP4UdtaAtom();
  248. } else if (ATOMID(type) == ATOMID("url ")) {
  249. pAtom = new MP4UrlAtom();
  250. } else if (ATOMID(type) == ATOMID("urn ")) {
  251. pAtom = new MP4UrnAtom();
  252. } else if (ATOMID(type) == ATOMID("ulaw")) {
  253. pAtom = new MP4SoundAtom("ulaw");
  254. }
  255. break;
  256. case 'v':
  257. if (ATOMID(type) == ATOMID("vmhd")) {
  258. pAtom = new MP4VmhdAtom();
  259. }
  260. break;
  261. case 'y':
  262. if (ATOMID(type) == ATOMID("yuv2")) {
  263. pAtom = new MP4VideoAtom("yuv2");
  264. }
  265. else if (ATOMID(type) == ATOMID("yrrc")) {
  266. pAtom = new MP4Meta4Atom(type);
  267. }
  268. break;
  269. case 'S':
  270. if (ATOMID(type) == ATOMID("SVQ3")) {
  271. pAtom = new MP4VideoAtom("SVQ3");
  272. } else if (ATOMID(type) == ATOMID("SMI ")) {
  273. pAtom = new MP4SmiAtom();
  274. }
  275. break;
  276. case 0251:
  277. static const char name[5]={'\xA9','n', 'a', 'm', '\0'};
  278. static const char cmt[5]={'\xA9','c', 'm', 't', '\0'};
  279. static const char cpy[5]={'\xA9','c', 'p', 'y', '\0'};
  280. static const char des[5]={'\xA9','d', 'e', 's','\0'};
  281. static const char prd[5]={'\xA9', 'p', 'r', 'd', '\0'};
  282. static const char lyr[5]={'\xA9', 'l', 'y', 'r', '\0'};
  283. if (ATOMID(type) == ATOMID(name) ||
  284. ATOMID(type) == ATOMID(cmt) ||
  285. ATOMID(type) == ATOMID(cpy) ||
  286. ATOMID(type) == ATOMID(prd) ||
  287. ATOMID(type) == ATOMID(des) ||
  288. ATOMID(type) == ATOMID(lyr)) {
  289. pAtom = new MP4Meta2Atom(type);
  290. }
  291. break;
  292. }
  293. }
  294. if (pAtom == NULL) {
  295. pAtom = new MP4StandardAtom(type);
  296. // unknown type is set by StandardAtom type
  297. }
  298. ASSERT(pAtom);
  299. return pAtom;
  300. }
  301. // generate a skeletal self
  302. void MP4Atom::Generate()
  303. {
  304. u_int32_t i;
  305. // for all properties
  306. for (i = 0; i < m_pProperties.Size(); i++) {
  307. // ask it to self generate
  308. m_pProperties[i]->Generate();
  309. }
  310. // for all mandatory, single child atom types
  311. for (i = 0; i < m_pChildAtomInfos.Size(); i++) {
  312. if (m_pChildAtomInfos[i]->m_mandatory
  313. && m_pChildAtomInfos[i]->m_onlyOne) {
  314. // create the mandatory, single child atom
  315. MP4Atom* pChildAtom =
  316. CreateAtom(m_pChildAtomInfos[i]->m_name);
  317. AddChildAtom(pChildAtom);
  318. // and ask it to self generate
  319. pChildAtom->Generate();
  320. }
  321. }
  322. }
  323. MP4Atom* MP4Atom::ReadAtom(MP4File* pFile, MP4Atom* pParentAtom)
  324. {
  325. u_int8_t hdrSize = 8;
  326. u_int8_t extendedType[16];
  327. u_int64_t pos = pFile->GetPosition();
  328. VERBOSE_READ(pFile->GetVerbosity(),
  329. printf("ReadAtom: pos = 0x"X64"\n", pos));
  330. u_int64_t dataSize = pFile->ReadUInt32();
  331. char type[5];
  332. pFile->ReadBytes((u_int8_t*)&type[0], 4);
  333. type[4] = '\0';
  334. // extended size
  335. if (dataSize == 1) {
  336. dataSize = pFile->ReadUInt64();
  337. hdrSize += 8;
  338. pFile->Check64BitStatus(type);
  339. }
  340. // extended type
  341. if (ATOMID(type) == ATOMID("uuid")) {
  342. pFile->ReadBytes(extendedType, sizeof(extendedType));
  343. hdrSize += sizeof(extendedType);
  344. }
  345. if (dataSize == 0) {
  346. // extends to EOF
  347. dataSize = pFile->GetSize() - pos;
  348. }
  349. dataSize -= hdrSize;
  350. VERBOSE_READ(pFile->GetVerbosity(),
  351. printf("ReadAtom: type = \"%s\" data-size = "U64" (0x"X64") hdr %u\n",
  352. type, dataSize, dataSize, hdrSize));
  353. if (pos + hdrSize + dataSize > pParentAtom->GetEnd()) {
  354. VERBOSE_ERROR(pFile->GetVerbosity(),
  355. printf("ReadAtom: invalid atom size, extends outside parent atom - skipping to end of \"%s\" \"%s\" "U64" vs "U64"\n",
  356. pParentAtom->GetType(), type,
  357. pos + hdrSize + dataSize,
  358. pParentAtom->GetEnd()));
  359. VERBOSE_READ(pFile->GetVerbosity(),
  360. printf("parent %s ("U64") pos "U64" hdr %d data "U64" sum "U64"\n",
  361. pParentAtom->GetType(),
  362. pParentAtom->GetEnd(),
  363. pos,
  364. hdrSize,
  365. dataSize,
  366. pos + hdrSize + dataSize));
  367. #if 0
  368. throw new MP4Error("invalid atom size", "ReadAtom");
  369. #else
  370. //pFile->SetPosition(pParentAtom->GetEnd());
  371. //return 0;
  372. // TODO: benski> we should re-enable this if we can find a good way to very that the datasize might be correct.
  373. // skip to end of atom
  374. dataSize = pParentAtom->GetEnd() - pos - hdrSize;
  375. #endif
  376. }
  377. MP4Atom* pAtom = CreateAtom(type);
  378. pAtom->SetFile(pFile);
  379. pAtom->SetStart(pos);
  380. pAtom->SetEnd(pos + hdrSize + dataSize);
  381. pAtom->SetSize(dataSize);
  382. if (ATOMID(type) == ATOMID("uuid")) {
  383. pAtom->SetExtendedType(extendedType);
  384. }
  385. if (pAtom->IsUnknownType()) {
  386. if (!IsReasonableType(pAtom->GetType())) {
  387. VERBOSE_READ(pFile->GetVerbosity(),
  388. printf("Warning: atom type %s is suspect\n", pAtom->GetType()));
  389. } else {
  390. VERBOSE_READ(pFile->GetVerbosity(),
  391. printf("Info: atom type %s is unknown\n", pAtom->GetType()));
  392. }
  393. if (dataSize > 0) {
  394. pAtom->AddProperty(
  395. new MP4BytesProperty("data", dataSize));
  396. }
  397. }
  398. pAtom->SetParentAtom(pParentAtom);
  399. pAtom->Read();
  400. return pAtom;
  401. }
  402. bool MP4Atom::IsReasonableType(const char* type)
  403. {
  404. for (u_int8_t i = 0; i < 4; i++) {
  405. if (iscntrl((unsigned char)type[i])) {
  406. return false;
  407. }
  408. if (i == 3 && type[i] == ' ') {
  409. continue;
  410. }
  411. return false;
  412. }
  413. return true;
  414. }
  415. // generic read
  416. void MP4Atom::Read()
  417. {
  418. ASSERT(m_pFile);
  419. if (ATOMID(m_type) != 0 && m_size > 1000000) {
  420. VERBOSE_READ(GetVerbosity(),
  421. printf("Warning: %s atom size "U64" is suspect\n",
  422. m_type, m_size));
  423. }
  424. ReadProperties();
  425. // read child atoms, if we expect there to be some
  426. if (m_pChildAtomInfos.Size() > 0) {
  427. ReadChildAtoms();
  428. }
  429. Skip(); // to end of atom
  430. }
  431. void MP4Atom::Skip()
  432. {
  433. if (m_pFile->GetPosition() != m_end) {
  434. VERBOSE_READ(m_pFile->GetVerbosity(),
  435. printf("Skip: "U64" bytes\n", m_end - m_pFile->GetPosition()));
  436. }
  437. m_pFile->SetPosition(m_end);
  438. }
  439. MP4Atom* MP4Atom::FindAtomMP4(const char* name)
  440. {
  441. if (!IsMe(name)) {
  442. return NULL;
  443. }
  444. if (!IsRootAtom()) {
  445. VERBOSE_FIND(m_pFile->GetVerbosity(),
  446. printf("FindAtomMP4: matched %s\n", name));
  447. name = MP4NameAfterFirst(name);
  448. // I'm the sought after atom
  449. if (name == NULL) {
  450. return this;
  451. }
  452. }
  453. // else it's one of my children
  454. return FindChildAtom(name);
  455. }
  456. bool MP4Atom::FindProperty(const char *name,
  457. MP4Property** ppProperty, u_int32_t* pIndex)
  458. {
  459. if (!IsMe(name)) {
  460. return false;
  461. }
  462. if (!IsRootAtom()) {
  463. VERBOSE_FIND(m_pFile->GetVerbosity(),
  464. printf("FindProperty: matched %s\n", name));
  465. name = MP4NameAfterFirst(name);
  466. // no property name given
  467. if (name == NULL) {
  468. return false;
  469. }
  470. }
  471. return FindContainedProperty(name, ppProperty, pIndex);
  472. }
  473. bool MP4Atom::IsMe(const char* name)
  474. {
  475. if (name == NULL) {
  476. return false;
  477. }
  478. // root atom always matches
  479. if (!strcmp(m_type, "")) {
  480. return true;
  481. }
  482. // check if our atom name is specified as the first component
  483. if (!MP4NameFirstMatches(m_type, name)) {
  484. return false;
  485. }
  486. return true;
  487. }
  488. MP4Atom* MP4Atom::FindChildAtom(const char* name)
  489. {
  490. u_int32_t atomIndex = 0;
  491. // get the index if we have one, e.g. moov.trak[2].mdia...
  492. (void)MP4NameFirstIndex(name, &atomIndex);
  493. // need to get to the index'th child atom of the right type
  494. for (u_int32_t i = 0; i < m_pChildAtoms.Size(); i++) {
  495. if (MP4NameFirstMatches(m_pChildAtoms[i]->GetType(), name)) {
  496. if (atomIndex == 0) {
  497. // this is the one, ask it to match
  498. return m_pChildAtoms[i]->FindAtomMP4(name);
  499. }
  500. atomIndex--;
  501. }
  502. }
  503. return NULL;
  504. }
  505. bool MP4Atom::FindContainedProperty(const char *name,
  506. MP4Property** ppProperty, u_int32_t* pIndex)
  507. {
  508. u_int32_t numProperties = m_pProperties.Size();
  509. u_int32_t i;
  510. // check all of our properties
  511. for (i = 0; i < numProperties; i++) {
  512. if (m_pProperties[i]->FindProperty(name, ppProperty, pIndex)) {
  513. return true;
  514. }
  515. }
  516. // not one of our properties,
  517. // presumably one of our children's properties
  518. // check child atoms...
  519. // check if we have an index, e.g. trak[2].mdia...
  520. u_int32_t atomIndex = 0;
  521. (void)MP4NameFirstIndex(name, &atomIndex);
  522. // need to get to the index'th child atom of the right type
  523. for (i = 0; i < m_pChildAtoms.Size(); i++) {
  524. if (MP4NameFirstMatches(m_pChildAtoms[i]->GetType(), name)) {
  525. if (atomIndex == 0) {
  526. // this is the one, ask it to match
  527. return m_pChildAtoms[i]->FindProperty(name, ppProperty, pIndex);
  528. }
  529. atomIndex--;
  530. }
  531. }
  532. VERBOSE_FIND(m_pFile->GetVerbosity(),
  533. printf("FindProperty: no match for %s\n", name));
  534. return false;
  535. }
  536. void MP4Atom::ReadProperties(u_int32_t startIndex, u_int32_t count)
  537. {
  538. u_int32_t numProperties = MIN(count, m_pProperties.Size() - startIndex);
  539. // read any properties of the atom
  540. for (u_int32_t i = startIndex; i < startIndex + numProperties; i++) {
  541. m_pProperties[i]->Read(m_pFile);
  542. if (m_pFile->GetPosition() > m_end) {
  543. VERBOSE_READ(GetVerbosity(),
  544. printf("ReadProperties: insufficient data for property: %s pos 0x"X64" atom end 0x"X64"\n",
  545. m_pProperties[i]->GetName(),
  546. m_pFile->GetPosition(), m_end));
  547. // benski> throw new MP4Error("atom is too small", "Atom ReadProperties");
  548. return;
  549. }
  550. }
  551. }
  552. void MP4Atom::ReadChildAtoms()
  553. {
  554. bool this_is_udta = ATOMID(m_type) == ATOMID("udta");
  555. VERBOSE_READ(GetVerbosity(),
  556. printf("ReadChildAtoms: of %s\n", m_type[0] ? m_type : "root"));
  557. for (u_int64_t position = m_pFile->GetPosition();
  558. position < m_end;
  559. position = m_pFile->GetPosition()) {
  560. // make sure that we have enough to read at least 8 bytes
  561. // size and type.
  562. if (m_end - position < 2 * sizeof(uint32_t)) {
  563. // if we're reading udta, it's okay to have 4 bytes of 0
  564. if (this_is_udta &&
  565. m_end - position == sizeof(uint32_t)) {
  566. u_int32_t mbz = m_pFile->ReadUInt32();
  567. if (mbz != 0) {
  568. VERBOSE_WARNING(GetVerbosity(),
  569. printf("Error: In udta atom, end value is not zero %x\n",
  570. mbz));
  571. }
  572. continue;
  573. }
  574. // otherwise, output a warning, but don't care
  575. VERBOSE_WARNING(GetVerbosity(),
  576. printf("Error: In %s atom, extra "D64" bytes at end of atom\n",
  577. m_type, (m_end - position)));
  578. for (uint64_t ix = 0; ix < m_end - position; ix++) {
  579. (void)m_pFile->ReadUInt8();
  580. }
  581. continue;
  582. }
  583. MP4Atom* pChildAtom = MP4Atom::ReadAtom(m_pFile, this);
  584. if (pChildAtom)
  585. {
  586. AddChildAtom(pChildAtom);
  587. MP4AtomInfo* pChildAtomInfo = FindAtomInfo(pChildAtom->GetType());
  588. // if child atom is of known type
  589. // but not expected here print warning
  590. if (pChildAtomInfo == NULL && !pChildAtom->IsUnknownType()) {
  591. VERBOSE_READ(GetVerbosity(),
  592. printf("Warning: In atom %s unexpected child atom %s\n",
  593. GetType(), pChildAtom->GetType()));
  594. }
  595. // if child atoms should have just one instance
  596. // and this is more than one, print warning
  597. if (pChildAtomInfo) {
  598. pChildAtomInfo->m_count++;
  599. if (pChildAtomInfo->m_onlyOne && pChildAtomInfo->m_count > 1) {
  600. VERBOSE_READ(GetVerbosity(),
  601. printf("Warning: In atom %s multiple child atoms %s\n",
  602. GetType(), pChildAtom->GetType()));
  603. }
  604. }
  605. }
  606. }
  607. // if mandatory child atom doesn't exist, print warning
  608. u_int32_t numAtomInfo = m_pChildAtomInfos.Size();
  609. for (u_int32_t i = 0; i < numAtomInfo; i++) {
  610. if (m_pChildAtomInfos[i]->m_mandatory
  611. && m_pChildAtomInfos[i]->m_count == 0) {
  612. VERBOSE_READ(GetVerbosity(),
  613. printf("Warning: In atom %s missing child atom %s\n",
  614. GetType(), m_pChildAtomInfos[i]->m_name));
  615. }
  616. }
  617. VERBOSE_READ(GetVerbosity(),
  618. printf("ReadChildAtoms: finished %s\n", m_type));
  619. }
  620. MP4AtomInfo* MP4Atom::FindAtomInfo(const char* name)
  621. {
  622. u_int32_t numAtomInfo = m_pChildAtomInfos.Size();
  623. for (u_int32_t i = 0; i < numAtomInfo; i++) {
  624. if (ATOMID(m_pChildAtomInfos[i]->m_name) == ATOMID(name)) {
  625. return m_pChildAtomInfos[i];
  626. }
  627. }
  628. return NULL;
  629. }
  630. // generic write
  631. void MP4Atom::Write()
  632. {
  633. ASSERT(m_pFile);
  634. BeginWrite();
  635. WriteProperties();
  636. WriteChildAtoms();
  637. FinishWrite();
  638. }
  639. void MP4Atom::Rewrite()
  640. {
  641. ASSERT(m_pFile);
  642. if (!m_end) {
  643. // This atom hasn't been written yet...
  644. return;
  645. }
  646. u_int64_t fPos = m_pFile->GetPosition();
  647. m_pFile->SetPosition(GetStart());
  648. Write();
  649. m_pFile->SetPosition(fPos);
  650. }
  651. void MP4Atom::BeginWrite(bool use64)
  652. {
  653. m_start = m_pFile->GetPosition();
  654. //use64 = m_pFile->Use64Bits();
  655. if (use64) {
  656. m_pFile->WriteUInt32(1);
  657. } else {
  658. m_pFile->WriteUInt32(0);
  659. }
  660. m_pFile->WriteBytes((u_int8_t*)&m_type[0], 4);
  661. if (use64) {
  662. m_pFile->WriteUInt64(0);
  663. }
  664. if (ATOMID(m_type) == ATOMID("uuid")) {
  665. m_pFile->WriteBytes(m_extendedType, sizeof(m_extendedType));
  666. }
  667. }
  668. void MP4Atom::FinishWrite(bool use64)
  669. {
  670. m_end = m_pFile->GetPosition();
  671. m_size = (m_end - m_start);
  672. VERBOSE_WRITE(GetVerbosity(),
  673. printf("end: type %s "U64" "U64" size "U64"\n", m_type,
  674. m_start, m_end,
  675. m_size));
  676. //use64 = m_pFile->Use64Bits();
  677. if (use64) {
  678. m_pFile->SetPosition(m_start + 8);
  679. m_pFile->WriteUInt64(m_size);
  680. } else {
  681. ASSERT(m_size <= (u_int64_t)0xFFFFFFFF);
  682. m_pFile->SetPosition(m_start);
  683. m_pFile->WriteUInt32(m_size);
  684. }
  685. m_pFile->SetPosition(m_end);
  686. // adjust size to just reflect data portion of atom
  687. m_size -= (use64 ? 16 : 8);
  688. if (ATOMID(m_type) == ATOMID("uuid")) {
  689. m_size -= sizeof(m_extendedType);
  690. }
  691. }
  692. void MP4Atom::WriteProperties(u_int32_t startIndex, u_int32_t count)
  693. {
  694. u_int32_t numProperties = MIN(count, m_pProperties.Size() - startIndex);
  695. VERBOSE_WRITE(GetVerbosity(),
  696. printf("Write: type %s\n", m_type));
  697. for (u_int32_t i = startIndex; i < startIndex + numProperties; i++) {
  698. m_pProperties[i]->Write(m_pFile);
  699. }
  700. }
  701. void MP4Atom::WriteChildAtoms()
  702. {
  703. u_int32_t size = m_pChildAtoms.Size();
  704. for (u_int32_t i = 0; i < size; i++) {
  705. m_pChildAtoms[i]->Write();
  706. }
  707. VERBOSE_WRITE(GetVerbosity(),
  708. printf("Write: finished %s\n", m_type));
  709. }
  710. void MP4Atom::AddProperty(MP4Property* pProperty)
  711. {
  712. ASSERT(pProperty);
  713. m_pProperties.Add(pProperty);
  714. pProperty->SetParentAtom(this);
  715. }
  716. void MP4Atom::AddVersionAndFlags()
  717. {
  718. AddProperty(new MP4Integer8Property("version"));
  719. AddProperty(new MP4Integer24Property("flags"));
  720. }
  721. void MP4Atom::AddReserved(char* name, u_int32_t size)
  722. {
  723. MP4BytesProperty* pReserved = new MP4BytesProperty(name, size);
  724. pReserved->SetReadOnly();
  725. AddProperty(pReserved);
  726. }
  727. void MP4Atom::ExpectChildAtom(const char* name, bool mandatory, bool onlyOne)
  728. {
  729. m_pChildAtomInfos.Add(new MP4AtomInfo(name, mandatory, onlyOne));
  730. }
  731. u_int8_t MP4Atom::GetVersion()
  732. {
  733. if (strcmp("version", m_pProperties[0]->GetName())) {
  734. return 0;
  735. }
  736. return ((MP4Integer8Property*)m_pProperties[0])->GetValue();
  737. }
  738. void MP4Atom::SetVersion(u_int8_t version)
  739. {
  740. if (strcmp("version", m_pProperties[0]->GetName())) {
  741. return;
  742. }
  743. ((MP4Integer8Property*)m_pProperties[0])->SetValue(version);
  744. }
  745. u_int32_t MP4Atom::GetFlags()
  746. {
  747. if (strcmp("flags", m_pProperties[1]->GetName())) {
  748. return 0;
  749. }
  750. return ((MP4Integer24Property*)m_pProperties[1])->GetValue();
  751. }
  752. void MP4Atom::SetFlags(u_int32_t flags)
  753. {
  754. if (strcmp("flags", m_pProperties[1]->GetName())) {
  755. return;
  756. }
  757. ((MP4Integer24Property*)m_pProperties[1])->SetValue(flags);
  758. }
  759. u_int32_t MP4Atom::GetVerbosity()
  760. {
  761. ASSERT(m_pFile);
  762. return m_pFile->GetVerbosity();
  763. }
  764. u_int8_t MP4Atom::GetDepth()
  765. {
  766. if (m_depth < 0xFF) {
  767. return m_depth;
  768. }
  769. MP4Atom *pAtom = this;
  770. m_depth = 0;
  771. while ((pAtom = pAtom->GetParentAtom()) != NULL) {
  772. m_depth++;
  773. ASSERT(m_depth < 255);
  774. }
  775. return m_depth;
  776. }