mov.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:40k
源码类别:

Windows CE

开发平台:

C/C++

  1. /*****************************************************************************
  2.  *
  3.  * This program is free software ; you can redistribute it and/or modify
  4.  * it under the terms of the GNU General Public License as published by
  5.  * the Free Software Foundation; either version 2 of the License, or
  6.  * (at your option) any later version.
  7.  *
  8.  * This program is distributed in the hope that it will be useful,
  9.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11.  * GNU General Public License for more details.
  12.  *
  13.  * You should have received a copy of the GNU General Public License
  14.  * along with this program; if not, write to the Free Software
  15.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  16.  *
  17.  * $Id: mov.c 607 2006-01-22 20:58:29Z picard $
  18.  *
  19.  * The Core Pocket Media Player
  20.  * Copyright (c) 2004-2005 Gabor Kovacs
  21.  *
  22.  ****************************************************************************/
  23. #include "../common/common.h"
  24. #include "../common/zlib/zlib.h"
  25. #include "mov.h"
  26. #include "movpal.h"
  27. #define MP4_INVALID_AUDIO_TYPE          0x00
  28. #define MP4_MPEG1_AUDIO_TYPE            0x6B
  29. #define MP4_MPEG2_AUDIO_TYPE            0x69
  30. #define MP4_MPEG2_AAC_MAIN_AUDIO_TYPE   0x66
  31. #define MP4_MPEG2_AAC_LC_AUDIO_TYPE     0x67
  32. #define MP4_MPEG2_AAC_SSR_AUDIO_TYPE    0x68
  33. #define MP4_MPEG4_AUDIO_TYPE            0x40
  34. #define MP4_PRIVATE_AUDIO_TYPE          0xE0
  35. #define MP4_INVALID_VIDEO_TYPE          0x00
  36. #define MP4_MPEG1_VIDEO_TYPE            0x6A
  37. #define MP4_MPEG2_SIMPLE_VIDEO_TYPE     0x60
  38. #define MP4_MPEG2_MAIN_VIDEO_TYPE       0x61
  39. #define MP4_MPEG2_SNR_VIDEO_TYPE        0x62
  40. #define MP4_MPEG2_SPATIAL_VIDEO_TYPE    0x63
  41. #define MP4_MPEG2_HIGH_VIDEO_TYPE       0x64
  42. #define MP4_MPEG2_442_VIDEO_TYPE        0x65
  43. #define MP4_MPEG4_VIDEO_TYPE            0x20
  44. #define MP4_JPEG_VIDEO_TYPE             0x6C
  45. typedef struct mp4stsc
  46. {
  47. int FirstChunk;
  48. int Samples;
  49. } mp4stsc;
  50. typedef struct mp4stts
  51. {
  52. int Count;
  53. int Delta;
  54. } mp4stts;
  55. typedef struct mp4streampos
  56. {
  57. int CurrentTime;
  58. int SampleNo;
  59. int SamplesLeft;
  60. int STSSDelta;
  61. int STSSValue;
  62. int STSZDelta;
  63. int STSZValue;
  64. int STTSLeft;
  65. const uint8_t* STSSPos;
  66. const uint8_t* STSSEnd;
  67. const mp4stts* STTSPos;
  68. const mp4stsc* STSCPos;
  69. const uint8_t* STSZPos;
  70. const uint8_t* STSZEnd;
  71. const int* STCOPos;
  72. } mp4streampos;
  73. typedef struct mp4stream
  74. {
  75. format_stream Stream;
  76. tick_t Duration;
  77. int TimeScale;
  78. int SamplesPerPacket;
  79. int BytesPerPacket;
  80. bool_t AllKey;
  81. filepos_t OffsetMin;
  82. filepos_t OffsetMax;
  83. int StartTime;
  84. mp4streampos Pos;
  85. int STSZDef; //default sample size
  86. array STSS; //key samples (compressed)
  87. array STSZ; //sample size (compressed)
  88. array STTS; //sample duration (mp4stts) + delimiter
  89. array STSC; //sample per chunk (mp4stsc) + delimiter
  90. array STCO; //chunk offset (int) + delimiter
  91. } mp4stream;
  92. typedef struct mp4
  93. {
  94. format_base Format;
  95. uint32_t Type;
  96. uint32_t CompressType;
  97. boolmem_t ErrorShowed;
  98. boolmem_t MOOVFound;
  99. boolmem_t RMRAFound;
  100. int TimeScale;
  101. mp4stream* Track;
  102. tchar_t Meta[32];
  103. } mp4;
  104. typedef void (*mp4atomfunc)(mp4* p, filepos_t EndOfAtom);
  105. typedef struct mp4atomtable
  106. {
  107. uint32_t Atom;
  108. mp4atomfunc Func;
  109. } mp4atomtable;
  110. typedef struct mp4atom
  111. {
  112. uint32_t Atom;
  113. filepos_t EndOfAtom;
  114. } mp4atom;
  115. static int ReadVersion(format_reader* Reader)
  116. {
  117. int Ver = Reader->Read8(Reader);
  118. Reader->Skip(Reader,3); //flags;
  119. return Ver;
  120. }
  121. static bool_t ReadAtom(format_reader* Reader, mp4atom* Atom)
  122. {
  123. filepos_t Size;
  124. Atom->Atom = 0;
  125. Atom->EndOfAtom = Reader->FilePos;
  126. Size = Reader->ReadBE32(Reader);
  127. Reader->Read(Reader,&Atom->Atom,sizeof(Atom->Atom));
  128. if (Size == 1)
  129. Size = (filepos_t)Reader->ReadBE64(Reader);
  130. Atom->EndOfAtom += Size;
  131. return Size >= 8;
  132. }
  133. static void ReadSubAtoms(mp4* p,filepos_t EndOfAtom);
  134. static INLINE format_reader* Reader(mp4* p) { return p->Format.Reader; }
  135. static void ReadFTYP(mp4* p, filepos_t EndOfAtom)
  136. {
  137. p->Type = 0;
  138. Reader(p)->Read(Reader(p),&p->Type,sizeof(p->Type));
  139. }
  140. static void ReadRMRA(mp4* p, filepos_t EndOfAtom)
  141. {
  142. p->RMRAFound = 1;
  143. ReadSubAtoms(p,EndOfAtom);
  144. p->RMRAFound = 0;
  145. }
  146. static void ReadMOOV(mp4* p, filepos_t EndOfAtom)
  147. {
  148. p->MOOVFound = 1;
  149. ReadSubAtoms(p,EndOfAtom);
  150. }
  151. static INLINE const uint8_t* ReadValue(const uint8_t* p,const uint8_t* pe,int* Delta,int* Value,bool_t Alternate)
  152. {
  153. if (p>=pe)
  154. *Value = 0;
  155. else
  156. {
  157. int i = *(int8_t*)(p++);
  158. while (!(i & 1))
  159. i = (i<<7) | *(p++);
  160. i >>= 1;
  161. if (Alternate) *Delta = -*Delta;
  162. *Delta += i;
  163. *Value += *Delta;
  164. }
  165. return p;
  166. }
  167. static void WriteValue(array* Array,int* Delta,int* Value,int i,bool_t Alternate)
  168. {
  169. uint8_t Data[8];
  170. int n,Flag = 1;
  171. i -= *Value;
  172. *Value += i;
  173. if (Alternate) *Delta = -*Delta;
  174. i -= *Delta;
  175. *Delta += i;
  176. for (n=7;i>=64||i<-64;i>>=7,--n)
  177. {
  178. Data[n] = (uint8_t)(((i & 127) << 1)|Flag);
  179. Flag = 0;
  180. }
  181. Data[n] = (uint8_t)((i << 1)|Flag);
  182. ArrayAppend(Array,Data+n,8-n,1024);
  183. }
  184. static NOINLINE void NextKey(mp4streampos* Pos)
  185. {
  186. if (!Pos->STSSPos)
  187. ++Pos->STSSValue;
  188. else
  189. Pos->STSSPos = ReadValue(Pos->STSSPos,Pos->STSSEnd,&Pos->STSSDelta,&Pos->STSSValue,0);
  190. }
  191. static int NextSample(mp4stream* Stream,mp4streampos* Pos)
  192. {
  193. if (Stream->Stream.Fragmented || Stream->Stream.ForceMerge)
  194. {
  195. int n,i;
  196. for (n=Pos->SamplesLeft;n>0;n-=i)
  197. {
  198. if (!Pos->STTSLeft)
  199. Pos->STTSLeft = (++Pos->STTSPos)->Count;
  200. i = min(Pos->STTSLeft,n);
  201. Pos->STTSLeft -= i;
  202. Pos->CurrentTime += i*Pos->STTSPos->Delta;
  203. }
  204. n = Pos->SamplesLeft;
  205. Pos->SampleNo += n;
  206. Pos->SamplesLeft = 0;
  207. if (Stream->STSZDef==1 && Stream->SamplesPerPacket && Stream->BytesPerPacket)
  208. return Scale(n,Stream->BytesPerPacket,Stream->SamplesPerPacket);
  209. return Stream->STSZDef*n;
  210. }
  211. else
  212. {
  213. if (!Pos->STTSLeft)
  214. Pos->STTSLeft = (++Pos->STTSPos)->Count;
  215. --Pos->STTSLeft;
  216. ++Pos->SampleNo;
  217. --Pos->SamplesLeft;
  218. Pos->CurrentTime += Pos->STTSPos->Delta;
  219. if (!Stream->STSZDef)
  220. Pos->STSZPos = ReadValue(Pos->STSZPos,Pos->STSZEnd,&Pos->STSZDelta,&Pos->STSZValue,1);
  221. return Pos->STSZValue;
  222. }
  223. }
  224. static void NextChunk(mp4stream* Stream,mp4streampos* Pos)
  225. {
  226. // return sample count in chunk and step to next chunk
  227. do
  228. {
  229. int Chunk = Pos->STCOPos - ARRAYBEGIN(Stream->STCO,int);
  230. while (Pos->STSCPos[1].FirstChunk <= Chunk)
  231. ++Pos->STSCPos;
  232. ++Pos->STCOPos;
  233. Pos->SamplesLeft = Pos->STSCPos->Samples;
  234. } while (Pos->SamplesLeft <= 0);
  235. }
  236. static void Head(mp4stream* Stream,mp4streampos* Pos)
  237. {
  238. Pos->SampleNo = 0;
  239. Pos->CurrentTime = Stream->StartTime;
  240. Pos->SamplesLeft = 0;
  241. Pos->STTSLeft = 0;
  242. Pos->STSSDelta = 0;
  243. Pos->STSSValue = 0;
  244. Pos->STSZDelta = 0;
  245. Pos->STSZValue = 0;
  246. Pos->STSSPos = ARRAYBEGIN(Stream->STSS,uint8_t);
  247. Pos->STSSEnd = ARRAYEND(Stream->STSS,uint8_t);
  248. Pos->STTSPos = ARRAYBEGIN(Stream->STTS,mp4stts);
  249. Pos->STSCPos = ARRAYBEGIN(Stream->STSC,mp4stsc);
  250. Pos->STSZPos = ARRAYBEGIN(Stream->STSZ,uint8_t);
  251. Pos->STSZEnd = ARRAYEND(Stream->STSZ,uint8_t);
  252. Pos->STCOPos = ARRAYBEGIN(Stream->STCO,int);
  253. if (Pos->STTSPos)
  254. Pos->STTSLeft = Pos->STTSPos->Count;
  255. if (Stream->STSZDef)
  256. Pos->STSZValue = Stream->STSZDef;
  257. if (Pos->STSSPos)
  258. NextKey(Pos);
  259. else
  260. if (Stream->AllKey)
  261. Pos->STSSValue = 0;
  262. else
  263. Pos->STSSValue = -1;
  264. }
  265. static int GetFrames(mp4stream* Stream)
  266. {
  267. const mp4stsc* i;
  268. int Frames = 0;
  269. int Chunks = ARRAYCOUNT(Stream->STCO,int)-1; //minus delimier
  270. for (i=ARRAYBEGIN(Stream->STSC,mp4stsc);i!=ARRAYEND(Stream->STSC,mp4stsc)-1;++i)
  271. {
  272. int Next = min(Chunks,i[1].FirstChunk);
  273. if (Next > i->FirstChunk)
  274. Frames += i->Samples * (Next - i->FirstChunk);
  275. }
  276. return Frames;
  277. }
  278. static void ReadTRAK(mp4* p,filepos_t EndOfAtom)
  279. {
  280. mp4stream* Stream;
  281. p->Track = (mp4stream*) Format_AddStream(&p->Format,sizeof(mp4stream));
  282. p->Track->OffsetMin = MAX_INT;
  283. p->Track->OffsetMax = 0;
  284. ReadSubAtoms(p,EndOfAtom);
  285. Stream = p->Track;
  286. if (Stream)
  287. {
  288. if (ARRAYEMPTY(Stream->STCO) || ARRAYEMPTY(Stream->STTS) || ARRAYEMPTY(Stream->STSC))
  289. Format_RemoveStream(&p->Format);
  290. else
  291. {
  292. if (Stream->Stream.Format.Type == PACKET_VIDEO && Stream->Duration>0)
  293. {
  294. // calc FPS
  295. Stream->Stream.Format.PacketRate.Num = Scale(GetFrames(Stream),TICKSPERSEC*1000,Stream->Duration);
  296. Stream->Stream.Format.PacketRate.Den = 1000;
  297. if (Stream->Stream.Format.PacketRate.Num < 1000) // slideshow or podcast?
  298. Stream->Stream.Format.Format.Video.Pixel.Flags |= PF_NOPREROTATE;
  299. }
  300. //todo: calc ByteRate
  301. Head(Stream,&Stream->Pos);
  302. Format_PrepairStream(&p->Format,&Stream->Stream);
  303. }
  304. p->Track = NULL;
  305. }
  306. }
  307. static void ReadMETA(mp4* p,filepos_t EndOfAtom)
  308. {
  309. ReadVersion(Reader(p));
  310. ReadSubAtoms(p,EndOfAtom);
  311. }
  312. static void ReadSTSS(mp4* p,filepos_t EndOfAtom)
  313. {
  314. mp4stream* Stream = p->Track;
  315. int Count;
  316. int Delta,Value;
  317. if (!Stream || Stream->Stream.Fragmented) return;
  318. ReadVersion(Reader(p));
  319. Count = Reader(p)->ReadBE32(Reader(p));
  320. if (Count <= 1 && Stream->Stream.Format.Type == PACKET_VIDEO &&
  321. Stream->Stream.Format.Format.Video.Pixel.FourCC == FOURCC('S','2','6','3'))
  322. {
  323. // assume all frames as keyframes
  324. Stream->AllKey = 1;
  325. return;
  326. }
  327. ArrayClear(&Stream->STSS);
  328. ArrayAlloc(&Stream->STSS,Count+128,1024);
  329. Delta = Value = 0;
  330. while (Count-->0)
  331. WriteValue(&Stream->STSS,&Delta,&Value,Reader(p)->ReadBE32(Reader(p))-1,0);
  332. ArrayLock(&Stream->STSS);
  333. }
  334. static void ReadSTSC(mp4* p,filepos_t EndOfAtom)
  335. {
  336. mp4stream* Stream = p->Track;
  337. int Count;
  338. if (!Stream) return;
  339. ReadVersion(Reader(p));
  340. Count = Reader(p)->ReadBE32(Reader(p));
  341. ArrayClear(&Stream->STSC);
  342. if (ArrayAppend(&Stream->STSC,NULL,sizeof(mp4stsc)*(Count+1),1))
  343. {
  344. mp4stsc* se = ARRAYEND(Stream->STSC,mp4stsc)-1;
  345. mp4stsc* s;
  346. for (s=ARRAYBEGIN(Stream->STSC,mp4stsc);s!=se;++s)
  347. {
  348. s->FirstChunk = Reader(p)->ReadBE32(Reader(p))-1; 
  349. s->Samples = Reader(p)->ReadBE32(Reader(p));
  350. Reader(p)->ReadBE32(Reader(p)); // desc
  351. }
  352. s->FirstChunk = MAX_INT; // delimiter
  353. s->Samples = 0;
  354. ArrayLock(&Stream->STSC);
  355. }
  356. }
  357. static void ReadSTCO(mp4* p,filepos_t EndOfAtom)
  358. {
  359. mp4stream* Stream = p->Track;
  360. int Count;
  361. if (!Stream) return;
  362. ReadVersion(Reader(p));
  363. Count = Reader(p)->ReadBE32(Reader(p));
  364. ArrayClear(&Stream->STCO);
  365. if (ArrayAppend(&Stream->STCO,NULL,sizeof(int)*(Count+1),1))
  366. {
  367. int* ce = ARRAYEND(Stream->STCO,int)-1;
  368. int* c;
  369. for (c=ARRAYBEGIN(Stream->STCO,int);c!=ce;++c)
  370. {
  371. *c = Reader(p)->ReadBE32(Reader(p));
  372. // skip first and last chunks (some crappy encoders make bad interleaving, but leaving the last chunk at file end)
  373. if (Count<3 || (c!=ARRAYBEGIN(Stream->STCO,int) && c!=ce-1))
  374. {
  375. if (Stream->OffsetMin > *c)
  376. Stream->OffsetMin = *c;
  377. if (Stream->OffsetMax < *c)
  378. Stream->OffsetMax = *c;
  379. }
  380. }
  381. *c = MAX_INT;
  382. ArrayLock(&Stream->STCO);
  383. }
  384. }
  385. static void ReadCTTS(mp4* p,filepos_t EndOfAtom)
  386. {
  387. // presentation time offset (TCPMP only handles decoding time at the moment)
  388. mp4stream* Stream = p->Track;
  389. int Count;
  390. if (!Stream) return;
  391. ReadVersion(Reader(p));
  392. Count = Reader(p)->ReadBE32(Reader(p));
  393. if (Count>0)
  394. {
  395. int Offset;
  396. int Min = MAX_INT;
  397. while (Count-->0)
  398. {
  399. Reader(p)->ReadBE32(Reader(p)); // samples
  400. Offset = Reader(p)->ReadBE32(Reader(p));
  401. if (Min > Offset)
  402. Min = Offset;
  403. }
  404. if (Min>0 && Min<Stream->TimeScale)
  405. Stream->StartTime = Min;
  406. }
  407. }
  408. static void ReadSTSZ(mp4* p,filepos_t EndOfAtom)
  409. {
  410. mp4stream* Stream = p->Track;
  411. int Count;
  412. if (!Stream) return;
  413. ReadVersion(Reader(p));
  414. Stream->STSZDef = Reader(p)->ReadBE32(Reader(p));
  415. Count = Reader(p)->ReadBE32(Reader(p));
  416. if (!Stream->STSZDef)
  417. {
  418. int Delta,Value;
  419. Stream->Stream.Fragmented = 0;
  420. ArrayClear(&Stream->STSZ);
  421. ArrayAlloc(&Stream->STSZ,(Stream->Stream.Format.Type==PACKET_VIDEO?2*Count:Count)+1024,1024);
  422. Delta = Value = 0;
  423. while (Count-->0)
  424. WriteValue(&Stream->STSZ,&Delta,&Value,Reader(p)->ReadBE32(Reader(p)),1);
  425. ArrayLock(&Stream->STSZ);
  426. }
  427. else
  428. if (Stream->STSZDef==1)
  429. Stream->Stream.Fragmented = 1;
  430. }
  431. static void ReadSTTS(mp4* p,filepos_t EndOfAtom)
  432. {
  433. mp4stream* Stream = p->Track;
  434. int Count;
  435. if (!Stream) return;
  436. ReadVersion(Reader(p));
  437. Count = Reader(p)->ReadBE32(Reader(p));
  438. ArrayClear(&Stream->STTS);
  439. if (ArrayAppend(&Stream->STTS,NULL,sizeof(mp4stts)*(Count+1),1))
  440. {
  441. mp4stts* se = ARRAYEND(Stream->STTS,mp4stts)-1;
  442. mp4stts* s;
  443. for (s=ARRAYBEGIN(Stream->STTS,mp4stts);s!=se;++s)
  444. {
  445. s->Count = Reader(p)->ReadBE32(Reader(p)); 
  446. s->Delta = Reader(p)->ReadBE32(Reader(p));
  447. }
  448. s->Count = MAX_INT;
  449. s->Delta = 0;
  450. ArrayLock(&Stream->STTS);
  451. }
  452. }
  453. static void ReadExtra(mp4* p,filepos_t EndOfAtom)
  454. {
  455. filepos_t Len = EndOfAtom - Reader(p)->FilePos;
  456. packetformat* Format;
  457. if (!p->Track || Len<=0) return;
  458. Format = &p->Track->Stream.Format;
  459. if (PacketFormatExtra(Format,Len))
  460. Reader(p)->Read(Reader(p),Format->Extra,Format->ExtraLength);
  461. }
  462. static int DescLen(mp4* p)
  463. {
  464. int Len = 0;
  465. int i;
  466. for (i=0;i<4;++i)
  467. {
  468. int v = Reader(p)->Read8(Reader(p));
  469. Len = (Len << 7) | (v & 0x7F);
  470. if (!(v & 0x80))
  471. break;
  472. }
  473. return Len;
  474. }
  475. static void ReadESDS(mp4* p,filepos_t EndOfAtom)
  476. {
  477. int Tag,Len;
  478. mp4stream* Stream = p->Track;
  479. if (!Stream) return;
  480. ReadVersion(Reader(p));
  481. Tag = Reader(p)->Read8(Reader(p));
  482. Len = DescLen(p);
  483. Reader(p)->Skip(Reader(p),2); //ID
  484. if (Tag == 3)
  485. Reader(p)->Skip(Reader(p),1); //priority
  486. Tag = Reader(p)->Read8(Reader(p));
  487. Len = DescLen(p);
  488. if (Tag == 4) //config descr
  489. {
  490. int ObjTypeId = Reader(p)->Read8(Reader(p));
  491. Reader(p)->Skip(Reader(p),12); //stream_type,buffer_size,max_bitrate,min_bitrate
  492. Tag = Reader(p)->Read8(Reader(p));
  493. Len = DescLen(p);
  494. if (Tag == 5 && PacketFormatExtra(&Stream->Stream.Format,Len))
  495. Reader(p)->Read(Reader(p),Stream->Stream.Format.Extra,Stream->Stream.Format.ExtraLength);
  496. //override fourcc or format if neccessary
  497. if (Stream->Stream.Format.Type == PACKET_VIDEO)
  498. {
  499. switch (ObjTypeId)
  500. {
  501. case MP4_MPEG1_VIDEO_TYPE:
  502. case MP4_MPEG2_SIMPLE_VIDEO_TYPE:
  503. case MP4_MPEG2_MAIN_VIDEO_TYPE:
  504. case MP4_MPEG2_SNR_VIDEO_TYPE:
  505. case MP4_MPEG2_SPATIAL_VIDEO_TYPE:
  506. case MP4_MPEG2_HIGH_VIDEO_TYPE:
  507. case MP4_MPEG2_442_VIDEO_TYPE:
  508. Stream->Stream.Format.Format.Video.Pixel.FourCC = FOURCC('m','p','e','g');
  509. break;
  510. case MP4_MPEG4_VIDEO_TYPE:
  511. Stream->Stream.Format.Format.Video.Pixel.FourCC = FOURCC('m','p','4','v');
  512. break;
  513. case MP4_JPEG_VIDEO_TYPE:
  514. Stream->Stream.Format.Format.Video.Pixel.FourCC = FOURCC('j','p','e','g');
  515. Stream->AllKey = 1;
  516. break;
  517. }
  518. }
  519. if (Stream->Stream.Format.Type == PACKET_AUDIO)
  520. {
  521. switch (ObjTypeId)
  522. {
  523. case MP4_MPEG1_AUDIO_TYPE:
  524. case MP4_MPEG2_AUDIO_TYPE:
  525. Stream->Stream.Format.Format.Audio.Format = AUDIOFMT_MP3;
  526. break;
  527. case MP4_MPEG2_AAC_MAIN_AUDIO_TYPE:
  528. case MP4_MPEG2_AAC_LC_AUDIO_TYPE:
  529. case MP4_MPEG2_AAC_SSR_AUDIO_TYPE:
  530. case MP4_MPEG4_AUDIO_TYPE:
  531. Stream->Stream.Format.Format.Audio.Format = AUDIOFMT_AAC;
  532. break;
  533. case MP4_PRIVATE_AUDIO_TYPE+1:
  534. if (Stream->Stream.Format.ExtraLength>4 && 
  535. *(uint32_t*)Stream->Stream.Format.Extra == FOURCC('Q','L','C','M'))
  536. Stream->Stream.Format.Format.Audio.Format = AUDIOFMT_QCELP;
  537. break;
  538. }
  539. }
  540. }
  541. }
  542. static void SetText(mp4* p,uint32_t FourCC)
  543. {
  544. packetformat* Format = &p->Track->Stream.Format;
  545. PacketFormatClear(Format);
  546. Format->Type = PACKET_SUBTITLE;
  547. Format->Format.Subtitle.FourCC = FourCC;
  548. PacketFormatDefault(Format);
  549. }
  550. static void SetAudio(mp4* p,int AudioFormat,int SampleRate,int Bits,int Channels)
  551. {
  552. packetformat* Format = &p->Track->Stream.Format;
  553. PacketFormatClear(Format);
  554. Format->Type = PACKET_AUDIO;
  555. Format->Format.Audio.Format = AudioFormat;
  556. Format->Format.Audio.Flags = PCM_PACKET_BASED;
  557. Format->Format.Audio.SampleRate = SampleRate;
  558. Format->Format.Audio.Bits = Bits;
  559. Format->Format.Audio.Channels = Channels;
  560. PacketFormatDefault(Format);
  561. }
  562. static void ReadAudio(mp4* p,int AudioFormat,int Atom,filepos_t EndOfAtom,int FixedBits)
  563. {
  564. packetformat* Format = &p->Track->Stream.Format;
  565. PacketFormatClear(Format);
  566. Format->Type = PACKET_AUDIO;
  567. Format->Format.Audio.Format = AudioFormat;
  568. Format->Format.Audio.Channels = 1;
  569. Format->Format.Audio.Flags = PCM_PACKET_BASED;
  570. #ifdef IS_BIG_ENDIAN
  571. if (Atom == FOURCC('s','o','w','t'))
  572. Format->Format.Audio.Flags |= PCM_SWAPEDBYTES;
  573. #else
  574. if (Atom == FOURCC('t','w','o','s'))
  575. Format->Format.Audio.Flags |= PCM_SWAPEDBYTES;
  576. #endif
  577. if (Atom == FOURCC('r','a','w',' ') || Atom == FOURCC('N','O','N','E'))
  578. {
  579. #ifndef IS_BIG_ENDIAN
  580. Format->Format.Audio.Flags |= PCM_SWAPEDBYTES; // some digital cameras use 'raw ' with 16bit big endian
  581. #endif
  582. Format->Format.Audio.Bits = 8;
  583. }
  584. else
  585. Format->Format.Audio.Bits = 16;
  586. if (EndOfAtom - Reader(p)->FilePos >= 20)
  587. {
  588. int Ver = Reader(p)->ReadBE16(Reader(p));
  589. Reader(p)->Skip(Reader(p),2+4); // revision, vendor
  590. Format->Format.Audio.Channels = Reader(p)->ReadBE16(Reader(p)); // channel count
  591. Format->Format.Audio.Bits = Reader(p)->ReadBE16(Reader(p)); // sample size
  592. Reader(p)->Skip(Reader(p),2+2); // compression_id,packet_size
  593. Format->Format.Audio.SampleRate = Reader(p)->ReadBE16(Reader(p)); // sample rate
  594. Reader(p)->Skip(Reader(p),2); // reserved (part of 32bit sample rate?)
  595. if (FixedBits < 0)
  596. FixedBits = Format->Format.Audio.Bits; 
  597. if (Ver == 1)
  598. {
  599. p->Track->SamplesPerPacket = Reader(p)->ReadBE32(Reader(p));
  600. Reader(p)->ReadBE32(Reader(p));
  601. p->Track->BytesPerPacket = Reader(p)->ReadBE32(Reader(p));
  602. Reader(p)->ReadBE32(Reader(p));
  603. if (AudioFormat == AUDIOFMT_ADPCM_MS || AudioFormat == AUDIOFMT_ADPCM_IMA)
  604. Format->Format.Audio.BlockAlign = p->Track->BytesPerPacket;
  605. }
  606. else
  607. if (FixedBits)
  608. {
  609. p->Track->SamplesPerPacket = 1;
  610. p->Track->BytesPerPacket = (FixedBits * Format->Format.Audio.Channels) >> 3;
  611. }
  612. ReadSubAtoms(p,EndOfAtom);
  613. }
  614. PacketFormatDefault(Format);
  615. }
  616. static void ReadVideo(mp4* p,int FourCC,filepos_t EndOfAtom)
  617. {
  618. int ColTable,BitCount,ColCount;
  619. bool_t ColGray;
  620. packetformat* Format = &p->Track->Stream.Format;
  621. PacketFormatClear(Format);
  622. Format->Type = PACKET_VIDEO;
  623. Reader(p)->Skip(Reader(p),16); // reserved
  624. Format->Format.Video.Pixel.FourCC = FourCC;
  625. Format->Format.Video.Width = Reader(p)->ReadBE16(Reader(p));
  626. Format->Format.Video.Height = Reader(p)->ReadBE16(Reader(p)); 
  627. Format->Format.Video.Aspect = ASPECT_ONE; //todo: fix
  628. if (FourCC == FOURCC('m','p','4','v'))
  629. {
  630. // use mpeg4 vol information instead 
  631. Format->Format.Video.Width = 0;
  632. Format->Format.Video.Height = 0;
  633. }
  634. Reader(p)->Skip(Reader(p),14+32); // reserved,compressor
  635. BitCount = Reader(p)->ReadBE16(Reader(p));
  636. ColGray = (BitCount & 32)!=0;
  637. BitCount &= 31;
  638. ColCount = 1<<BitCount;
  639. Format->Format.Video.Pixel.BitCount = BitCount;
  640. ColTable = Reader(p)->ReadBE16(Reader(p));
  641.     if ((BitCount==2 || BitCount==4 || BitCount==8) &&
  642. PacketFormatExtra(Format,sizeof(rgb)*ColCount)) 
  643. {
  644. rgb* Pal = Format->Format.Video.Pixel.Palette = (rgb*)Format->Extra;
  645. if (ColGray)
  646. {
  647. int i;
  648. for (i=0;i<ColCount;++i)
  649. {
  650. int v = 255 - (i*255)/(ColCount-1);
  651. Pal[i].c.r = (uint8_t)v;
  652. Pal[i].c.g = (uint8_t)v;
  653. Pal[i].c.b = (uint8_t)v;
  654. Pal[i].c.a = 0;
  655. }
  656. }
  657. else
  658. if (ColTable & 8)
  659. {
  660. // default palette
  661. int i;
  662. const rgbval_t* v = MovPal;
  663. if (BitCount>2) v += 1<<2;
  664. if (BitCount>4) v += 1<<4;
  665. for (i=0;i<ColCount;++i)
  666. Pal[i].v = v[i];
  667. }
  668. else
  669. {
  670. int Start,End;
  671. Start = Reader(p)->ReadBE32(Reader(p));
  672. Reader(p)->Skip(Reader(p),2); // count
  673. End = Reader(p)->ReadBE16(Reader(p))+1;
  674. if (End > ColCount)
  675. End = ColCount;
  676. for (;Start<End;++Start)
  677. {
  678. uint8_t v[4][2];
  679. Reader(p)->Read(Reader(p),v,sizeof(v)); // 16bit a,r,g,b 
  680. Pal[Start].c.r = v[1][0];
  681. Pal[Start].c.g = v[2][0];
  682. Pal[Start].c.b = v[3][0];
  683. Pal[Start].c.a = 0;
  684. }
  685. }
  686. }
  687. ReadSubAtoms(p,EndOfAtom);
  688. PacketFormatDefault(Format);
  689. }
  690. static void ReadSTSD(mp4* p,filepos_t EndOfAtom)
  691. {
  692. mp4stream* Stream = p->Track;
  693. int DescCount;
  694. mp4atom Atom;
  695. if (!Stream) return;
  696. ReadVersion(Reader(p));
  697. DescCount = Reader(p)->ReadBE32(Reader(p));
  698. if (DescCount && ReadAtom(Reader(p),&Atom))
  699. {
  700. uint32_t FirstAtom = Atom.Atom;
  701. Reader(p)->Skip(Reader(p),6+2); // reserved,reference index
  702. Stream->Stream.Fragmented = 0;
  703. // fourcc codes from libavformat
  704. if (Atom.Atom == FOURCC('A','V','D','J'))
  705. Atom.Atom = FOURCC('j','p','e','g');
  706. switch (Atom.Atom)
  707. {
  708. case FOURCC('p','n','g',' '):
  709. Atom.Atom = FOURCC('P','N','G','_');
  710. case FOURCC('t','i','f','f'):
  711. case FOURCC('j','p','e','g'):
  712. case FOURCC('m','j','p','a'):
  713. case FOURCC('m','j','p','b'):
  714. Stream->AllKey = 1;
  715. // no break;
  716. case FOURCC('3','I','V','2'):
  717. case FOURCC('3','I','V','1'):
  718. case FOURCC('a','v','c','1'):
  719. case FOURCC('S','V','Q','1'):
  720. case FOURCC('S','V','Q','3'):
  721. case FOURCC('m','p','4','v'):
  722. case FOURCC('D','I','V','X'):
  723. case FOURCC('V','P','3','1'):
  724. case FOURCC('h','2','6','3'):
  725. case FOURCC('s','2','6','3'):
  726. case FOURCC('c','v','i','d'):
  727. ReadVideo(p,Atom.Atom,Atom.EndOfAtom);
  728. break;
  729. // case FOURCC('O','g','g','V'):
  730. // Stream->Stream.Fragmented = 1;
  731. // ReadAudio(p,AUDIOFMT_VORBIS_MODE1,Atom.Atom,Atom.EndOfAtom,-1);
  732. // break;
  733. case FOURCC('s','o','w','t'):
  734. case FOURCC('t','w','o','s'):
  735. case FOURCC('r','a','w',' '):
  736. case FOURCC('N','O','N','E'):
  737. Stream->Stream.Fragmented = 1;
  738. ReadAudio(p,AUDIOFMT_PCM,Atom.Atom,Atom.EndOfAtom,-1);
  739. break;
  740. case FOURCC('u','l','a','w'):
  741. Stream->Stream.Fragmented = 1;
  742. ReadAudio(p,AUDIOFMT_MULAW,Atom.Atom,Atom.EndOfAtom,8);
  743. break;
  744. case FOURCC('a','l','a','w'):
  745. Stream->Stream.Fragmented = 1;
  746. ReadAudio(p,AUDIOFMT_ALAW,Atom.Atom,Atom.EndOfAtom,8);
  747. break;
  748. case FOURCC('Q','D','M','2'):
  749. Stream->Stream.Fragmented = 1;
  750. ReadAudio(p,AUDIOFMT_QDESIGN2,Atom.Atom,Atom.EndOfAtom,0);
  751. break;
  752. case FOURCC('.','m','p','3'):
  753. case 0x6D730055:
  754. case 0x5500736D:
  755. Stream->Stream.Fragmented = 1;
  756. ReadAudio(p,AUDIOFMT_MP3,Atom.Atom,Atom.EndOfAtom,0);
  757. break;
  758. case 0x6D730002:
  759. case 0x0200736D:
  760. Stream->Stream.Fragmented = 1;
  761. ReadAudio(p,AUDIOFMT_ADPCM_MS,Atom.Atom,Atom.EndOfAtom,0);
  762. break;
  763. case 0x6D730011:
  764. case 0x1100736D:
  765. Stream->Stream.Fragmented = 1;
  766. ReadAudio(p,AUDIOFMT_ADPCM_IMA,Atom.Atom,Atom.EndOfAtom,0);
  767. break;
  768. case FOURCC('i','m','a','4'):
  769. Stream->Stream.Fragmented = 1;
  770. ReadAudio(p,AUDIOFMT_ADPCM_IMA_QT,Atom.Atom,Atom.EndOfAtom,0);
  771. Stream->SamplesPerPacket = 64;
  772. Stream->BytesPerPacket = 34*Stream->Stream.Format.Format.Audio.Channels;
  773. break;
  774. case FOURCC('m','p','4','a'):
  775. ReadAudio(p,AUDIOFMT_AAC,Atom.Atom,Atom.EndOfAtom,0);
  776. break;
  777. case FOURCC('s','a','m','r'):
  778. SetAudio(p,AUDIOFMT_AMR_NB,8000,16,1);
  779. break;
  780. case FOURCC('s','a','w','b'):
  781. SetAudio(p,AUDIOFMT_AMR_WB,16000,16,1);
  782. break;
  783. case FOURCC('t','e','x','t'):
  784. SetText(p,UpperFourCC(Atom.Atom));
  785. break;
  786. case FOURCC('t','x','3','g'):
  787. SetText(p,UpperFourCC(Atom.Atom));
  788. break;
  789. }
  790. while (--DescCount>0)
  791. {
  792. Reader(p)->Seek(Reader(p),Atom.EndOfAtom,SEEK_SET);
  793. ReadAtom(Reader(p),&Atom);
  794. if (Atom.Atom != FirstAtom)
  795. {
  796. if (!p->ErrorShowed)
  797. {
  798. p->ErrorShowed = 1;
  799. ShowError(p->Format.Format.Class,MP4_ID,MP4_MULTIPLE_FORMAT);
  800. }
  801. Stream->Stream.Format.Type = PACKET_NONE;
  802. break;
  803. }
  804. }
  805. }
  806. if (Stream->Stream.Format.Type == PACKET_NONE)
  807. {
  808. Format_RemoveStream(&p->Format);
  809. p->Track = NULL;
  810. }
  811. }
  812. static void ReadMVHD(mp4* p,filepos_t EndOfAtom)
  813. {
  814. int Duration;
  815. ReadVersion(Reader(p));
  816. Reader(p)->ReadBE32(Reader(p)); // creation time
  817. Reader(p)->ReadBE32(Reader(p)); // modification time
  818. p->TimeScale = Reader(p)->ReadBE32(Reader(p)); // timescale
  819. Duration = Reader(p)->ReadBE32(Reader(p)); // duration
  820. if (Duration>0)
  821. p->Format.Duration = Scale(Duration,TICKSPERSEC,p->TimeScale);
  822. }
  823. static void ReadMDHD(mp4* p,filepos_t EndOfAtom)
  824. {
  825. int Duration = -1;
  826. if (!p->Track) return;
  827. switch (ReadVersion(Reader(p)))
  828. {
  829. case 0:
  830. Reader(p)->ReadBE32(Reader(p)); // creation time
  831. Reader(p)->ReadBE32(Reader(p)); // modification time
  832. p->Track->TimeScale = Reader(p)->ReadBE32(Reader(p)); // timescale
  833. Duration = Reader(p)->ReadBE32(Reader(p)); // duration
  834. break;
  835. case 1:
  836. Reader(p)->ReadBE64(Reader(p)); // creation time
  837. Reader(p)->ReadBE64(Reader(p)); // modification time
  838. p->Track->TimeScale = Reader(p)->ReadBE32(Reader(p)); // timescale
  839. Duration = (int)Reader(p)->ReadBE64(Reader(p)); // duration
  840. break;
  841. }
  842. if (Duration>0)
  843. {
  844. Duration = Scale(Duration,TICKSPERSEC,p->Track->TimeScale);
  845. if (p->Format.Duration < Duration)
  846. p->Format.Duration = Duration;
  847. }
  848. p->Track->Duration = Duration;
  849. }
  850. static void ReadCMOV(mp4* p,filepos_t EndOfAtom)
  851. {
  852. ReadSubAtoms(p,EndOfAtom);
  853. p->CompressType = 0;
  854. }
  855. static void ReadDCOM(mp4* p,filepos_t EndOfAtom)
  856. {
  857. p->CompressType = 0;
  858. Reader(p)->Read(Reader(p),&p->CompressType,sizeof(p->CompressType));
  859. }
  860. static void ReadCMVD(mp4* p,filepos_t EndOfAtom)
  861. {
  862. if (p->CompressType == FOURCC('z','l','i','b'))
  863. {
  864. uint32_t DstLen = Reader(p)->ReadBE32(Reader(p));
  865. int SrcLen = EndOfAtom - Reader(p)->FilePos;
  866. uint8_t* Src = (uint8_t*)malloc(SrcLen);
  867. uint8_t* Dst = (uint8_t*)malloc(DstLen);
  868. if (Src && Dst && Reader(p)->Read(Reader(p),Src,SrcLen)==SrcLen && 
  869. uncompress(Dst,&DstLen,Src,SrcLen)==Z_OK)
  870. {
  871. format_buffer Buffer;
  872. format_reader* Reader = p->Format.Reader;
  873. format_reader Backup = *Reader;
  874. Buffer.Block.Id = 0;
  875. Buffer.Block.Ptr = Dst;
  876. Buffer.Length = DstLen;
  877. Reader->BufferFirst = NULL;
  878. Reader->BufferLast = NULL;
  879. Reader->NoMoreInput = 1;
  880. Reader->ReadPos = 0;
  881. Reader->ReadLen = DstLen;
  882. Reader->FilePos = 0;
  883. Reader->Input = NULL;
  884. Reader->InputBuffer = NULL;
  885. Reader->ReadBuffer = &Buffer;
  886. Reader->Format = &p->Format;
  887. Reader->BufferAvailable = 0;
  888. ReadSubAtoms(p,DstLen);
  889. *Reader = Backup;
  890. }
  891. free(Src);
  892. free(Dst);
  893. }
  894. }
  895. static void AddMeta(mp4* p,const tchar_t* Meta,int Size)
  896. {
  897. pin* Comment = &p->Format.Comment;
  898. format_stream* Stream = (format_stream*)p->Track;
  899. if (Stream)
  900. Comment = &Stream->Comment;
  901. if (Comment->Node)
  902. Comment->Node->Set(Comment->Node,Comment->No,Meta,Size);
  903. }
  904. static void ReadMetaString(mp4* p,filepos_t EndOfAtom)
  905. {
  906. tchar_t Meta[512];
  907. char UTF8[512];
  908. int Len = EndOfAtom - Reader(p)->FilePos;
  909. if (Len>=512) Len=511;
  910. Len = Reader(p)->Read(Reader(p),UTF8,Len);
  911. if (Len>0)
  912. {
  913. UTF8[Len] = 0;
  914. tcscpy_s(Meta,TSIZEOF(Meta),p->Meta);
  915. UTF8ToTcs(Meta+tcslen(p->Meta),TSIZEOF(Meta)-tcslen(p->Meta),UTF8);
  916. AddMeta(p,Meta,sizeof(Meta));
  917. }
  918. }
  919. static void ReadRDRF(mp4* p,filepos_t EndOfAtom)
  920. {
  921. if (p->RMRAFound)
  922. {
  923. //redirect
  924. if (Reader(p)->ReadBE32(Reader(p))==0)
  925. {
  926. int Size;
  927. uint32_t Type = 0;
  928. Reader(p)->Read(Reader(p),&Type,sizeof(Type));
  929. Size = Reader(p)->ReadBE32(Reader(p));
  930. if (Type == FOURCC('u','r','l',' '))
  931. {
  932. tcscpy_s(p->Meta,TSIZEOF(p->Meta),T("REDIRECT="));
  933. ReadMetaString(p,min(EndOfAtom,Reader(p)->FilePos + Size));
  934. p->Meta[0] = 0;
  935. }
  936. }
  937. }
  938. }
  939. static void ReadDATA(mp4* p,filepos_t EndOfAtom)
  940. {
  941. ReadVersion(Reader(p));
  942. Reader(p)->Skip(Reader(p),4); //reserved;
  943. if (tcscmp(p->Meta,T("COVER="))==0)
  944. {
  945. tchar_t Meta[256];
  946. stprintf_s(Meta,TSIZEOF(Meta),T("%s:%d:%d:"),p->Meta,Reader(p)->FilePos,EndOfAtom-Reader(p)->FilePos);
  947. AddMeta(p,Meta,sizeof(Meta));
  948. }
  949. else
  950. if (tcscmp(p->Meta,T("GENRE="))==0)
  951. {
  952. tchar_t Meta[256];
  953. tcscpy_s(Meta,TSIZEOF(Meta),p->Meta);
  954. if (ID3v1_Genre(Reader(p)->ReadBE16(Reader(p))-1,Meta+tcslen(Meta),256-tcslen(Meta)))
  955. AddMeta(p,Meta,sizeof(Meta));
  956. }
  957. else
  958. if (p->Meta[0])
  959. ReadMetaString(p,EndOfAtom);
  960. }
  961. static void ReadNeroChapter(mp4* p,filepos_t EndOfAtom)
  962. {
  963. int Count,i,Len;
  964. Reader(p)->Read8(Reader(p)); // version?
  965. Reader(p)->Skip(Reader(p),4); // ???
  966. Count = Reader(p)->ReadBE32(Reader(p));
  967. for (i=0;i<Count;++i)
  968. {
  969. int64_t Time = Reader(p)->ReadBE64(Reader(p));
  970. stprintf_s(p->Meta,TSIZEOF(p->Meta),T("CHAPTER%02dNAME="),i+1);
  971. Len = Reader(p)->Read8(Reader(p));
  972. ReadMetaString(p,Reader(p)->FilePos + Len);
  973. BuildChapter(p->Meta,TSIZEOF(p->Meta),i+1,Time,10000);
  974. AddMeta(p,p->Meta,sizeof(p->Meta));
  975. }
  976. }
  977. static void ReadNAME(mp4* p,filepos_t EndOfAtom)
  978. {
  979. ReadVersion(Reader(p));
  980. if (p->Meta[0])
  981. ReadMetaString(p,EndOfAtom);
  982. else
  983. {
  984. char UTF8[512];
  985. int Len = EndOfAtom - Reader(p)->FilePos;
  986. if (Len>510) Len=510;
  987. Len = Reader(p)->Read(Reader(p),UTF8,Len);
  988. if (Len>0)
  989. {
  990. UTF8[Len] = '=';
  991. UTF8[Len+1] = 0;
  992. UTF8ToTcs(p->Meta,TSIZEOF(p->Meta),UTF8);
  993. }
  994. }
  995. }
  996. static void ReadMeta(mp4* p,filepos_t EndOfAtom, const tchar_t* Meta)
  997. {
  998. mp4atom Atom;
  999. int Pos = Reader(p)->FilePos;
  1000. tcscpy_s(p->Meta,TSIZEOF(p->Meta),Meta);
  1001. ReadAtom(Reader(p),&Atom);
  1002. Reader(p)->Seek(Reader(p),Pos,SEEK_SET);
  1003. if (Atom.EndOfAtom > EndOfAtom)
  1004. ReadNAME(p,EndOfAtom);
  1005. else
  1006. ReadSubAtoms(p,EndOfAtom);
  1007. p->Meta[0] = 0;
  1008. }
  1009. static void ReadMetaCover(mp4* p,filepos_t EndOfAtom) { ReadMeta(p,EndOfAtom,T("COVER=")); }
  1010. static void ReadMetaName(mp4* p,filepos_t EndOfAtom) { ReadMeta(p,EndOfAtom,T("TITLE=")); }
  1011. static void ReadMetaArtist(mp4* p,filepos_t EndOfAtom) { ReadMeta(p,EndOfAtom,T("ARTIST=")); }
  1012. static void ReadMetaWriter(mp4* p,filepos_t EndOfAtom) { ReadMeta(p,EndOfAtom,T("WRITER=")); }
  1013. static void ReadMetaAlbum(mp4* p,filepos_t EndOfAtom) { ReadMeta(p,EndOfAtom,T("ALBUM=")); }
  1014. static void ReadMetaDate(mp4* p,filepos_t EndOfAtom) { ReadMeta(p,EndOfAtom,T("DATE=")); }
  1015. static void ReadMetaTool(mp4* p,filepos_t EndOfAtom) { ReadMeta(p,EndOfAtom,T("TOOL=")); }
  1016. static void ReadMetaComment(mp4* p,filepos_t EndOfAtom) { ReadMeta(p,EndOfAtom,T("COMMENT=")); }
  1017. static void ReadMetaGenre(mp4* p,filepos_t EndOfAtom) { ReadMeta(p,EndOfAtom,T("GENRE=")); }
  1018. static const mp4atomtable AtomTable[] =
  1019. {
  1020. { FOURCC('f','t','y','p'), ReadFTYP },
  1021. { FOURCC('m','o','o','v'), ReadMOOV },
  1022. { FOURCC('t','r','a','k'), ReadTRAK },
  1023. { FOURCC('m','v','h','d'), ReadMVHD },
  1024. { FOURCC('m','d','h','d'), ReadMDHD },
  1025. { FOURCC('s','t','b','l'), ReadSubAtoms },
  1026. { FOURCC('m','i','n','f'), ReadSubAtoms },
  1027. { FOURCC('e','d','t','s'), ReadSubAtoms },
  1028. { FOURCC('m','d','i','a'), ReadSubAtoms },
  1029. { FOURCC('u','d','t','a'), ReadSubAtoms },
  1030. { FOURCC('i','l','s','t'), ReadSubAtoms },
  1031. { FOURCC('w','a','v','e'), ReadSubAtoms },
  1032. { FOURCC('-','-','-','-'), ReadSubAtoms },
  1033. { FOURCC('r','m','d','a'), ReadSubAtoms },
  1034. { FOURCC('r','m','r','a'), ReadRMRA },
  1035. { FOURCC('r','d','r','f'), ReadRDRF },
  1036. { FOURCC('m','e','t','a'), ReadMETA },
  1037. { FOURCC('s','t','s','d'), ReadSTSD },
  1038. { FOURCC('s','t','s','s'), ReadSTSS },
  1039. { FOURCC('s','t','s','c'), ReadSTSC },
  1040. { FOURCC('s','t','c','o'), ReadSTCO },
  1041. { FOURCC('c','t','t','s'), ReadCTTS },
  1042. { FOURCC('s','t','s','z'), ReadSTSZ },
  1043. { FOURCC('s','t','t','s'), ReadSTTS },
  1044. { FOURCC('c','m','o','v'), ReadCMOV },
  1045. { FOURCC('d','c','o','m'), ReadDCOM },
  1046. { FOURCC('c','m','v','d'), ReadCMVD },
  1047. { FOURCC('e','s','d','s'), ReadESDS },
  1048. { FOURCC('S','M','I',' '), ReadExtra },
  1049. { FOURCC('a','v','c','C'), ReadExtra },
  1050. { FOURCC('d','a','t','a'), ReadDATA },
  1051. { FOURCC('n','a','m','e'), ReadNAME },
  1052. { FOURCC('c','h','p','l'), ReadNeroChapter },
  1053. { FOURCC('251','n','a','m'), ReadMetaName },
  1054. { FOURCC('251','A','R','T'), ReadMetaArtist },
  1055. { FOURCC('251','w','r','t'), ReadMetaWriter },
  1056. { FOURCC('251','a','l','b'), ReadMetaAlbum },
  1057. { FOURCC('251','d','a','y'), ReadMetaDate },
  1058. { FOURCC('251','t','o','o'), ReadMetaTool },
  1059. { FOURCC('251','c','m','t'), ReadMetaComment },
  1060. { FOURCC('251','g','e','n'), ReadMetaGenre },
  1061. { FOURCC('c','o','v','r'), ReadMetaCover },
  1062. { FOURCC('g','n','r','e'), ReadMetaGenre },
  1063. { 0, NULL }
  1064. };
  1065. static void ReadSubAtoms(mp4* p,filepos_t EndOfAtom)
  1066. {
  1067. mp4atom Atom;
  1068. const mp4atomtable* i;
  1069. while (Reader(p)->FilePos < EndOfAtom - 8)
  1070. {
  1071. if (!ReadAtom(Reader(p),&Atom))
  1072. break;
  1073. if (p->MOOVFound && Atom.Atom == FOURCC('m','d','a','t'))
  1074. break;
  1075. for (i=AtomTable;i->Atom;++i)
  1076. if (i->Atom == Atom.Atom)
  1077. {
  1078. i->Func(p,Atom.EndOfAtom);
  1079. break;
  1080. }
  1081. Reader(p)->Seek(Reader(p),Atom.EndOfAtom,SEEK_SET);
  1082. }
  1083. p->Meta[0] = 0;
  1084. }
  1085. static mp4stream* FindNextChunk(mp4* p, format_reader* Reader)
  1086. {
  1087. mp4stream* Stream = NULL;
  1088. int Min = MAX_INT;
  1089. int No;
  1090. for (No=0;No<p->Format.StreamCount;++No)
  1091. {
  1092. mp4stream* s = (mp4stream*)p->Format.Streams[No];
  1093. if (s->Stream.Pin.Node && s->Stream.Reader == Reader && Min > *s->Pos.STCOPos)
  1094. {
  1095. Min = *s->Pos.STCOPos;
  1096. Stream = s;
  1097. }
  1098. }
  1099. if (Stream)
  1100. {
  1101. if (Reader->Seek(Reader,Min,SEEK_SET) == ERR_NONE)
  1102. {
  1103. Reader->Current = &Stream->Stream;
  1104. NextChunk(Stream,&Stream->Pos);
  1105. }
  1106. else
  1107. Stream = NULL;
  1108. }
  1109. return Stream;
  1110. }
  1111. static void AddTextChapters(mp4* p,mp4stream* s)
  1112. {
  1113. format_reader* Reader = p->Format.Reader;
  1114. mp4streampos Pos;
  1115. int No = 1;
  1116. Head(s,&Pos);
  1117. for (;;)
  1118. {
  1119. filepos_t FilePos = *Pos.STCOPos;
  1120. if (FilePos == MAX_INT)
  1121. break;
  1122. NextChunk(s,&Pos);
  1123. while (Pos.SamplesLeft)
  1124. {
  1125. if (Reader->Seek(Reader,FilePos,SEEK_SET) == ERR_NONE)
  1126. {
  1127. int Len = Reader->ReadBE16(Reader);
  1128. if (Len)
  1129. {
  1130. stprintf_s(p->Meta,TSIZEOF(p->Meta),T("CHAPTER%02dNAME="),No);
  1131. ReadMetaString(p,Reader->FilePos+Len);
  1132. BuildChapter(p->Meta,TSIZEOF(p->Meta),No,(int64_t)Pos.CurrentTime*1000,s->TimeScale);
  1133. AddMeta(p,p->Meta,sizeof(p->Meta));
  1134. ++No;
  1135. }
  1136. }
  1137. FilePos += NextSample(s,&Pos);
  1138. }
  1139. }
  1140. }
  1141. static int Init(mp4* p)
  1142. {
  1143. int No;
  1144. p->MOOVFound = 0;
  1145. p->Type = FOURCC('m','o','o','v'); //quicktime .mov
  1146. p->TimeScale = 0;
  1147. p->ErrorShowed = 0;
  1148. p->Format.HeaderLoaded = 1;
  1149. p->Meta[0] = 0;
  1150. ReadSubAtoms(p,MAX_INT);
  1151. if (!p->MOOVFound)
  1152. return ERR_INVALID_DATA;
  1153. if (p->Format.Comment.Node)
  1154. for (No=0;No<p->Format.StreamCount;++No)
  1155. {
  1156. mp4stream* s = (mp4stream*)p->Format.Streams[No];
  1157. if (s->Stream.Format.Type == PACKET_SUBTITLE && 
  1158. s->Stream.Format.Format.Subtitle.FourCC == FOURCC('T','E','X','T') && GetFrames(s)<100)
  1159. AddTextChapters(p,s);
  1160. }
  1161. for (No=0;No<p->Format.StreamCount;++No)
  1162. {
  1163. mp4stream* s = (mp4stream*)p->Format.Streams[No];
  1164. format_reader* Reader = Format_FindReader(&p->Format,s->OffsetMin,s->OffsetMax);
  1165. if (!Reader)
  1166. break;
  1167. s->Stream.Reader = Reader;
  1168. }
  1169. for (No=0;No<MAXREADER;++No)
  1170. FindNextChunk(p,p->Format.Reader+No);
  1171. return ERR_NONE;
  1172. }
  1173. static int ReadPacket(mp4* p, format_reader* Reader, format_packet* Packet)
  1174. {
  1175. mp4stream* Stream = (mp4stream*) Reader->Current;
  1176. if (!Stream)
  1177. {
  1178. Stream = FindNextChunk(p,Reader);
  1179. if (!Stream)
  1180. return ERR_END_OF_FILE;
  1181. }
  1182. Packet->Stream = &Stream->Stream;
  1183. Packet->RefTime = Scale(Stream->Pos.CurrentTime,TICKSPERSEC,Stream->TimeScale);
  1184. if (Stream->Pos.STSSValue >= 0)
  1185. {
  1186. Packet->Key = Stream->Pos.SampleNo == Stream->Pos.STSSValue;
  1187. if (Packet->Key)
  1188. NextKey(&Stream->Pos);
  1189. }
  1190. Packet->Data = Reader->ReadAsRef(Reader,NextSample(Stream,&Stream->Pos));
  1191. if (Stream->Pos.SamplesLeft==0)
  1192. Reader->Current = NULL;
  1193. return ERR_NONE;
  1194. }
  1195. static bool_t GetNeedKey(mp4stream* Stream)
  1196. {
  1197. return (!ARRAYEMPTY(Stream->STSS) || Stream->AllKey) && Stream->Stream.Format.Type == PACKET_VIDEO;
  1198. }
  1199. static int SeekReader(mp4* p, format_reader* Reader, tick_t* DstTime, filepos_t DstPos, bool_t PrevKey)
  1200. {
  1201. mp4stream* Stream = (mp4stream*) Format_DefSyncStream(&p->Format,Reader);
  1202. if (Stream && Reader->Input)
  1203. {
  1204. mp4streampos Last;
  1205. mp4streampos Pos;
  1206. bool_t NeedKey;
  1207. tick_t SyncTime;
  1208. int DstMediaTime,No;
  1209. filepos_t FilePos;
  1210. filepos_t LastFilePos = -1;
  1211. DstMediaTime = -1;
  1212. if (*DstTime >= 0)
  1213. DstMediaTime = Scale(*DstTime,Stream->TimeScale,TICKSPERSEC);
  1214. NeedKey = GetNeedKey(Stream);
  1215. if (!NeedKey)
  1216. PrevKey = 0;
  1217. else
  1218. if (Stream->AllKey) // SyncTime will be independent anyway. we always need current chapter image
  1219. PrevKey = 1;
  1220. if (PrevKey && DstMediaTime >= 0)
  1221. DstMediaTime += 1+Stream->TimeScale/256; // seek to same position even if there is rounding error
  1222. Head(Stream,&Last);
  1223. Head(Stream,&Pos);
  1224. for (;;)
  1225. {
  1226. FilePos = *Pos.STCOPos;
  1227. if (FilePos == MAX_INT)
  1228. break;
  1229. NextChunk(Stream,&Pos);
  1230. while (Pos.SamplesLeft)
  1231. {
  1232. bool_t Key = Pos.SampleNo == Pos.STSSValue;
  1233. if (DstMediaTime >= 0 && Pos.CurrentTime >= DstMediaTime && (!NeedKey || Key))
  1234. {
  1235. if (PrevKey && Pos.CurrentTime != DstMediaTime && LastFilePos>=0)
  1236. {
  1237. FilePos = LastFilePos;
  1238. Pos = Last;
  1239. }
  1240. goto found;
  1241. }
  1242. if (DstPos >= 0 && FilePos >= DstPos)
  1243. goto found;
  1244. if (Key || Pos.STSSValue<0)
  1245. {
  1246. LastFilePos = FilePos;
  1247. Last = Pos;
  1248. }
  1249. if (Key) NextKey(&Pos);
  1250. FilePos += NextSample(Stream,&Pos);
  1251. }
  1252. }
  1253. if (LastFilePos>=0)
  1254. {
  1255. FilePos = LastFilePos;
  1256. Pos = Last;
  1257. }
  1258. found:
  1259. if (FilePos==MAX_INT || Reader->Seek(Reader,FilePos,SEEK_SET) != ERR_NONE)
  1260. return ERR_NOT_SUPPORTED;
  1261. Stream->Stream.Reader->Current = Pos.SamplesLeft ? &Stream->Stream:NULL;
  1262. Stream->Pos = Pos;
  1263. SyncTime = Scale(Pos.CurrentTime,TICKSPERSEC,Stream->TimeScale);
  1264. if (*DstTime >= 0 && (!Stream->AllKey || (abs(*DstTime-SyncTime)<TICKSPERSEC/16))) // use updated time with other Readers
  1265. *DstTime = SyncTime;
  1266. // set current positions for other streams
  1267. for (No=0;No<p->Format.StreamCount;++No)
  1268. {
  1269. mp4stream* s = (mp4stream*) p->Format.Streams[No];
  1270. if (s->Stream.Reader==Reader && s != Stream)
  1271. {
  1272. Head(s,&s->Pos);
  1273. for (;;)
  1274. {
  1275. if (*s->Pos.STCOPos >= FilePos)
  1276. break;
  1277. NextChunk(s,&s->Pos);
  1278. while (s->Pos.SamplesLeft)
  1279. {
  1280. if (s->Pos.SampleNo == s->Pos.STSSValue) 
  1281. NextKey(&s->Pos);
  1282. NextSample(s,&s->Pos);
  1283. }
  1284. }
  1285. }
  1286. }
  1287. }
  1288. return ERR_NONE;
  1289. }
  1290. static int Seek(mp4* p, tick_t DstTime, filepos_t DstPos, bool_t PrevKey)
  1291. {
  1292. int Result;
  1293. int Skip = -1;
  1294. int No;
  1295. for (No=0;No<MAXREADER;++No)
  1296. {
  1297. mp4stream* Stream = (mp4stream*) Format_DefSyncStream(&p->Format,&p->Format.Reader[No]);
  1298. if (Stream && GetNeedKey(Stream))
  1299. {
  1300. Skip = No;
  1301. Result = SeekReader(p,&p->Format.Reader[No],&DstTime,DstPos,PrevKey);
  1302. if (Result != ERR_NONE)
  1303. return Result;
  1304. if (Stream->AllKey && DstTime >= 0)
  1305. p->Format.SyncTime = DstTime;
  1306. break;
  1307. }
  1308. }
  1309. if (Skip<0)
  1310. PrevKey = 0;
  1311. for (No=0;No<MAXREADER;++No)
  1312. if (No != Skip)
  1313. {
  1314. Result = SeekReader(p,&p->Format.Reader[No],&DstTime,DstPos,PrevKey);
  1315. if (Result != ERR_NONE)
  1316. return Result;
  1317. }
  1318. Format_AfterSeek(&p->Format);
  1319. return ERR_NONE;
  1320. }
  1321. static void FreeStream(mp4* p, mp4stream* Stream)
  1322. {
  1323. ArrayClear(&Stream->STSS);
  1324. ArrayClear(&Stream->STSZ);
  1325. ArrayClear(&Stream->STTS);
  1326. ArrayClear(&Stream->STSC);
  1327. ArrayClear(&Stream->STCO);
  1328. }
  1329. static int Create(mp4* p)
  1330. {
  1331. p->Format.Init = (fmtfunc)Init;
  1332. p->Format.Seek = (fmtseek)Seek;
  1333. p->Format.ReadPacket = (fmtreadpacket)ReadPacket;
  1334. p->Format.FreeStream = (fmtstream)FreeStream;
  1335. return ERR_NONE;
  1336. }
  1337. static const nodedef MP4 =
  1338. {
  1339. sizeof(mp4),
  1340. MP4_ID,
  1341. FORMATBASE_CLASS,
  1342. PRI_DEFAULT,
  1343. (nodecreate)Create,
  1344. };
  1345. void MP4_Init()
  1346. {
  1347. NodeRegisterClass(&MP4);
  1348. }
  1349. void MP4_Done()
  1350. {
  1351. NodeUnRegisterClass(MP4_ID);
  1352. }