rtphint.cpp
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:33k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  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.  All Rights Reserved.
  17.  * 
  18.  * Contributor(s): 
  19.  * Dave Mackie dmackie@cisco.com
  20.  */
  21. #include "mp4common.h"
  22. /* rtp hint track operations */
  23. MP4RtpHintTrack::MP4RtpHintTrack(MP4File* pFile, MP4Atom* pTrakAtom)
  24. : MP4Track(pFile, pTrakAtom)
  25. {
  26. m_pRefTrack = NULL;
  27. m_pRtpMapProperty = NULL;
  28. m_pPayloadNumberProperty = NULL;
  29. m_pMaxPacketSizeProperty = NULL;
  30. m_pSnroProperty = NULL;
  31. m_pTsroProperty = NULL;
  32. m_pReadHint = NULL;
  33. m_pReadHintSample = NULL;
  34. m_readHintSampleSize = 0;
  35. m_pWriteHint = NULL;
  36. m_writeHintId = MP4_INVALID_SAMPLE_ID;
  37. m_writePacketId = 0;
  38. m_pTrpy = NULL;
  39. m_pNump = NULL;
  40. m_pTpyl = NULL;
  41. m_pMaxr = NULL;
  42. m_pDmed = NULL;
  43. m_pDimm = NULL;
  44. m_pPmax = NULL;
  45. m_pDmax = NULL;
  46. m_pMaxPdu = NULL;
  47. m_pAvgPdu = NULL;
  48. m_pMaxBitRate = NULL;
  49. m_pAvgBitRate = NULL;
  50. m_thisSec = 0;
  51. m_bytesThisSec = 0;
  52. m_bytesThisHint = 0;
  53. m_bytesThisPacket = 0;
  54. }
  55. MP4RtpHintTrack::~MP4RtpHintTrack()
  56. {
  57. delete m_pReadHint;
  58. delete m_pReadHintSample;
  59. delete m_pWriteHint;
  60. }
  61. void MP4RtpHintTrack::InitRefTrack()
  62. {
  63. if (m_pRefTrack == NULL) {
  64. MP4Integer32Property* pRefTrackIdProperty = NULL;
  65. m_pTrakAtom->FindProperty(
  66. "trak.tref.hint.entries[0].trackId",
  67. (MP4Property**)&pRefTrackIdProperty);
  68. ASSERT(pRefTrackIdProperty);
  69. m_pRefTrack = m_pFile->GetTrack(pRefTrackIdProperty->GetValue());
  70. }
  71. }
  72. void MP4RtpHintTrack::InitRtpStart() 
  73. {
  74. struct timeval tv;
  75. gettimeofday(&tv, NULL);
  76. srandom((tv.tv_usec << 12) | (tv.tv_sec & 0xFFF));
  77. ASSERT(m_pTrakAtom);
  78. m_pTrakAtom->FindProperty(
  79. "trak.udta.hnti.rtp .snro.offset",
  80. (MP4Property**)&m_pSnroProperty);
  81. if (m_pSnroProperty) {
  82. m_rtpSequenceStart = m_pSnroProperty->GetValue();
  83. } else {
  84. m_rtpSequenceStart = random();
  85. }
  86. m_pTrakAtom->FindProperty(
  87. "trak.udta.hnti.rtp .tsro.offset",
  88. (MP4Property**)&m_pTsroProperty);
  89. if (m_pTsroProperty) {
  90. m_rtpTimestampStart = m_pTsroProperty->GetValue();
  91. } else {
  92. m_rtpTimestampStart = random();
  93. }
  94. }
  95. void MP4RtpHintTrack::ReadHint(
  96. MP4SampleId hintSampleId,
  97. u_int16_t* pNumPackets)
  98. {
  99. if (m_pRefTrack == NULL) {
  100. InitRefTrack();
  101. InitRtpStart();
  102. }
  103. // dispose of any old hint
  104. delete m_pReadHint;
  105. m_pReadHint = NULL;
  106. delete m_pReadHintSample;
  107. m_pReadHintSample = NULL;
  108. m_readHintSampleSize = 0;
  109. // read the desired hint sample into memory
  110. ReadSample(
  111. hintSampleId, 
  112. &m_pReadHintSample, 
  113. &m_readHintSampleSize,
  114. &m_readHintTimestamp);
  115. m_pFile->EnableMemoryBuffer(m_pReadHintSample, m_readHintSampleSize);
  116. m_pReadHint = new MP4RtpHint(this);
  117. m_pReadHint->Read(m_pFile);
  118. m_pFile->DisableMemoryBuffer();
  119. if (pNumPackets) {
  120. *pNumPackets = GetHintNumberOfPackets();
  121. }
  122. }
  123. u_int16_t MP4RtpHintTrack::GetHintNumberOfPackets()
  124. {
  125. if (m_pReadHint == NULL) {
  126. throw new MP4Error("no hint has been read",
  127. "MP4GetRtpHintNumberOfPackets");
  128. }
  129. return m_pReadHint->GetNumberOfPackets();
  130. }
  131. bool MP4RtpHintTrack::GetPacketBFrame(u_int16_t packetIndex)
  132. {
  133. if (m_pReadHint == NULL) {
  134. throw new MP4Error("no hint has been read",
  135. "MP4GetRtpPacketBFrame");
  136. }
  137. MP4RtpPacket* pPacket =
  138. m_pReadHint->GetPacket(packetIndex);
  139. return pPacket->IsBFrame();
  140. }
  141. u_int16_t MP4RtpHintTrack::GetPacketTransmitOffset(u_int16_t packetIndex)
  142. {
  143. if (m_pReadHint == NULL) {
  144. throw new MP4Error("no hint has been read",
  145. "MP4GetRtpPacketTransmitOffset");
  146. }
  147. MP4RtpPacket* pPacket =
  148. m_pReadHint->GetPacket(packetIndex);
  149. return pPacket->GetTransmitOffset();
  150. }
  151. void MP4RtpHintTrack::ReadPacket(
  152. u_int16_t packetIndex,
  153. u_int8_t** ppBytes, 
  154. u_int32_t* pNumBytes,
  155. u_int32_t ssrc,
  156. bool addHeader,
  157. bool addPayload)
  158. {
  159. if (m_pReadHint == NULL) {
  160. throw new MP4Error("no hint has been read",
  161. "MP4ReadRtpPacket");
  162. }
  163. if (!addHeader && !addPayload) {
  164. throw new MP4Error("no data requested",
  165. "MP4ReadRtpPacket");
  166. }
  167. MP4RtpPacket* pPacket =
  168. m_pReadHint->GetPacket(packetIndex);
  169. *pNumBytes = 0;
  170. if (addHeader) {
  171. *pNumBytes += 12;
  172. }
  173. if (addPayload) {
  174. *pNumBytes += pPacket->GetDataSize();
  175. }
  176. // if needed, allocate the packet memory
  177. bool buffer_malloc = false;
  178. if (*ppBytes == NULL) {
  179. *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes);
  180. buffer_malloc = true;
  181. }
  182. try {
  183. u_int8_t* pDest = *ppBytes;
  184. if (addHeader) {
  185. *pDest++ =
  186. 0x80 | (pPacket->GetPBit() << 5) | (pPacket->GetXBit() << 4);
  187. *pDest++ =
  188. (pPacket->GetMBit() << 7) | pPacket->GetPayload();
  189. *((u_int16_t*)pDest) = 
  190. htons(m_rtpSequenceStart + pPacket->GetSequenceNumber());
  191. pDest += 2; 
  192. *((u_int32_t*)pDest) = 
  193. htonl(m_rtpTimestampStart + (u_int32_t)m_readHintTimestamp);
  194. pDest += 4; 
  195. *((u_int32_t*)pDest) = 
  196. htonl(ssrc);
  197. pDest += 4;
  198. }
  199. if (addPayload) {
  200. pPacket->GetData(pDest);
  201. }
  202. }
  203. catch (MP4Error* e) {
  204. if (buffer_malloc) {
  205. MP4Free(*ppBytes);
  206. *ppBytes = NULL;
  207. }
  208. throw e;
  209. }
  210. VERBOSE_READ_HINT(m_pFile->GetVerbosity(),
  211. printf("ReadPacket: %u ", packetIndex);
  212. MP4HexDump(*ppBytes, *pNumBytes););
  213. }
  214. MP4Timestamp MP4RtpHintTrack::GetRtpTimestampStart()
  215. {
  216. if (m_pRefTrack == NULL) {
  217. InitRefTrack();
  218. InitRtpStart();
  219. }
  220. return m_rtpTimestampStart;
  221. }
  222. void MP4RtpHintTrack::SetRtpTimestampStart(MP4Timestamp start)
  223. {
  224. if (!m_pTsroProperty) {
  225. MP4Atom* pTsroAtom =
  226. m_pFile->AddDescendantAtoms(m_pTrakAtom, "udta.hnti.rtp .tsro");
  227. ASSERT(pTsroAtom);
  228. pTsroAtom->FindProperty("offset",
  229. (MP4Property**)&m_pTsroProperty);
  230. ASSERT(m_pTsroProperty);
  231. }
  232. m_pTsroProperty->SetValue(start);
  233. m_rtpTimestampStart = start;
  234. }
  235. void MP4RtpHintTrack::InitPayload()
  236. {
  237. ASSERT(m_pTrakAtom);
  238. if (m_pRtpMapProperty == NULL) {
  239. m_pTrakAtom->FindProperty(
  240. "trak.udta.hinf.payt.rtpMap",
  241. (MP4Property**)&m_pRtpMapProperty);
  242. }
  243. if (m_pPayloadNumberProperty == NULL) {
  244. m_pTrakAtom->FindProperty(
  245. "trak.udta.hinf.payt.payloadNumber",
  246. (MP4Property**)&m_pPayloadNumberProperty);
  247. }
  248. if (m_pMaxPacketSizeProperty == NULL) {
  249. m_pTrakAtom->FindProperty(
  250. "trak.mdia.minf.stbl.stsd.rtp .maxPacketSize",
  251. (MP4Property**)&m_pMaxPacketSizeProperty);
  252. }
  253. }
  254. void MP4RtpHintTrack::GetPayload(
  255. char** ppPayloadName,
  256. u_int8_t* pPayloadNumber,
  257. u_int16_t* pMaxPayloadSize)
  258. {
  259. InitPayload();
  260. if (ppPayloadName) {
  261. if (m_pRtpMapProperty) {
  262. const char* pRtpMap = m_pRtpMapProperty->GetValue();
  263. char* pSlash = strchr(pRtpMap, '/');
  264. u_int32_t length;
  265. if (pSlash) {
  266. length = pSlash - pRtpMap;
  267. } else {
  268. length = strlen(pRtpMap);
  269. }
  270. *ppPayloadName = (char*)MP4Calloc(length + 1);
  271. strncpy(*ppPayloadName, pRtpMap, length); 
  272. } else {
  273. *ppPayloadName = NULL;
  274. }
  275. }
  276. if (pPayloadNumber) {
  277. if (m_pPayloadNumberProperty) {
  278. *pPayloadNumber = m_pPayloadNumberProperty->GetValue();
  279. } else {
  280. *pPayloadNumber = 0;
  281. }
  282. }
  283. if (pMaxPayloadSize) {
  284. if (m_pMaxPacketSizeProperty) {
  285. *pMaxPayloadSize = m_pMaxPacketSizeProperty->GetValue();
  286. } else {
  287. *pMaxPayloadSize = 0;
  288. }
  289. }
  290. }
  291. void MP4RtpHintTrack::SetPayload(
  292. const char* payloadName,
  293. u_int8_t payloadNumber,
  294. u_int16_t maxPayloadSize)
  295. {
  296. InitRefTrack();
  297. InitPayload();
  298. ASSERT(m_pRtpMapProperty);
  299. ASSERT(m_pPayloadNumberProperty);
  300. ASSERT(m_pMaxPacketSizeProperty);
  301. char* rtpMapBuf = (char*)MP4Malloc(strlen(payloadName) + 16);
  302. sprintf(rtpMapBuf, "%s/%u", payloadName, GetTimeScale());
  303. m_pRtpMapProperty->SetValue(rtpMapBuf);
  304. m_pPayloadNumberProperty->SetValue(payloadNumber);
  305. if (maxPayloadSize == 0) {
  306. maxPayloadSize = 1460;
  307. m_pMaxPacketSizeProperty->SetValue(maxPayloadSize);
  308. // set sdp media type
  309. const char* sdpMediaType;
  310. if (!strcmp(m_pRefTrack->GetType(), MP4_AUDIO_TRACK_TYPE)) {
  311. sdpMediaType = "audio";
  312. } else if (!strcmp(m_pRefTrack->GetType(), MP4_VIDEO_TRACK_TYPE)) {
  313. sdpMediaType = "video";
  314. } else {
  315. sdpMediaType = "application";
  316. }
  317. char* sdpBuf = (char*)MP4Malloc(
  318. strlen(sdpMediaType) + strlen(rtpMapBuf) + 256);
  319. sprintf(sdpBuf, 
  320. "m=%s 0 RTP/AVP %u1512"
  321. "a=rtpmap:%u %s1512"
  322. "a=control:trackID=%u1512" 
  323. "a=mpeg4-esid:%u1512",
  324. sdpMediaType, payloadNumber,
  325. payloadNumber, rtpMapBuf,
  326. m_trackId,
  327. m_pRefTrack->GetId());
  328. MP4StringProperty* pSdpProperty = NULL;
  329. m_pTrakAtom->FindProperty("trak.udta.hnti.sdp .sdpText",
  330. (MP4Property**)&pSdpProperty);
  331. ASSERT(pSdpProperty);
  332. pSdpProperty->SetValue(sdpBuf);
  333. // cleanup
  334. MP4Free(rtpMapBuf);
  335. MP4Free(sdpBuf);
  336. }
  337. void MP4RtpHintTrack::AddHint(bool isBFrame, u_int32_t timestampOffset)
  338. {
  339. // on first hint, need to lookup the reference track
  340. if (m_writeHintId == MP4_INVALID_SAMPLE_ID) {
  341. InitRefTrack();
  342. InitStats();
  343. }
  344. if (m_pWriteHint) {
  345. throw new MP4Error("unwritten hint is still pending", "MP4AddRtpHint");
  346. }
  347. m_pWriteHint = new MP4RtpHint(this);
  348. m_pWriteHint->SetBFrame(isBFrame);
  349. m_pWriteHint->SetTimestampOffset(timestampOffset);
  350. m_bytesThisHint = 0;
  351. m_writeHintId++;
  352. }
  353. void MP4RtpHintTrack::AddPacket(bool setMbit, int32_t transmitOffset)
  354. {
  355. if (m_pWriteHint == NULL) {
  356. throw new MP4Error("no hint pending", "MP4RtpAddPacket");
  357. }
  358. MP4RtpPacket* pPacket = m_pWriteHint->AddPacket();
  359. ASSERT(m_pPayloadNumberProperty);
  360. pPacket->Set(
  361. m_pPayloadNumberProperty->GetValue(), 
  362. m_writePacketId++, 
  363. setMbit);
  364. pPacket->SetTransmitOffset(transmitOffset);
  365. m_bytesThisHint += 12;
  366. if (m_bytesThisPacket > m_pPmax->GetValue()) {
  367. m_pPmax->SetValue(m_bytesThisPacket);
  368. }
  369. m_bytesThisPacket = 12;
  370. m_pNump->IncrementValue();
  371. m_pTrpy->IncrementValue(12); // RTP packet header size
  372. }
  373. void MP4RtpHintTrack::AddImmediateData(
  374. const u_int8_t* pBytes,
  375. u_int32_t numBytes)
  376. {
  377. if (m_pWriteHint == NULL) {
  378. throw new MP4Error("no hint pending", "MP4RtpAddImmediateData");
  379. }
  380. MP4RtpPacket* pPacket = m_pWriteHint->GetCurrentPacket();
  381. if (pPacket == NULL) {
  382. throw new MP4Error("no packet pending", "MP4RtpAddImmediateData");
  383. }
  384. if (pBytes == NULL || numBytes == 0) {
  385. throw new MP4Error("no data",
  386. "AddImmediateData");
  387. }
  388. if (numBytes > 14) {
  389. throw new MP4Error("data size is larger than 14 bytes",
  390. "AddImmediateData");
  391. }
  392. MP4RtpImmediateData* pData = new MP4RtpImmediateData(pPacket);
  393. pData->Set(pBytes, numBytes);
  394. pPacket->AddData(pData);
  395. m_bytesThisHint += numBytes;
  396. m_bytesThisPacket += numBytes;
  397. m_pDimm->IncrementValue(numBytes);
  398. m_pTpyl->IncrementValue(numBytes);
  399. m_pTrpy->IncrementValue(numBytes);
  400. }
  401. void MP4RtpHintTrack::AddSampleData(
  402. MP4SampleId sampleId,
  403. u_int32_t dataOffset,
  404. u_int32_t dataLength)
  405. {
  406. if (m_pWriteHint == NULL) {
  407. throw new MP4Error("no hint pending", "MP4RtpAddSampleData");
  408. }
  409. MP4RtpPacket* pPacket = m_pWriteHint->GetCurrentPacket();
  410. if (pPacket == NULL) {
  411. throw new MP4Error("no packet pending", "MP4RtpAddSampleData");
  412. }
  413. MP4RtpSampleData* pData = new MP4RtpSampleData(pPacket);
  414. pData->SetReferenceSample(sampleId, dataOffset, dataLength);
  415. pPacket->AddData(pData);
  416. m_bytesThisHint += dataLength;
  417. m_bytesThisPacket += dataLength;
  418. m_pDmed->IncrementValue(dataLength);
  419. m_pTpyl->IncrementValue(dataLength);
  420. m_pTrpy->IncrementValue(dataLength);
  421. }
  422. void MP4RtpHintTrack::AddESConfigurationPacket()
  423. {
  424. if (m_pWriteHint == NULL) {
  425. throw new MP4Error("no hint pending", 
  426. "MP4RtpAddESConfigurationPacket");
  427. }
  428. u_int8_t* pConfig = NULL;
  429. u_int32_t configSize = 0;
  430. m_pFile->GetTrackESConfiguration(m_pRefTrack->GetId(),
  431. &pConfig, &configSize);
  432. if (pConfig == NULL) {
  433. return;
  434. }
  435. ASSERT(m_pMaxPacketSizeProperty);
  436. if (configSize > m_pMaxPacketSizeProperty->GetValue()) {
  437. throw new MP4Error("ES configuration is too large for RTP payload",
  438. "MP4RtpAddESConfigurationPacket");
  439. }
  440. AddPacket(false);
  441. MP4RtpPacket* pPacket = m_pWriteHint->GetCurrentPacket();
  442. ASSERT(pPacket);
  443. // This is ugly!
  444. // To get the ES configuration data somewhere known
  445. // we create a sample data reference that points to 
  446. // this hint track (not the media track)
  447. // and this sample of the hint track 
  448. // the offset into this sample is filled in during the write process
  449. MP4RtpSampleData* pData = new MP4RtpSampleData(pPacket);
  450. pData->SetEmbeddedImmediate(m_writeSampleId, pConfig, configSize);
  451. pPacket->AddData(pData);
  452. m_bytesThisHint += configSize;
  453. m_bytesThisPacket += configSize;
  454. m_pTpyl->IncrementValue(configSize);
  455. m_pTrpy->IncrementValue(configSize);
  456. }
  457. void MP4RtpHintTrack::WriteHint(MP4Duration duration, bool isSyncSample)
  458. {
  459. if (m_pWriteHint == NULL) {
  460. throw new MP4Error("no hint pending", "MP4WriteRtpHint");
  461. }
  462. u_int8_t* pBytes;
  463. u_int64_t numBytes;
  464. m_pFile->EnableMemoryBuffer();
  465. m_pWriteHint->Write(m_pFile);
  466. m_pFile->DisableMemoryBuffer(&pBytes, &numBytes);
  467. WriteSample(pBytes, numBytes, duration, 0, isSyncSample);
  468. MP4Free(pBytes);
  469. // update statistics
  470. if (m_bytesThisPacket > m_pPmax->GetValue()) {
  471. m_pPmax->SetValue(m_bytesThisPacket);
  472. }
  473. if (duration > m_pDmax->GetValue()) {
  474. m_pDmax->SetValue(duration);
  475. }
  476. MP4Timestamp startTime;
  477. GetSampleTimes(m_writeHintId, &startTime, NULL);
  478. if (startTime < m_thisSec + GetTimeScale()) {
  479. m_bytesThisSec += m_bytesThisHint;
  480. } else {
  481. if (m_bytesThisSec > m_pMaxr->GetValue()) {
  482. m_pMaxr->SetValue(m_bytesThisSec);
  483. }
  484. m_thisSec = startTime - (startTime % GetTimeScale());
  485. m_bytesThisSec = m_bytesThisHint;
  486. }
  487. // cleanup
  488. delete m_pWriteHint;
  489. m_pWriteHint = NULL;
  490. }
  491. void MP4RtpHintTrack::FinishWrite()
  492. {
  493. if (m_writeHintId != MP4_INVALID_SAMPLE_ID) {
  494. m_pMaxPdu->SetValue(m_pPmax->GetValue());
  495. if (m_pNump->GetValue()) {
  496. m_pAvgPdu->SetValue(m_pTrpy->GetValue() / m_pNump->GetValue());
  497. }
  498. m_pMaxBitRate->SetValue(m_pMaxr->GetValue() * 8);
  499. if (GetDuration()) {
  500. m_pAvgBitRate->SetValue(
  501. m_pTrpy->GetValue() * 8 * GetTimeScale() / GetDuration());
  502. }
  503. }
  504. MP4Track::FinishWrite();
  505. }
  506. void MP4RtpHintTrack::InitStats()
  507. {
  508. MP4Atom* pHinfAtom = m_pTrakAtom->FindAtom("trak.udta.hinf");
  509. ASSERT(pHinfAtom);
  510. pHinfAtom->FindProperty("hinf.trpy.bytes", (MP4Property**)&m_pTrpy); 
  511. pHinfAtom->FindProperty("hinf.nump.packets", (MP4Property**)&m_pNump); 
  512. pHinfAtom->FindProperty("hinf.tpyl.bytes", (MP4Property**)&m_pTpyl); 
  513. pHinfAtom->FindProperty("hinf.maxr.bytes", (MP4Property**)&m_pMaxr); 
  514. pHinfAtom->FindProperty("hinf.dmed.bytes", (MP4Property**)&m_pDmed); 
  515. pHinfAtom->FindProperty("hinf.dimm.bytes", (MP4Property**)&m_pDimm); 
  516. pHinfAtom->FindProperty("hinf.pmax.bytes", (MP4Property**)&m_pPmax); 
  517. pHinfAtom->FindProperty("hinf.dmax.milliSecs", (MP4Property**)&m_pDmax); 
  518. MP4Atom* pHmhdAtom = m_pTrakAtom->FindAtom("trak.mdia.minf.hmhd");
  519. ASSERT(pHmhdAtom);
  520. pHmhdAtom->FindProperty("hmhd.maxPduSize", (MP4Property**)&m_pMaxPdu); 
  521. pHmhdAtom->FindProperty("hmhd.avgPduSize", (MP4Property**)&m_pAvgPdu); 
  522. pHmhdAtom->FindProperty("hmhd.maxBitRate", (MP4Property**)&m_pMaxBitRate); 
  523. pHmhdAtom->FindProperty("hmhd.avgBitRate", (MP4Property**)&m_pAvgBitRate); 
  524. MP4Integer32Property* pMaxrPeriod = NULL;
  525. pHinfAtom->FindProperty("hinf.maxr.granularity",
  526.  (MP4Property**)&pMaxrPeriod); 
  527. if (pMaxrPeriod) {
  528. pMaxrPeriod->SetValue(1000); // 1 second
  529. }
  530. }
  531. MP4RtpHint::MP4RtpHint(MP4RtpHintTrack* pTrack)
  532. {
  533. m_pTrack = pTrack;
  534. AddProperty( /* 0 */
  535. new MP4Integer16Property("packetCount"));
  536. AddProperty( /* 1 */
  537. new MP4Integer16Property("reserved"));
  538. }
  539. MP4RtpHint::~MP4RtpHint()
  540. {
  541. for (u_int32_t i = 0; i < m_rtpPackets.Size(); i++) {
  542. delete m_rtpPackets[i];
  543. }
  544. }
  545. MP4RtpPacket* MP4RtpHint::AddPacket() 
  546. {
  547. MP4RtpPacket* pPacket = new MP4RtpPacket(this);
  548. m_rtpPackets.Add(pPacket);
  549. // packetCount property
  550. ((MP4Integer16Property*)m_pProperties[0])->IncrementValue();
  551. pPacket->SetBFrame(m_isBFrame);
  552. pPacket->SetTimestampOffset(m_timestampOffset);
  553. return pPacket;
  554. }
  555. void MP4RtpHint::Read(MP4File* pFile)
  556. {
  557. // call base class Read for required properties
  558. MP4Container::Read(pFile);
  559. u_int16_t numPackets =
  560. ((MP4Integer16Property*)m_pProperties[0])->GetValue();
  561. for (u_int16_t i = 0; i < numPackets; i++) {
  562. MP4RtpPacket* pPacket = new MP4RtpPacket(this);
  563. m_rtpPackets.Add(pPacket);
  564. pPacket->Read(pFile);
  565. }
  566. VERBOSE_READ_HINT(pFile->GetVerbosity(),
  567. printf("ReadHint:n"); Dump(stdout, 10, false););
  568. }
  569. void MP4RtpHint::Write(MP4File* pFile)
  570. {
  571. u_int64_t hintStartPos = pFile->GetPosition();
  572. MP4Container::Write(pFile);
  573. u_int64_t packetStartPos = pFile->GetPosition();
  574. u_int32_t i;
  575. // first write out packet (and data) entries
  576. for (i = 0; i < m_rtpPackets.Size(); i++) {
  577. m_rtpPackets[i]->Write(pFile);
  578. }
  579. // now let packets write their extra data into the hint sample
  580. for (i = 0; i < m_rtpPackets.Size(); i++) {
  581. m_rtpPackets[i]->WriteEmbeddedData(pFile, hintStartPos);
  582. }
  583. u_int64_t endPos = pFile->GetPosition();
  584. pFile->SetPosition(packetStartPos);
  585. // finally rewrite the packet and data entries
  586. // which now contain the correct offsets for the embedded data
  587. for (i = 0; i < m_rtpPackets.Size(); i++) {
  588. m_rtpPackets[i]->Write(pFile);
  589. }
  590. pFile->SetPosition(endPos);
  591. VERBOSE_WRITE_HINT(pFile->GetVerbosity(),
  592. printf("WriteRtpHint:n"); Dump(stdout, 14, false));
  593. }
  594. void MP4RtpHint::Dump(FILE* pFile, u_int8_t indent, bool dumpImplicits)
  595. {
  596. MP4Container::Dump(pFile, indent, dumpImplicits);
  597. for (u_int32_t i = 0; i < m_rtpPackets.Size(); i++) {
  598. Indent(pFile, indent);
  599. fprintf(pFile, "RtpPacket: %un", i);
  600. m_rtpPackets[i]->Dump(pFile, indent + 1, dumpImplicits);
  601. }
  602. }
  603. MP4RtpPacket::MP4RtpPacket(MP4RtpHint* pHint)
  604. {
  605. m_pHint = pHint;
  606. AddProperty( /* 0 */
  607. new MP4Integer32Property("relativeXmitTime"));
  608. AddProperty( /* 1 */
  609. new MP4BitfieldProperty("reserved1", 2));
  610. AddProperty( /* 2 */
  611. new MP4BitfieldProperty("Pbit", 1));
  612. AddProperty( /* 3 */
  613. new MP4BitfieldProperty("Xbit", 1));
  614. AddProperty( /* 4 */
  615. new MP4BitfieldProperty("reserved2", 4));
  616. AddProperty( /* 5 */
  617. new MP4BitfieldProperty("Mbit", 1));
  618. AddProperty( /* 6 */
  619. new MP4BitfieldProperty("payloadType", 7));
  620. AddProperty( /* 7  */
  621. new MP4Integer16Property("sequenceNumber"));
  622. AddProperty( /* 8 */
  623. new MP4BitfieldProperty("reserved3", 13));
  624. AddProperty( /* 9 */
  625. new MP4BitfieldProperty("extraFlag", 1));
  626. AddProperty( /* 10 */
  627. new MP4BitfieldProperty("bFrameFlag", 1));
  628. AddProperty( /* 11 */
  629. new MP4BitfieldProperty("repeatFlag", 1));
  630. AddProperty( /* 12 */
  631. new MP4Integer16Property("entryCount"));
  632. }
  633.  
  634. MP4RtpPacket::~MP4RtpPacket()
  635. {
  636. for (u_int32_t i = 0; i < m_rtpData.Size(); i++) {
  637. delete m_rtpData[i];
  638. }
  639. }
  640. void MP4RtpPacket::AddExtraProperties()
  641. {
  642. AddProperty( /* 13 */
  643. new MP4Integer32Property("extraInformationLength"));
  644. // This is a bit of a hack, since the tlv entries are really defined 
  645. // as atoms but there is only one type defined now, rtpo, and getting 
  646. // our atom code hooked up here would be a major pain with little gain
  647. AddProperty( /* 14 */
  648. new MP4Integer32Property("tlvLength"));
  649. AddProperty( /* 15 */
  650. new MP4StringProperty("tlvType"));
  651. AddProperty( /* 16 */
  652. new MP4Integer32Property("timestampOffset"));
  653. ((MP4Integer32Property*)m_pProperties[13])->SetValue(16);
  654. ((MP4Integer32Property*)m_pProperties[14])->SetValue(12);
  655. ((MP4StringProperty*)m_pProperties[15])->SetFixedLength(4);
  656. ((MP4StringProperty*)m_pProperties[15])->SetValue("rtpo");
  657. }
  658. void MP4RtpPacket::Read(MP4File* pFile)
  659. {
  660. // call base class Read for required properties
  661. MP4Container::Read(pFile);
  662. // read extra info if present
  663. // we only support the rtpo field!
  664. if (((MP4BitfieldProperty*)m_pProperties[9])->GetValue() == 1) {
  665. ReadExtra(pFile);
  666. }
  667. u_int16_t numDataEntries =
  668. ((MP4Integer16Property*)m_pProperties[12])->GetValue();
  669. // read data entries
  670. for (u_int16_t i = 0; i < numDataEntries; i++) {
  671. u_int8_t dataType;
  672. pFile->PeekBytes(&dataType, 1);
  673. MP4RtpData* pData;
  674. switch (dataType) {
  675. case 0:
  676. pData = new MP4RtpNullData(this);
  677. break;
  678. case 1:
  679. pData = new MP4RtpImmediateData(this);
  680. break;
  681. case 2:
  682. pData = new MP4RtpSampleData(this);
  683. break;
  684. case 3:
  685. pData = new MP4RtpSampleDescriptionData(this);
  686. break;
  687. default:
  688. throw new MP4Error("unknown packet data entry type",
  689. "MP4ReadHint");
  690. }
  691. m_rtpData.Add(pData);
  692. // read data entry's properties
  693. pData->Read(pFile);
  694. }
  695. }
  696. void MP4RtpPacket::ReadExtra(MP4File* pFile)
  697. {
  698. AddExtraProperties();
  699. int32_t extraLength = (int32_t)pFile->ReadUInt32();
  700. if (extraLength < 4) {
  701. throw new MP4Error("bad packet extra info length",
  702. "MP4RtpPacket::ReadExtra");
  703. }
  704. extraLength -= 4;
  705. while (extraLength > 0) {
  706. u_int32_t entryLength = pFile->ReadUInt32();
  707. u_int32_t entryTag = pFile->ReadUInt32();
  708. if (entryLength < 8) {
  709. throw new MP4Error("bad packet extra info entry length",
  710. "MP4RtpPacket::ReadExtra");
  711. }
  712. if (entryTag == STRTOINT32("rtpo") && entryLength == 12) {
  713. // read the rtp timestamp offset
  714. m_pProperties[16]->Read(pFile);
  715. } else {
  716. // ignore it, LATER carry it along
  717. pFile->SetPosition(pFile->GetPosition() + entryLength - 8);
  718. }
  719. extraLength -= entryLength;
  720. }
  721. if (extraLength < 0) {
  722. throw new MP4Error("invalid packet extra info length",
  723. "MP4RtpPacket::ReadExtra");
  724. }
  725. }
  726. void MP4RtpPacket::Set(u_int8_t payloadNumber, 
  727. u_int32_t packetId, bool setMbit)
  728. {
  729. ((MP4BitfieldProperty*)m_pProperties[5])->SetValue(setMbit);
  730. ((MP4BitfieldProperty*)m_pProperties[6])->SetValue(payloadNumber);
  731. ((MP4Integer16Property*)m_pProperties[7])->SetValue(packetId);
  732. }
  733. int32_t MP4RtpPacket::GetTransmitOffset()
  734. {
  735. return ((MP4Integer32Property*)m_pProperties[0])->GetValue();
  736. }
  737. void MP4RtpPacket::SetTransmitOffset(int32_t transmitOffset)
  738. {
  739. ((MP4Integer32Property*)m_pProperties[0])->SetValue(transmitOffset);
  740. }
  741. bool MP4RtpPacket::GetPBit()
  742. {
  743. return ((MP4BitfieldProperty*)m_pProperties[2])->GetValue();
  744. }
  745. bool MP4RtpPacket::GetXBit()
  746. {
  747. return ((MP4BitfieldProperty*)m_pProperties[3])->GetValue();
  748. }
  749. bool MP4RtpPacket::GetMBit()
  750. {
  751. return ((MP4BitfieldProperty*)m_pProperties[5])->GetValue();
  752. }
  753. u_int8_t MP4RtpPacket::GetPayload()
  754. {
  755. return ((MP4BitfieldProperty*)m_pProperties[6])->GetValue();
  756. }
  757. u_int16_t MP4RtpPacket::GetSequenceNumber()
  758. {
  759. return ((MP4Integer16Property*)m_pProperties[7])->GetValue();
  760. }
  761. bool MP4RtpPacket::IsBFrame()
  762. {
  763. return ((MP4BitfieldProperty*)m_pProperties[10])->GetValue();
  764. }
  765. void MP4RtpPacket::SetBFrame(bool isBFrame)
  766. {
  767. ((MP4BitfieldProperty*)m_pProperties[10])->SetValue(isBFrame);
  768. }
  769. void MP4RtpPacket::SetTimestampOffset(u_int32_t timestampOffset)
  770. {
  771. if (timestampOffset == 0) {
  772. return;
  773. }
  774. ASSERT(((MP4BitfieldProperty*)m_pProperties[9])->GetValue() == 0);
  775. // set X bit
  776. ((MP4BitfieldProperty*)m_pProperties[9])->SetValue(1);
  777. AddExtraProperties();
  778. ((MP4Integer32Property*)m_pProperties[16])->SetValue(timestampOffset);
  779. }
  780. void MP4RtpPacket::AddData(MP4RtpData* pData)
  781. {
  782. m_rtpData.Add(pData);
  783. // increment entry count property
  784. ((MP4Integer16Property*)m_pProperties[12])->IncrementValue();
  785. }
  786. u_int32_t MP4RtpPacket::GetDataSize()
  787. {
  788. u_int32_t totalDataSize = 0;
  789. for (u_int32_t i = 0; i < m_rtpData.Size(); i++) {
  790. totalDataSize += m_rtpData[i]->GetDataSize();
  791. }
  792. return totalDataSize;
  793. }
  794. void MP4RtpPacket::GetData(u_int8_t* pDest)
  795. {
  796. for (u_int32_t i = 0; i < m_rtpData.Size(); i++) {
  797. m_rtpData[i]->GetData(pDest);
  798. pDest += m_rtpData[i]->GetDataSize();
  799. }
  800. }
  801. void MP4RtpPacket::Write(MP4File* pFile)
  802. {
  803. MP4Container::Write(pFile);
  804. for (u_int32_t i = 0; i < m_rtpData.Size(); i++) {
  805. m_rtpData[i]->Write(pFile);
  806. }
  807. }
  808. void MP4RtpPacket::WriteEmbeddedData(MP4File* pFile, u_int64_t startPos)
  809. {
  810. for (u_int32_t i = 0; i < m_rtpData.Size(); i++) {
  811. m_rtpData[i]->WriteEmbeddedData(pFile, startPos);
  812. }
  813. }
  814. void MP4RtpPacket::Dump(FILE* pFile, u_int8_t indent, bool dumpImplicits)
  815. {
  816. MP4Container::Dump(pFile, indent, dumpImplicits);
  817. for (u_int32_t i = 0; i < m_rtpData.Size(); i++) {
  818. Indent(pFile, indent);
  819. fprintf(pFile, "RtpData: %un", i);
  820. m_rtpData[i]->Dump(pFile, indent + 1, dumpImplicits);
  821. }
  822. }
  823. MP4RtpData::MP4RtpData(MP4RtpPacket* pPacket)
  824. {
  825. m_pPacket = pPacket;
  826. AddProperty( /* 0 */
  827. new MP4Integer8Property("type"));
  828. }
  829. MP4Track* MP4RtpData::FindTrackFromRefIndex(u_int8_t refIndex)
  830. {
  831. MP4Track* pTrack;
  832. if (refIndex == (u_int8_t)-1) {
  833. // ourselves
  834. pTrack = GetPacket()->GetHint()->GetTrack();
  835. } else if (refIndex == 0) {
  836. // our reference track
  837. pTrack = GetPacket()->GetHint()->GetTrack()->GetRefTrack();
  838. } else {
  839. // some other track
  840. MP4RtpHintTrack* pHintTrack =
  841. GetPacket()->GetHint()->GetTrack();
  842. MP4Atom* pTrakAtom = pHintTrack->GetTrakAtom();
  843. ASSERT(pTrakAtom);
  844. MP4Integer32Property* pTrackIdProperty = NULL;
  845. pTrakAtom->FindProperty(
  846. "trak.tref.hint.entries",
  847. (MP4Property**)&pTrackIdProperty);
  848. ASSERT(pTrackIdProperty);
  849. u_int32_t refTrackId = 
  850. pTrackIdProperty->GetValue(refIndex - 1);
  851. pTrack = pHintTrack->GetFile()->GetTrack(refTrackId); 
  852. }
  853. return pTrack;
  854. }
  855. MP4RtpNullData::MP4RtpNullData(MP4RtpPacket* pPacket)
  856. : MP4RtpData(pPacket)
  857. {
  858. ((MP4Integer8Property*)m_pProperties[0])->SetValue(0);
  859. AddProperty( /* 1 */
  860. new MP4BytesProperty("pad", 15));
  861. ((MP4BytesProperty*)m_pProperties[1])->SetFixedSize(15);
  862. }
  863. MP4RtpImmediateData::MP4RtpImmediateData(MP4RtpPacket* pPacket)
  864. : MP4RtpData(pPacket)
  865. {
  866. ((MP4Integer8Property*)m_pProperties[0])->SetValue(1);
  867. AddProperty( /* 1 */
  868. new MP4Integer8Property("count"));
  869. AddProperty( /* 2 */
  870. new MP4BytesProperty("data", 14));
  871. ((MP4BytesProperty*)m_pProperties[2])->SetFixedSize(14);
  872. }
  873. void MP4RtpImmediateData::Set(const u_int8_t* pBytes, u_int8_t numBytes)
  874. {
  875. ((MP4Integer8Property*)m_pProperties[1])->SetValue(numBytes);
  876. ((MP4BytesProperty*)m_pProperties[2])->SetValue(pBytes, numBytes);
  877. }
  878. u_int16_t MP4RtpImmediateData::GetDataSize()
  879. {
  880. return ((MP4Integer8Property*)m_pProperties[1])->GetValue();
  881. }
  882. void MP4RtpImmediateData::GetData(u_int8_t* pDest)
  883. {
  884. u_int8_t* pValue;
  885. u_int32_t valueSize;
  886. ((MP4BytesProperty*)m_pProperties[2])->GetValue(&pValue, &valueSize);
  887. memcpy(pDest, pValue, GetDataSize());
  888. MP4Free(pValue);
  889. }
  890. MP4RtpSampleData::MP4RtpSampleData(MP4RtpPacket* pPacket)
  891. : MP4RtpData(pPacket)
  892. {
  893. ((MP4Integer8Property*)m_pProperties[0])->SetValue(2);
  894. AddProperty( /* 1 */
  895. new MP4Integer8Property("trackRefIndex"));
  896. AddProperty( /* 2 */
  897. new MP4Integer16Property("length"));
  898. AddProperty( /* 3 */
  899. new MP4Integer32Property("sampleNumber"));
  900. AddProperty( /* 4 */
  901. new MP4Integer32Property("sampleOffset"));
  902. AddProperty( /* 5 */
  903. new MP4Integer16Property("bytesPerBlock"));
  904. AddProperty( /* 6 */
  905. new MP4Integer16Property("samplesPerBlock"));
  906. ((MP4Integer16Property*)m_pProperties[5])->SetValue(1);
  907. ((MP4Integer16Property*)m_pProperties[6])->SetValue(1);
  908. m_pRefData = NULL;
  909. m_pRefTrack = NULL;
  910. m_refSampleId = MP4_INVALID_SAMPLE_ID;
  911. m_refSampleOffset = 0;
  912. }
  913. void MP4RtpSampleData::SetEmbeddedImmediate(MP4SampleId sampleId, 
  914. u_int8_t* pData, u_int16_t dataLength)
  915. {
  916. ((MP4Integer8Property*)m_pProperties[1])->SetValue((u_int8_t)-1);
  917. ((MP4Integer16Property*)m_pProperties[2])->SetValue(dataLength);
  918. ((MP4Integer32Property*)m_pProperties[3])->SetValue(sampleId);
  919. ((MP4Integer32Property*)m_pProperties[4])->SetValue(0); 
  920. m_pRefData = pData;
  921. }
  922. void MP4RtpSampleData::SetReferenceSample(
  923. MP4SampleId refSampleId, u_int32_t refSampleOffset, 
  924. u_int16_t sampleLength)
  925. {
  926. ((MP4Integer8Property*)m_pProperties[1])->SetValue(0);
  927. ((MP4Integer16Property*)m_pProperties[2])->SetValue(sampleLength);
  928. ((MP4Integer32Property*)m_pProperties[3])->SetValue(refSampleId);
  929. ((MP4Integer32Property*)m_pProperties[4])->SetValue(refSampleOffset);
  930. }
  931. void MP4RtpSampleData::SetEmbeddedSample(
  932. MP4SampleId sampleId, MP4Track* pRefTrack,
  933. MP4SampleId refSampleId, u_int32_t refSampleOffset, 
  934. u_int16_t sampleLength)
  935. {
  936. ((MP4Integer8Property*)m_pProperties[1])->SetValue((u_int8_t)-1);
  937. ((MP4Integer16Property*)m_pProperties[2])->SetValue(sampleLength);
  938. ((MP4Integer32Property*)m_pProperties[3])->SetValue(sampleId);
  939. ((MP4Integer32Property*)m_pProperties[4])->SetValue(0);
  940. m_pRefTrack = pRefTrack;
  941. m_refSampleId = refSampleId;
  942. m_refSampleOffset = refSampleOffset;
  943. }
  944. u_int16_t MP4RtpSampleData::GetDataSize()
  945. {
  946. return ((MP4Integer16Property*)m_pProperties[2])->GetValue();
  947. }
  948. void MP4RtpSampleData::GetData(u_int8_t* pDest)
  949. {
  950. u_int8_t trackRefIndex = 
  951. ((MP4Integer8Property*)m_pProperties[1])->GetValue();
  952. MP4Track* pSampleTrack =
  953. FindTrackFromRefIndex(trackRefIndex);
  954. pSampleTrack->ReadSampleFragment(
  955. ((MP4Integer32Property*)m_pProperties[3])->GetValue(), // sampleId 
  956. ((MP4Integer32Property*)m_pProperties[4])->GetValue(), // sampleOffset
  957. ((MP4Integer16Property*)m_pProperties[2])->GetValue(), // sampleLength
  958. pDest);
  959. }
  960. void MP4RtpSampleData::WriteEmbeddedData(MP4File* pFile, u_int64_t startPos)
  961. {
  962. // if not using embedded data, nothing to do
  963. if (((MP4Integer8Property*)m_pProperties[1])->GetValue() != (u_int8_t)-1) {
  964. return;
  965. }
  966. // figure out the offset within this hint sample for this embedded data
  967. u_int64_t offset = pFile->GetPosition() - startPos;
  968. ASSERT(offset <= 0xFFFFFFFF);
  969. ((MP4Integer32Property*)m_pProperties[4])->SetValue((u_int32_t)offset);
  970. u_int16_t length = ((MP4Integer16Property*)m_pProperties[2])->GetValue();
  971. if (m_pRefData) {
  972. pFile->WriteBytes(m_pRefData, length);
  973. return;
  974. if (m_refSampleId != MP4_INVALID_SAMPLE_ID) {
  975. u_int8_t* pSample = NULL;
  976. u_int32_t sampleSize = 0;
  977. ASSERT(m_pRefTrack);
  978. m_pRefTrack->ReadSample(m_refSampleId, &pSample, &sampleSize);
  979. ASSERT(m_refSampleOffset + length <= sampleSize);
  980. pFile->WriteBytes(&pSample[m_refSampleOffset], length);
  981. MP4Free(pSample);
  982. return;
  983. }
  984. }
  985. MP4RtpSampleDescriptionData::MP4RtpSampleDescriptionData(MP4RtpPacket* pPacket)
  986. : MP4RtpData(pPacket)
  987. {
  988. ((MP4Integer8Property*)m_pProperties[0])->SetValue(3);
  989. AddProperty( /* 1 */
  990. new MP4Integer8Property("trackRefIndex"));
  991. AddProperty( /* 2 */
  992. new MP4Integer16Property("length"));
  993. AddProperty( /* 3 */
  994. new MP4Integer32Property("sampleDescriptionIndex"));
  995. AddProperty( /* 4 */
  996. new MP4Integer32Property("sampleDescriptionOffset"));
  997. AddProperty( /* 5 */
  998. new MP4Integer32Property("reserved"));
  999. }
  1000. void MP4RtpSampleDescriptionData::Set(u_int32_t sampleDescrIndex,
  1001. u_int32_t offset, u_int16_t length)
  1002. {
  1003. ((MP4Integer16Property*)m_pProperties[2])->SetValue(length);
  1004. ((MP4Integer32Property*)m_pProperties[3])->SetValue(sampleDescrIndex);
  1005. ((MP4Integer32Property*)m_pProperties[4])->SetValue(offset);
  1006. }
  1007. u_int16_t MP4RtpSampleDescriptionData::GetDataSize()
  1008. {
  1009. return ((MP4Integer16Property*)m_pProperties[2])->GetValue();
  1010. }
  1011. void MP4RtpSampleDescriptionData::GetData(u_int8_t* pDest)
  1012. {
  1013. // we start with the index into our track references
  1014. u_int8_t trackRefIndex = 
  1015. ((MP4Integer8Property*)m_pProperties[1])->GetValue();
  1016. // from which we can find the track structure
  1017. MP4Track* pSampleTrack =
  1018. FindTrackFromRefIndex(trackRefIndex);
  1019. // next find the desired atom in the track's sample description table
  1020. u_int32_t sampleDescrIndex =
  1021. ((MP4Integer32Property*)m_pProperties[3])->GetValue();
  1022. MP4Atom* pTrakAtom =
  1023. pSampleTrack->GetTrakAtom();
  1024. char sdName[64];
  1025. sprintf(sdName, "trak.mdia.minf.stbl.stsd.*[%u]", sampleDescrIndex);
  1026. MP4Atom* pSdAtom =
  1027. pTrakAtom->FindAtom(sdName);
  1028. // bad reference
  1029. if (pSdAtom == NULL) {
  1030. throw new MP4Error("invalid sample description index",
  1031. "MP4RtpSampleDescriptionData::GetData");
  1032. }
  1033. // check validity of the upcoming copy
  1034. u_int16_t length = 
  1035. ((MP4Integer16Property*)m_pProperties[2])->GetValue();
  1036. u_int32_t offset =
  1037. ((MP4Integer32Property*)m_pProperties[4])->GetValue();
  1038. if (offset + length > pSdAtom->GetSize()) {
  1039. throw new MP4Error("offset and/or length are too large", 
  1040. "MP4RtpSampleDescriptionData::GetData");
  1041. }
  1042. // now we use the raw file to get the desired bytes
  1043. MP4File* pFile = GetPacket()->GetHint()->GetTrack()->GetFile();
  1044. u_int64_t orgPos = pFile->GetPosition();
  1045. // It's not entirely clear from the spec whether the offset is from 
  1046. // the start of the sample descirption atom, or the start of the atom's
  1047. // data. I believe it is the former, but the commented out code will 
  1048. // realize the latter interpretation if I turn out to be wrong.
  1049. u_int64_t dataPos = pSdAtom->GetStart();
  1050. //u_int64_t dataPos = pSdAtom->GetEnd() - pSdAtom->GetSize();
  1051. pFile->SetPosition(dataPos + offset);
  1052. pFile->ReadBytes(pDest, length);
  1053. pFile->SetPosition(orgPos);
  1054. }