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

流媒体/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. 2000, 2001.  All Rights Reserved.
  17.  * 
  18.  * Contributor(s): 
  19.  * Dave Mackie dmackie@cisco.com
  20.  */
  21. // DEBUG #define MP4V_DEBUG 1
  22. /* 
  23.  * Notes:
  24.  *  - file formatted with tabstops == 4 spaces 
  25.  */
  26. #include <mp4creator.h>
  27. /*
  28.  * Load the next syntatic object from the file
  29.  * into the supplied buffer, which better be large enough!
  30.  *
  31.  * Objects are delineated by 4 byte start codes (0x00 0x00 0x01 0x??)
  32.  * Objects are padded to byte boundaries, and the encoder assures that
  33.  * the start code pattern is never generated for encoded data
  34.  */
  35. static int LoadNextObject(FILE* inFile, 
  36. u_int8_t* pBuf, u_int32_t* pBufSize, u_int8_t* pObjCode)
  37. {
  38. static u_int8_t state = 0;
  39. static u_int8_t nextObjCode = 0;
  40. *pBufSize = 0;
  41. /* initial state, never read from file before */
  42. if (state == 0) {
  43. /*
  44.  * go looking for first sync word 
  45.  * we discard anything before this
  46.  */
  47. state = 1;
  48. while (state < 5) {
  49. /* read a byte */
  50. u_char b;
  51. if (fread(&b, 1, 1, inFile) == 0) {
  52. // EOF or IO error
  53. return 0;
  54. }
  55. switch (state) {
  56. case 1:
  57. if (b == 0) {
  58. state = 2;
  59. }
  60. break;
  61. case 2:
  62. if (b == 0) {
  63. state = 3;
  64. }
  65. break;
  66. case 3:
  67. if (b == 1) {
  68. state = 4;
  69. }
  70. break;
  71. case 4:
  72. pBuf[0] = 0;
  73. pBuf[1] = 0;
  74. pBuf[2] = 1;
  75. pBuf[3] = b;
  76. (*pObjCode) = (u_int)b;
  77. *pBufSize = 4;
  78. state = 5;
  79. break;
  80. }
  81. }
  82. /* we're primed now */
  83. state = 1;
  84. } else if (state == 5) {
  85. /* EOF was reached on last call */
  86. return 0;
  87. } else {
  88. /*
  89.  * We have next object code from prevous call 
  90.  * insert start code into buffer
  91.  */
  92. (*pObjCode) = nextObjCode;
  93. pBuf[(*pBufSize)++] = 0;
  94. pBuf[(*pBufSize)++] = 0;
  95. pBuf[(*pBufSize)++] = 1;
  96. pBuf[(*pBufSize)++] = (u_char)(*pObjCode);
  97. }
  98. /* read bytes, execute state machine */
  99. while (1) {
  100. /* read a byte */
  101. u_char b;
  102. if (fread(&b, 1, 1, inFile) == 0) {
  103. /* handle EOF */
  104. if (feof(inFile)) {
  105. switch (state) {
  106. case 3:
  107. pBuf[(*pBufSize)++] = 0;
  108. /* fall thru */
  109. case 2:
  110. pBuf[(*pBufSize)++] = 0;
  111. break;
  112. }
  113. state = 5;
  114. return 1;
  115. }
  116. /* else error */
  117. *pBufSize = 0;
  118. return 0;
  119. }
  120. switch (state) {
  121. case 1:
  122. if (b == 0) {
  123. state = 2;
  124. } else {
  125. pBuf[(*pBufSize)++] = b;
  126. }
  127. break;
  128. case 2:
  129. if (b == 0) {
  130. state = 3;
  131. } else {
  132. pBuf[(*pBufSize)++] = 0;
  133. pBuf[(*pBufSize)++] = b;
  134. state = 1;
  135. }
  136. break;
  137. case 3:
  138. if (b == 1) {
  139. state = 4;
  140. } else if (b == 0) {
  141. pBuf[(*pBufSize)++] = 0;
  142. // state remains 3
  143. } else {
  144. pBuf[(*pBufSize)++] = 0;
  145. pBuf[(*pBufSize)++] = 0;
  146. pBuf[(*pBufSize)++] = b;
  147. state = 1;
  148. }
  149. break;
  150. case 4:
  151. nextObjCode = b;
  152. state = 1;
  153. return 1;
  154. default:
  155. ASSERT(false);
  156. }
  157. }
  158. }
  159. MP4TrackId Mp4vCreator(MP4FileHandle mp4File, FILE* inFile)
  160. {
  161. bool rc; 
  162. u_int8_t sampleBuffer[256 * 1024];
  163. u_int8_t* pCurrentSample = sampleBuffer;
  164. u_int32_t maxSampleSize = sizeof(sampleBuffer);
  165. // the current syntactical object
  166. // typically 1:1 with a sample 
  167. // but not always, i.e. non-VOP's 
  168. u_int8_t* pObj = pCurrentSample;
  169. u_int32_t objSize;
  170. u_int8_t objType;
  171. // the current sample
  172. MP4SampleId sampleId = 1;
  173. MP4Timestamp currentSampleTime = 0;
  174. // the last reference VOP 
  175. MP4SampleId refVopId = 1;
  176. MP4Timestamp refVopTime = 0;
  177. // track configuration info
  178. u_int8_t videoProfileLevel = 0x03;
  179. u_int8_t timeBits = 15;
  180. u_int16_t timeTicks = 30000;
  181. u_int16_t frameDuration = 3000;
  182. u_int16_t frameWidth = 320;
  183. u_int16_t frameHeight = 240;
  184. u_int32_t esConfigSize = 0;
  185. // start reading objects until we get the first VOP
  186. while (LoadNextObject(inFile, pObj, &objSize, &objType)) {
  187. // guard against buffer overflow
  188. if (pObj + objSize >= pCurrentSample + maxSampleSize) {
  189. fprintf(stderr,
  190. "%s: buffer overflow, invalid video stream?n", ProgName);
  191. exit(EXIT_MP4V_CREATOR);
  192. }
  193. if (Verbosity & MP4_DETAILS_SAMPLE) {
  194. printf("MP4V type %x size %un",
  195. objType, objSize);
  196. }
  197. if (objType == MP4AV_MPEG4_VOSH_START) {
  198. MP4AV_Mpeg4ParseVosh(pObj, objSize, 
  199. &videoProfileLevel);
  200. } else if (objType == MP4AV_MPEG4_VOL_START) {
  201. MP4AV_Mpeg4ParseVol(pObj, objSize, 
  202. &timeBits, &timeTicks, &frameDuration, 
  203. &frameWidth, &frameHeight);
  204. #ifdef MP4V_DEBUG
  205. printf("ParseVol: timeBits %u timeTicks %u frameDuration %un",
  206. timeBits, timeTicks, frameDuration);
  207. #endif
  208. } else if (objType == MP4AV_MPEG4_VOP_START) {
  209. esConfigSize = pObj - pCurrentSample;
  210. // ready to set up mp4 track
  211. break;
  212. pObj += objSize;
  213. }
  214. // convert frame duration to canonical time scale
  215. // note zero value for frame duration signals variable rate video
  216. if (timeTicks == 0) {
  217. timeTicks = 1;
  218. }
  219. u_int32_t mp4FrameDuration;
  220. if (VideoFrameRate) {
  221. mp4FrameDuration = (u_int32_t)(((float)Mp4TimeScale) / VideoFrameRate);
  222. } else if (frameDuration) {
  223. mp4FrameDuration = (Mp4TimeScale * frameDuration) / timeTicks;
  224. } else {
  225. // the spec for embedded timing and the implementations that I've
  226. // seen all vary dramatically, so until things become clearer
  227. // we don't support these types of encoders
  228. fprintf(stderr,
  229. "%s: variable rate video stream signalled,"
  230. " please specify average frame rate with -r optionn",
  231.  ProgName);
  232. exit(EXIT_MP4V_CREATOR);
  233. }
  234. // create the new video track
  235. MP4TrackId trackId = 
  236. MP4AddVideoTrack(
  237. mp4File, 
  238. Mp4TimeScale,
  239. mp4FrameDuration, 
  240. frameWidth, 
  241. frameHeight, 
  242. MP4_MPEG4_VIDEO_TYPE);
  243. if (trackId == MP4_INVALID_TRACK_ID) {
  244. fprintf(stderr,
  245. "%s: can't create video trackn", ProgName);
  246. exit(EXIT_MP4V_CREATOR);
  247. }
  248. if (MP4GetNumberOfTracks(mp4File, MP4_VIDEO_TRACK_TYPE) == 1) {
  249. MP4SetVideoProfileLevel(mp4File, 
  250. MP4AV_Mpeg4VideoToSystemsProfileLevel(videoProfileLevel));
  251. }
  252. if (esConfigSize) {
  253. MP4SetTrackESConfiguration(mp4File, trackId, 
  254. pCurrentSample, esConfigSize);
  255. // move past ES config, so it doesn't go into first sample
  256. pCurrentSample += esConfigSize;
  257. }
  258. // now process the rest of the video stream
  259. while (true) {
  260. if (objType != MP4AV_MPEG4_VOP_START) {
  261. // keep it in the buffer until a VOP comes along
  262. pObj += objSize;
  263. } else { // we have a VOP
  264. u_int32_t sampleSize = (pObj + objSize) - pCurrentSample;
  265. u_char vopType = MP4AV_Mpeg4GetVopType(pObj, objSize);
  266. rc = MP4WriteSample(mp4File, trackId, 
  267. pCurrentSample, sampleSize,
  268. mp4FrameDuration, 0, vopType == 'I');
  269. if (!rc) {
  270. fprintf(stderr,
  271. "%s: can't write video frame %un",
  272.  ProgName, sampleId);
  273. exit(EXIT_MP4V_CREATOR);
  274. }
  275. // deal with rendering time offsets 
  276. // that can occur when B frames are being used 
  277. // which is the case for all profiles except Simple Profile
  278. if (vopType != 'B') {
  279. if (videoProfileLevel > 3) {
  280. #ifdef MP4V_DEBUG
  281. printf("sample %u %c renderingOffset %dn",
  282. refVopId, vopType, currentSampleTime - refVopTime);
  283. #endif
  284. MP4SetSampleRenderingOffset(
  285. mp4File, trackId, refVopId,
  286. currentSampleTime - refVopTime);
  287. }
  288. refVopId = sampleId;
  289. refVopTime = currentSampleTime;
  290. }
  291. sampleId++;
  292. currentSampleTime += mp4FrameDuration;
  293. // reset pointers
  294. pObj = pCurrentSample = sampleBuffer;
  295. }
  296. // load next object from bitstream
  297. if (!LoadNextObject(inFile, pObj, &objSize, &objType)) {
  298. break;
  299. }
  300. // guard against buffer overflow
  301. if (pObj + objSize >= pCurrentSample + maxSampleSize) {
  302. fprintf(stderr,
  303. "%s: buffer overflow, invalid video stream?n", ProgName);
  304. exit(EXIT_MP4V_CREATOR);
  305. }
  306. if (Verbosity & MP4_DETAILS_SAMPLE) {
  307. printf("MP4V type %x size %un",
  308. objType, objSize);
  309. }
  310. }
  311. return trackId;
  312. }