MP4.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. #include "../../H/Misc/MP4.h"
  5. /******************************************************************************
  6. Documentation available here:
  7. http://l.web.umkc.edu/lizhu/teaching/2016sp.video-communication/ref/mp4.pdf
  8. /******************************************************************************/
  9. enum
  10. {
  11. #define COPYRIGHT_SYMBOL Char8(0xA9)
  12. CO64 =CC4('c','o','6','4'),
  13. CTTS =CC4('c','t','t','s'),
  14. ESDS =CC4('e','s','d','s'),
  15. FTYP =CC4('f','t','y','p'),
  16. GENRE2 =CC4('g','n','r','e'),
  17. MDHD =CC4('m','d','h','d'),
  18. MDIA =CC4('m','d','i','a'),
  19. MINF =CC4('m','i','n','f'),
  20. MOOF =CC4('m','o','o','f'),
  21. MOOV =CC4('m','o','o','v'),
  22. MP4A =CC4('m','p','4','a'),
  23. MVHD =CC4('m','v','h','d'),
  24. STBL =CC4('s','t','b','l'),
  25. STCO =CC4('s','t','c','o'),
  26. STSC =CC4('s','t','s','c'),
  27. STSD =CC4('s','t','s','d'),
  28. STSZ =CC4('s','t','s','z'),
  29. STTS =CC4('s','t','t','s'),
  30. STZ2 =CC4('s','t','z','2'),
  31. TFHD =CC4('t','f','h','d'),
  32. TKHD =CC4('t','k','h','d'),
  33. TRAF =CC4('t','r','a','f'),
  34. TRAK =CC4('t','r','a','k'),
  35. TRUN =CC4('t','r','u','n'),
  36. USER_DATA=CC4('u','d','t','a'),
  37. TITLE =CC4(COPYRIGHT_SYMBOL,'n','a','m'),
  38. ARTIST =CC4(COPYRIGHT_SYMBOL,'A','R','T'),
  39. WRITER =CC4(COPYRIGHT_SYMBOL,'w','r','t'),
  40. ALBUM =CC4(COPYRIGHT_SYMBOL,'a','l','b'),
  41. DATE =CC4(COPYRIGHT_SYMBOL,'d','a','y'),
  42. TOOL =CC4(COPYRIGHT_SYMBOL,'t','o','o'),
  43. COMMENT =CC4(COPYRIGHT_SYMBOL,'c','m','t'),
  44. GENRE1 =CC4(COPYRIGHT_SYMBOL,'g','e','n'),
  45. };
  46. /******************************************************************************/
  47. void MP4::zero() {time_scale=0; duration=-1;}
  48. MP4::MP4() {zero();}
  49. /******************************************************************************/
  50. Long MP4::Track::Part::dataSize()C
  51. {
  52. if(frame_sizes.elms())
  53. {
  54. Long size=0; REPA(frame_sizes)size+=frame_sizes[i]; return size;
  55. }
  56. return ULong(frames)*frame_size;
  57. }
  58. Int MP4::Track::frames()C
  59. {
  60. Int frames=0;
  61. if(stts.elms())REPA(stts )frames+=stts [i].count;
  62. else REPA(parts)frames+=parts[i].frames;
  63. return frames;
  64. }
  65. UInt MP4::Track::frameRangeSize(Int start, Int end)C
  66. {
  67. if(frame_size)return (end-start)*frame_size;
  68. MAX(start, 0);
  69. MIN(end , frame_sizes.elms());
  70. UInt size=0; for(; start<end; start++)size+=frame_sizes[start];
  71. return size;
  72. }
  73. Long MP4::Track::chunkOffset(Int i)C
  74. {
  75. return InRange(i, chunk_offset) ? chunk_offset[i] : 0;
  76. }
  77. void MP4::Track::frameChunk(Int frame, Int &chunk, Int &chunk_frame)C
  78. {
  79. Int chunk_i=1, frames=0; // start with 1 because MP4 has chunk indexes starting from 1
  80. if(stsc.elms())
  81. {
  82. UInt chunk_frames=stsc[0].frames_per_chunk;
  83. for(Int i=1; i<stsc.elms(); i++)
  84. {
  85. C STSC &next=stsc[i];
  86. Int chunks=next.first_chunk-chunk_i, end=frames+chunks*chunk_frames;
  87. if(frame<end)break;
  88. chunk_i =next.first_chunk;
  89. chunk_frames=next.frames_per_chunk;
  90. frames =end;
  91. }
  92. if(chunk_frames)
  93. {
  94. Int chunks=(frame-frames)/chunk_frames;
  95. chunk_i+=chunks;
  96. frames +=chunks*chunk_frames;
  97. }
  98. }
  99. chunk =chunk_i-1; // convert from 1 to 0 as the first index
  100. chunk_frame=frames;
  101. }
  102. C MP4::Track::Part* MP4::Track::findPart(Int &frame)C
  103. {
  104. FREPA(parts)
  105. {
  106. C Part &part=parts[i];
  107. if(InRange(frame, part.frames))return &part;
  108. frame-=part.frames;
  109. }
  110. return null;
  111. }
  112. Long MP4::Track::frameOffset(Int i)C
  113. {
  114. if(stsc.elms())
  115. {
  116. Int chunk, chunk_frame; frameChunk(i, chunk, chunk_frame);
  117. return chunkOffset(chunk)+frameRangeSize(chunk_frame, i);
  118. }
  119. if(C Part *part=findPart(i))
  120. {
  121. Long pos=part->pos;
  122. if(part->frame_sizes.elms())for(; --i>=0; )pos+=part->frame_sizes[i];
  123. else pos+=part->frame_size *i ;
  124. return pos;
  125. }
  126. return 0;
  127. }
  128. UInt MP4::Track::frameSize(Int i)C
  129. {
  130. if(InRange(i, frame_sizes))return frame_sizes[i];
  131. if(C Part *part=findPart(i))return part->frameSize(i);
  132. return frame_size;
  133. }
  134. Long MP4::Track::dataSize()C
  135. {
  136. Long size=0;
  137. if(frame_sizes.elms())
  138. {
  139. REPA(frame_sizes)size+=frame_sizes[i];
  140. }else
  141. if(parts.elms())
  142. {
  143. REPA(parts)size+=parts[i].dataSize();
  144. }else
  145. size=ULong(frames())*frame_size;
  146. return size;
  147. }
  148. MP4::Track* MP4::findTrack(Int id)
  149. {
  150. REPA(tracks)if(tracks[i].id==id)return &tracks[i];
  151. return null;
  152. }
  153. /******************************************************************************/
  154. static Bool ReadHeader(File &f, UInt &type, Long &size)
  155. {
  156. struct Header
  157. {
  158. UInt size, type;
  159. }header;
  160. if(!f.getFast(header))return false;
  161. switch(header.size)
  162. {
  163. case 0x00000000: size=f.left()+SIZE(header); break; // BigEndian 0 = to the end of the file (including size of the header)
  164. case 0x01000000: size=f.getBELong() ; break; // BigEndian 1 = 64-bit size
  165. default : SwapEndian(header.size); size=header.size; break;
  166. }
  167. if(size<0)return false;
  168. type=header.type;
  169. return true;
  170. }
  171. static UInt ReadDescLength(File &f)
  172. {
  173. Byte b;
  174. UInt i=0, length=0;
  175. do
  176. {
  177. b=f.getByte();
  178. length=(length<<7)|(b&0x7F);
  179. }while((b&0x80) && ++i<4);
  180. return length;
  181. }
  182. Bool MP4::read(File &f, Long max_pos, Track *track, Long moof_pos)
  183. {
  184. //ft.depth++;
  185. UInt tfhd_default_frame_duration=0, tfhd_default_frame_size=0;
  186. Long tfhd_base_data_offset=moof_pos;
  187. Long trun_data_offset=tfhd_base_data_offset;
  188. for(;;)
  189. {
  190. Long pos=f.pos(); if(pos>=max_pos)break; // reached the end for this parent
  191. UInt type; Long size; if(!ReadHeader(f, type, size))goto error;
  192. Long end=pos+size, data_pos=f.pos(), data_size=end-data_pos;
  193. #if DEBUG
  194. Char8 c[]={Char8(type&0xFF), Char8((type>>8)&0xFF), Char8((type>>16)&0xFF), Char8((type>>24)&0xFF)};
  195. //ft.startLine(); FREPA(c)ft.putChar(c[i]); ft.putText(S+" - "+data_pos+", "+data_size); ft.endLine();
  196. #endif
  197. switch(type)
  198. {
  199. // have children nodes
  200. case MOOV:
  201. case TRAK:
  202. case MDIA:
  203. case MINF:
  204. case STBL:
  205. case MOOF:
  206. case TRAF:
  207. #if 0 // not interested in
  208. case USER_DATA:
  209. case TITLE:
  210. case ARTIST:
  211. case WRITER:
  212. case ALBUM:
  213. case DATE:
  214. case TOOL:
  215. case COMMENT:
  216. case GENRE1:
  217. case GENRE2:
  218. #endif
  219. {
  220. if(!read(f, end, (type==TRAK) ? &tracks.New() : track, (type==MOOF) ? pos : moof_pos))goto error;
  221. }break;
  222. case MVHD:
  223. {
  224. switch(f.getByte()) // version
  225. {
  226. case 0:
  227. {
  228. UInt flags=f.getBEUInt24();
  229. UInt create_time=f.getBEUInt();
  230. UInt modify_time=f.getBEUInt();
  231. time_scale=f.getBEUInt();
  232. duration =f.getBEUInt(); if(duration==UINT_MAX)duration=-1;
  233. }break;
  234. }
  235. }break;
  236. case TKHD: if(track)
  237. {
  238. Byte ver =f.getByte();
  239. UInt flags=f.getBEUInt24();
  240. switch(ver)
  241. {
  242. case 0:
  243. {
  244. UInt create_time=f.getBEUInt();
  245. UInt modify_time=f.getBEUInt();
  246. track->id=f.getBEUInt();
  247. f.getBEUInt();
  248. track->duration=f.getBEUInt(); if(track->duration==UINT_MAX)track->duration=-1;
  249. }break;
  250. case 1:
  251. {
  252. ULong create_time=f.getBEULong();
  253. ULong modify_time=f.getBEULong();
  254. track->id=f.getBEUInt();
  255. f.getBEUInt();
  256. track->duration=f.getBELong();
  257. }break;
  258. }
  259. }break;
  260. case MDHD: if(track)
  261. {
  262. switch(f.getBEUInt()) // version
  263. {
  264. case 0:
  265. {
  266. UInt create_time=f.getBEUInt();
  267. UInt modify_time=f.getBEUInt();
  268. track->time_scale=f.getBEUInt();
  269. track->duration =f.getBEUInt(); if(track->duration==UINT_MAX)track->duration=-1;
  270. }break;
  271. case 1:
  272. {
  273. ULong create_time=f.getBEULong();
  274. ULong modify_time=f.getBEULong();
  275. track->time_scale=f.getBEUInt();
  276. track->duration =f.getBELong();
  277. }break;
  278. }
  279. }break;
  280. case STSD: if(track)
  281. {
  282. Byte ver=f.getByte(); if(ver==0)
  283. {
  284. UInt flags =f.getBEUInt24();
  285. UInt entry_count=f.getBEUInt();
  286. FREP(entry_count)
  287. {
  288. UInt type; Long size, pos=f.pos(); if(!ReadHeader(f, type, size))break;
  289. switch(type)
  290. {
  291. case MP4A:
  292. {
  293. f.skip(6); // reserved
  294. U16 data_reference_index=f.getBEUShort();
  295. f.getBEUInt();
  296. f.getBEUInt();
  297. track->channels=f.getBEUShort();
  298. UInt sample_size=f.getBEUShort();
  299. f.getBEUShort();
  300. f.getBEUShort();
  301. track->sample_rate=f.getBEUShort();
  302. f.getBEUShort();
  303. if(!ReadHeader(f, type, size))break;
  304. if(type==ESDS)
  305. {
  306. Byte ver=f.getByte(); if(ver==0)
  307. {
  308. UInt flags=f.getBEUInt24();
  309. Byte tag =f.getByte();
  310. if(tag==3)
  311. {
  312. if(ReadDescLength(f)<20)break;
  313. f.skip(3);
  314. }else f.skip(2);
  315. if(f.getByte()!=4)break;
  316. if(ReadDescLength(f)<13)break;
  317. Byte audio_type=f.getByte();
  318. f.getBEUInt();
  319. UInt max_bitrate=f.getBEUInt();
  320. track->avg_bit_rate=f.getBEUInt();
  321. if(f.getByte()!=5)break;
  322. UInt decoder_config_len=ReadDescLength(f);
  323. Mems<Byte> &decoder_config=track->decoder_config;
  324. decoder_config.setNum(decoder_config_len); if(!decoder_config.loadRawData(f)){decoder_config.clear(); break;}
  325. }
  326. }
  327. }break;
  328. }
  329. f.pos(pos+size);
  330. }
  331. }
  332. }break;
  333. case STSZ: if(track)
  334. {
  335. Byte ver=f.getByte(); if(ver==0)
  336. {
  337. UInt flags =f.getBEUInt24();
  338. track->frame_size =f.getBEUInt ();
  339. Mems<UInt> &frame_sizes=track->frame_sizes;
  340. if(track->frame_size==0)
  341. {
  342. frame_sizes.setNum(f.getBEUInt());
  343. frame_sizes.loadRawData(f);
  344. REPA(frame_sizes)SwapEndian(frame_sizes[i]);
  345. }else frame_sizes.clear();
  346. }
  347. }break;
  348. case STZ2:
  349. {
  350. }break;
  351. case STCO: if(track)
  352. {
  353. Byte ver=f.getByte(); if(ver==0)
  354. {
  355. UInt flags=f.getBEUInt24();
  356. Mems<Long> &chunk_offset=track->chunk_offset.setNum(f.getBEUInt());
  357. FREPAO(chunk_offset)=f.getBEUInt();
  358. }
  359. }break;
  360. case CO64: if(track)
  361. {
  362. Byte ver=f.getByte(); if(ver==0)
  363. {
  364. UInt flags=f.getBEUInt24();
  365. Mems<Long> &chunk_offset=track->chunk_offset.setNum(f.getBEUInt());
  366. chunk_offset.loadRawData(f); REPA(chunk_offset)SwapEndian(chunk_offset[i]);
  367. }
  368. }break;
  369. case STSC: if(track)
  370. {
  371. Byte ver=f.getByte(); if(ver==0)
  372. {
  373. UInt flags=f.getBEUInt24();
  374. Mems<Track::STSC> &stsc=track->stsc.setNum(f.getBEUInt());
  375. stsc.loadRawData(f); ASSERT(SIZE(Track::STSC)==12);
  376. REPA(stsc){Track::STSC &s=stsc[i]; SwapEndian(s.first_chunk); SwapEndian(s.frames_per_chunk); SwapEndian(s.frame_desc_index);}
  377. }
  378. }break;
  379. /* struct CTTS
  380. {
  381. UInt frame_count, frame_offset;
  382. };
  383. Mems<CTTS> ctts;
  384. case CTTS: if(track)
  385. {
  386. Byte ver=f.getByte(); if(ver==0)
  387. {
  388. UInt flags=f.getBEUInt24();
  389. Mems<Track::CTTS> &ctts=track->ctts.setNum(f.getBEUInt());
  390. ctts.loadRawData(f); ASSERT(SIZE(Track::CTTS)==8);
  391. REPA(ctts){Track::CTTS &s=ctts[i]; SwapEndian(s.frame_count); SwapEndian(s.frame_offset);}
  392. }
  393. }break; */
  394. case STTS: if(track)
  395. {
  396. Byte ver=f.getByte(); if(ver==0)
  397. {
  398. UInt flags=f.getBEUInt24();
  399. Mems<Track::STTS> &stts=track->stts.setNum(f.getBEUInt());
  400. stts.loadRawData(f); ASSERT(SIZE(Track::STTS)==8);
  401. REPA(stts){Track::STTS &s=stts[i]; SwapEndian(s.count); SwapEndian(s.delta);}
  402. }
  403. }break;
  404. // DASH
  405. case TFHD:
  406. {
  407. Byte ver =f.getByte();
  408. UInt flags=f.getBEUInt24();
  409. switch(ver)
  410. {
  411. case 0:
  412. {
  413. track=findTrack(f.getBEUInt()); // when encountering 'TFHD' then switch 'track' to the one from the header data in this level, so 'TRUN' can use it
  414. trun_data_offset=tfhd_base_data_offset=((flags&0x000001) ? f.getBELong() : moof_pos);
  415. if(flags&0x000002)UInt frame_description_index=f.getBEUInt();
  416. tfhd_default_frame_duration=((flags&0x000008) ? f.getBEUInt() : 0);
  417. tfhd_default_frame_size =((flags&0x000010) ? f.getBEUInt() : 0);
  418. if(flags&0x000020)UInt default_frame_flags=f.getBEUInt();
  419. }break;
  420. }
  421. }break;
  422. case TRUN: if(track) // 'track' should be available because this chunk is processed in the same level and after 'TFHD' which finds the track for us
  423. {
  424. Byte ver =f.getByte();
  425. UInt flags=f.getBEUInt24();
  426. switch(ver)
  427. {
  428. case 0:
  429. {
  430. if(UInt frame_count=f.getBEUInt())
  431. {
  432. if(flags&0x000001)trun_data_offset=tfhd_base_data_offset+f.getBEInt(); // if not present, then we have to reuse the last value
  433. if(flags&0x000004)UInt first_frame_flags=f.getBEUInt();
  434. Track::Part &part=track->parts.New();
  435. part.pos =trun_data_offset;
  436. part.frames =frame_count;
  437. part.frame_duration=tfhd_default_frame_duration;
  438. part.frame_size =tfhd_default_frame_size ;
  439. if(flags&0x000100)part.frame_durations.setNum(frame_count);
  440. if(flags&0x000200)part.frame_sizes .setNum(frame_count);
  441. FREP(frame_count)
  442. {
  443. UInt frame_duration=tfhd_default_frame_duration; if(flags&0x000100)part.frame_durations[i]=frame_duration=f.getBEUInt();
  444. UInt frame_size =tfhd_default_frame_size ; if(flags&0x000200)part.frame_sizes [i]=frame_size =f.getBEUInt();
  445. if(flags&0x000400)UInt frame_flags=f.getBEUInt();
  446. if(flags&0x000800)UInt frame_composition_time_offset=f.getBEUInt();
  447. trun_data_offset+=frame_size;
  448. }
  449. }
  450. }break;
  451. }
  452. }break;
  453. }
  454. if( f.pos()>end // if we're already after end
  455. || !f.pos(end))goto error; // or failed to skip
  456. }
  457. //ft.depth--;
  458. return true;
  459. error:
  460. //ft.depth--;
  461. return false;
  462. }
  463. Bool MP4::read(File &f)
  464. {
  465. tracks.clear();
  466. zero();
  467. return read(f, f.size(), null, 0);
  468. }
  469. /******************************************************************************/
  470. }
  471. /******************************************************************************/