選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

553 行
17KB

  1. #include "mov-internal.h"
  2. #include <assert.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. // stsd: Sample Description Box
  7. int mp4_read_extra(struct mov_t* mov, const struct mov_box_t* box)
  8. {
  9. int r;
  10. uint64_t p1, p2;
  11. p1 = mov_buffer_tell(&mov->io);
  12. r = mov_reader_box(mov, box);
  13. p2 = mov_buffer_tell(&mov->io);
  14. mov_buffer_skip(&mov->io, box->size - (p2 - p1));
  15. return r;
  16. }
  17. /*
  18. aligned(8) abstract class SampleEntry (unsigned int(32) format)
  19. extends Box(format){
  20. const unsigned int(8)[6] reserved = 0;
  21. unsigned int(16) data_reference_index;
  22. }
  23. */
  24. static int mov_read_sample_entry(struct mov_t* mov, struct mov_box_t* box, uint16_t* data_reference_index)
  25. {
  26. box->size = mov_buffer_r32(&mov->io);
  27. box->type = mov_buffer_r32(&mov->io);
  28. mov_buffer_skip(&mov->io, 6); // const unsigned int(8)[6] reserved = 0;
  29. *data_reference_index = (uint16_t)mov_buffer_r16(&mov->io); // ref [dref]
  30. return 0;
  31. }
  32. /*
  33. class AudioSampleEntry(codingname) extends SampleEntry (codingname){
  34. const unsigned int(32)[2] reserved = 0;
  35. template unsigned int(16) channelcount = 2;
  36. template unsigned int(16) samplesize = 16;
  37. unsigned int(16) pre_defined = 0;
  38. const unsigned int(16) reserved = 0 ;
  39. template unsigned int(32) samplerate = { default samplerate of media}<<16;
  40. }
  41. */
  42. static int mov_read_audio(struct mov_t* mov, struct mov_sample_entry_t* entry)
  43. {
  44. uint16_t qtver;
  45. struct mov_box_t box;
  46. mov_read_sample_entry(mov, &box, &entry->data_reference_index);
  47. entry->object_type_indication = mov_tag_to_object(box.type);
  48. entry->stream_type = MP4_STREAM_AUDIO;
  49. mov->track->tag = box.type;
  50. #if 0
  51. // const unsigned int(32)[2] reserved = 0;
  52. mov_buffer_skip(&mov->io, 8);
  53. #else
  54. qtver = mov_buffer_r16(&mov->io); /* version */
  55. mov_buffer_r16(&mov->io); /* revision level */
  56. mov_buffer_r32(&mov->io); /* vendor */
  57. #endif
  58. entry->u.audio.channelcount = (uint16_t)mov_buffer_r16(&mov->io);
  59. entry->u.audio.samplesize = (uint16_t)mov_buffer_r16(&mov->io);
  60. #if 0
  61. // unsigned int(16) pre_defined = 0;
  62. // const unsigned int(16) reserved = 0 ;
  63. mov_buffer_skip(&mov->io, 4);
  64. #else
  65. mov_buffer_r16(&mov->io); /* audio cid */
  66. mov_buffer_r16(&mov->io); /* packet size = 0 */
  67. #endif
  68. entry->u.audio.samplerate = mov_buffer_r32(&mov->io); // { default samplerate of media}<<16;
  69. // audio extra(avc1: ISO/IEC 14496-14:2003(E))
  70. box.size -= 36;
  71. // https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-124774
  72. if (1 == qtver && box.size >= 16)
  73. {
  74. // Sound Sample Description (Version 1)
  75. mov_buffer_r32(&mov->io); // Samples per packet
  76. mov_buffer_r32(&mov->io); // Bytes per packet
  77. mov_buffer_r32(&mov->io); // Bytes per frame
  78. mov_buffer_r32(&mov->io); // Bytes per sample
  79. box.size -= 16;
  80. }
  81. else if (2 == qtver && box.size >= 36)
  82. {
  83. // Sound Sample Description (Version 2)
  84. mov_buffer_r32(&mov->io); // sizeOfStructOnly
  85. mov_buffer_r64(&mov->io); // audioSampleRate
  86. mov_buffer_r32(&mov->io); // numAudioChannels
  87. mov_buffer_r32(&mov->io); // always7F000000
  88. mov_buffer_r32(&mov->io); // constBitsPerChannel
  89. mov_buffer_r32(&mov->io); // formatSpecificFlags
  90. mov_buffer_r32(&mov->io); // constBytesPerAudioPacket
  91. mov_buffer_r32(&mov->io); // constLPCMFramesPerAudioPacket
  92. box.size -= 36;
  93. }
  94. return mp4_read_extra(mov, &box);
  95. }
  96. /*
  97. class VisualSampleEntry(codingname) extends SampleEntry (codingname){
  98. unsigned int(16) pre_defined = 0;
  99. const unsigned int(16) reserved = 0;
  100. unsigned int(32)[3] pre_defined = 0;
  101. unsigned int(16) width;
  102. unsigned int(16) height;
  103. template unsigned int(32) horizresolution = 0x00480000; // 72 dpi
  104. template unsigned int(32) vertresolution = 0x00480000; // 72 dpi
  105. const unsigned int(32) reserved = 0;
  106. template unsigned int(16) frame_count = 1;
  107. string[32] compressorname;
  108. template unsigned int(16) depth = 0x0018;
  109. int(16) pre_defined = -1;
  110. // other boxes from derived specifications
  111. CleanApertureBox clap; // optional
  112. PixelAspectRatioBox pasp; // optional
  113. }
  114. class AVCSampleEntry() extends VisualSampleEntry ('avc1'){
  115. AVCConfigurationBox config;
  116. MPEG4BitRateBox (); // optional
  117. MPEG4ExtensionDescriptorsBox (); // optional
  118. }
  119. class AVC2SampleEntry() extends VisualSampleEntry ('avc2'){
  120. AVCConfigurationBox avcconfig;
  121. MPEG4BitRateBox bitrate; // optional
  122. MPEG4ExtensionDescriptorsBox descr; // optional
  123. extra_boxes boxes; // optional
  124. }
  125. */
  126. static int mov_read_video(struct mov_t* mov, struct mov_sample_entry_t* entry)
  127. {
  128. struct mov_box_t box;
  129. mov_read_sample_entry(mov, &box, &entry->data_reference_index);
  130. entry->object_type_indication = mov_tag_to_object(box.type);
  131. entry->stream_type = MP4_STREAM_VISUAL;
  132. mov->track->tag = box.type;
  133. #if 1
  134. //unsigned int(16) pre_defined = 0;
  135. //const unsigned int(16) reserved = 0;
  136. //unsigned int(32)[3] pre_defined = 0;
  137. mov_buffer_skip(&mov->io, 16);
  138. #else
  139. mov_buffer_r16(&mov->io); /* version */
  140. mov_buffer_r16(&mov->io); /* revision level */
  141. mov_buffer_r32(&mov->io); /* vendor */
  142. mov_buffer_r32(&mov->io); /* temporal quality */
  143. mov_buffer_r32(&mov->io); /* spatial quality */
  144. #endif
  145. entry->u.visual.width = (uint16_t)mov_buffer_r16(&mov->io);
  146. entry->u.visual.height = (uint16_t)mov_buffer_r16(&mov->io);
  147. entry->u.visual.horizresolution = mov_buffer_r32(&mov->io); // 0x00480000 - 72 dpi
  148. entry->u.visual.vertresolution = mov_buffer_r32(&mov->io); // 0x00480000 - 72 dpi
  149. // const unsigned int(32) reserved = 0;
  150. mov_buffer_r32(&mov->io); /* data size, always 0 */
  151. entry->u.visual.frame_count = (uint16_t)mov_buffer_r16(&mov->io);
  152. //string[32] compressorname;
  153. //uint32_t len = mov_buffer_r8(&mov->io);
  154. //mov_buffer_skip(&mov->io, len);
  155. mov_buffer_skip(&mov->io, 32);
  156. entry->u.visual.depth = (uint16_t)mov_buffer_r16(&mov->io);
  157. // int(16) pre_defined = -1;
  158. mov_buffer_skip(&mov->io, 2);
  159. // video extra(avc1: ISO/IEC 14496-15:2010(E))
  160. box.size -= 86;
  161. return mp4_read_extra(mov, &box);
  162. }
  163. /*
  164. class PixelAspectRatioBox extends Box(‘pasp?{
  165. unsigned int(32) hSpacing;
  166. unsigned int(32) vSpacing;
  167. }
  168. */
  169. int mov_read_pasp(struct mov_t* mov, const struct mov_box_t* box)
  170. {
  171. mov_buffer_r32(&mov->io);
  172. mov_buffer_r32(&mov->io);
  173. (void)box;
  174. return 0;
  175. }
  176. static int mov_read_hint_sample_entry(struct mov_t* mov, struct mov_sample_entry_t* entry)
  177. {
  178. struct mov_box_t box;
  179. mov_read_sample_entry(mov, &box, &entry->data_reference_index);
  180. mov_buffer_skip(&mov->io, box.size - 16);
  181. mov->track->tag = box.type;
  182. return mov_buffer_error(&mov->io);
  183. }
  184. static int mov_read_meta_sample_entry(struct mov_t* mov, struct mov_sample_entry_t* entry)
  185. {
  186. struct mov_box_t box;
  187. mov_read_sample_entry(mov, &box, &entry->data_reference_index);
  188. mov_buffer_skip(&mov->io, box.size - 16);
  189. mov->track->tag = box.type;
  190. return mov_buffer_error(&mov->io);
  191. }
  192. // ISO/IEC 14496-12:2015(E) 12.5 Text media (p184)
  193. /*
  194. class PlainTextSampleEntry(codingname) extends SampleEntry (codingname) {
  195. }
  196. class SimpleTextSampleEntry(codingname) extends PlainTextSampleEntry ('stxt') {
  197. string content_encoding; // optional
  198. string mime_format;
  199. BitRateBox (); // optional
  200. TextConfigBox (); // optional
  201. }
  202. */
  203. static int mov_read_text_sample_entry(struct mov_t* mov, struct mov_sample_entry_t* entry)
  204. {
  205. struct mov_box_t box;
  206. mov_read_sample_entry(mov, &box, &entry->data_reference_index);
  207. if (MOV_TEXT == box.type)
  208. {
  209. // https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-69835
  210. //mov_buffer_r32(&mov->io); /* display flags */
  211. //mov_buffer_r32(&mov->io); /* text justification */
  212. //mov_buffer_r16(&mov->io); /* background color: 48-bit RGB color */
  213. //mov_buffer_r16(&mov->io);
  214. //mov_buffer_r16(&mov->io);
  215. //mov_buffer_r64(&mov->io); /* default text box (top, left, bottom, right) */
  216. //mov_buffer_r64(&mov->io); /* reserved */
  217. //mov_buffer_r16(&mov->io); /* font number */
  218. //mov_buffer_r16(&mov->io); /* font face */
  219. //mov_buffer_r8(&mov->io); /* reserved */
  220. //mov_buffer_r16(&mov->io); /* reserved */
  221. //mov_buffer_r16(&mov->io); /* foreground color: 48-bit RGB color */
  222. //mov_buffer_r16(&mov->io);
  223. //mov_buffer_r16(&mov->io);
  224. ////mov_buffer_r16(&mov->io); /* text name */
  225. mov_buffer_skip(&mov->io, box.size - 16);
  226. }
  227. else
  228. {
  229. mov_buffer_skip(&mov->io, box.size - 16);
  230. }
  231. mov->track->tag = box.type;
  232. return mov_buffer_error(&mov->io);
  233. }
  234. // ISO/IEC 14496-12:2015(E) 12.6 Subtitle media (p185)
  235. /*
  236. class SubtitleSampleEntry(codingname) extends SampleEntry (codingname) {
  237. }
  238. class XMLSubtitleSampleEntry() extends SubtitleSampleEntry('stpp') {
  239. string namespace;
  240. string schema_location; // optional
  241. string auxiliary_mime_types;
  242. // optional, required if auxiliary resources are present
  243. BitRateBox (); // optional
  244. }
  245. class TextSubtitleSampleEntry() extends SubtitleSampleEntry('sbtt') {
  246. string content_encoding; // optional
  247. string mime_format;
  248. BitRateBox (); // optional
  249. TextConfigBox (); // optional
  250. }
  251. class TextSampleEntry() extends SampleEntry('tx3g') {
  252. unsigned int(32) displayFlags;
  253. signed int(8) horizontal-justification;
  254. signed int(8) vertical-justification;
  255. unsigned int(8) background-color-rgba[4];
  256. BoxRecord default-text-box;
  257. StyleRecord default-style;
  258. FontTableBox font-table;
  259. DisparityBox default-disparity;
  260. }
  261. */
  262. static int mov_read_subtitle_sample_entry(struct mov_t* mov, struct mov_sample_entry_t* entry)
  263. {
  264. struct mov_box_t box;
  265. mov_read_sample_entry(mov, &box, &entry->data_reference_index);
  266. box.size -= 16;
  267. if (box.type == MOV_TAG('t', 'x', '3', 'g'))
  268. {
  269. mov_read_tx3g(mov, &box);
  270. }
  271. else
  272. {
  273. mov_buffer_skip(&mov->io, box.size - 16);
  274. }
  275. entry->object_type_indication = MOV_OBJECT_TEXT;
  276. entry->stream_type = MP4_STREAM_VISUAL;
  277. mov->track->tag = box.type;
  278. return mov_buffer_error(&mov->io);
  279. }
  280. int mov_read_stsd(struct mov_t* mov, const struct mov_box_t* box)
  281. {
  282. uint32_t i, entry_count;
  283. struct mov_track_t* track = mov->track;
  284. mov_buffer_r8(&mov->io);
  285. mov_buffer_r24(&mov->io);
  286. entry_count = mov_buffer_r32(&mov->io);
  287. if (track->stsd.entry_count < entry_count)
  288. {
  289. void* p = realloc(track->stsd.entries, sizeof(track->stsd.entries[0]) * entry_count);
  290. if (NULL == p) return -ENOMEM;
  291. track->stsd.entries = (struct mov_sample_entry_t*)p;
  292. }
  293. track->stsd.entry_count = entry_count;
  294. for (i = 0; i < entry_count; i++)
  295. {
  296. track->stsd.current = &track->stsd.entries[i];
  297. memset(track->stsd.current, 0, sizeof(*track->stsd.current));
  298. if (MOV_AUDIO == track->handler_type)
  299. {
  300. mov_read_audio(mov, &track->stsd.entries[i]);
  301. }
  302. else if (MOV_VIDEO == track->handler_type)
  303. {
  304. mov_read_video(mov, &track->stsd.entries[i]);
  305. }
  306. else if (MOV_HINT == track->handler_type)
  307. {
  308. mov_read_hint_sample_entry(mov, &track->stsd.entries[i]);
  309. }
  310. else if (MOV_META == track->handler_type)
  311. {
  312. mov_read_meta_sample_entry(mov, &track->stsd.entries[i]);
  313. }
  314. else if (MOV_CLCP == track->handler_type)
  315. {
  316. mov_read_meta_sample_entry(mov, &track->stsd.entries[i]);
  317. }
  318. else if (MOV_TEXT == track->handler_type)
  319. {
  320. mov_read_text_sample_entry(mov, &track->stsd.entries[i]);
  321. }
  322. else if (MOV_SUBT == track->handler_type || MOV_SBTL == track->handler_type)
  323. {
  324. mov_read_subtitle_sample_entry(mov, &track->stsd.entries[i]);
  325. }
  326. else if (MOV_ALIS == track->handler_type)
  327. {
  328. mov_read_meta_sample_entry(mov, &track->stsd.entries[i]);
  329. }
  330. else
  331. {
  332. assert(0); // ignore
  333. mov_read_meta_sample_entry(mov, &track->stsd.entries[i]);
  334. }
  335. }
  336. (void)box;
  337. return mov_buffer_error(&mov->io);
  338. }
  339. //static int mov_write_h264(const struct mov_t* mov)
  340. //{
  341. // size_t size;
  342. // uint64_t offset;
  343. // const struct mov_track_t* track = mov->track;
  344. //
  345. // size = 8 /* Box */;
  346. //
  347. // offset = mov_buffer_tell(&mov->io);
  348. // mov_buffer_w32(&mov->io, 0); /* size */
  349. // mov_buffer_w32(&mov->io, MOV_TAG('a', 'v', 'c', 'C'));
  350. //
  351. // mov_write_size(mov, offset, size); /* update size */
  352. // return size;
  353. //}
  354. static size_t mov_write_video(const struct mov_t* mov, const struct mov_sample_entry_t* entry)
  355. {
  356. size_t size;
  357. uint64_t offset;
  358. char compressorname[32];
  359. memset(compressorname, 0, sizeof(compressorname));
  360. assert(1 == entry->data_reference_index);
  361. size = 8 /* Box */ + 8 /* SampleEntry */ + 70 /* VisualSampleEntry */;
  362. offset = mov_buffer_tell(&mov->io);
  363. mov_buffer_w32(&mov->io, 0); /* size */
  364. mov_buffer_w32(&mov->io, mov->track->tag); // "h264"
  365. mov_buffer_w32(&mov->io, 0); /* Reserved */
  366. mov_buffer_w16(&mov->io, 0); /* Reserved */
  367. mov_buffer_w16(&mov->io, entry->data_reference_index); /* Data-reference index */
  368. mov_buffer_w16(&mov->io, 0); /* Reserved / Codec stream version */
  369. mov_buffer_w16(&mov->io, 0); /* Reserved / Codec stream revision (=0) */
  370. mov_buffer_w32(&mov->io, 0); /* Reserved */
  371. mov_buffer_w32(&mov->io, 0); /* Reserved */
  372. mov_buffer_w32(&mov->io, 0); /* Reserved */
  373. mov_buffer_w16(&mov->io, entry->u.visual.width); /* Video width */
  374. mov_buffer_w16(&mov->io, entry->u.visual.height); /* Video height */
  375. mov_buffer_w32(&mov->io, 0x00480000); /* Horizontal resolution 72dpi */
  376. mov_buffer_w32(&mov->io, 0x00480000); /* Vertical resolution 72dpi */
  377. mov_buffer_w32(&mov->io, 0); /* reserved / Data size (= 0) */
  378. mov_buffer_w16(&mov->io, 1); /* Frame count (= 1) */
  379. // ISO 14496-15:2017 AVCC \012AVC Coding
  380. // ISO 14496-15:2017 HVCC \013HEVC Coding
  381. //mov_buffer_w8(&mov->io, 0 /*strlen(compressor_name)*/); /* compressorname */
  382. mov_buffer_write(&mov->io, compressorname, 32); // fill empty
  383. // ISO/IEC 14496-15:2017 4.5 Template field used (19)
  384. // 0x18 - the video sequence is in color with no alpha
  385. // 0x28 - the video sequence is in grayscale with no alpha
  386. // 0x20 - the video sequence has alpha (gray or color)
  387. mov_buffer_w16(&mov->io, 0x18); /* Reserved */
  388. mov_buffer_w16(&mov->io, 0xffff); /* Reserved */
  389. if(MOV_OBJECT_H264 == entry->object_type_indication)
  390. size += mov_write_avcc(mov);
  391. else if(MOV_OBJECT_MP4V == entry->object_type_indication)
  392. size += mov_write_esds(mov);
  393. else if (MOV_OBJECT_HEVC == entry->object_type_indication)
  394. size += mov_write_hvcc(mov);
  395. else if (MOV_OBJECT_AV1 == entry->object_type_indication)
  396. size += mov_write_av1c(mov);
  397. else if (MOV_OBJECT_VP8 == entry->object_type_indication || MOV_OBJECT_VP9 == entry->object_type_indication)
  398. size += mov_write_vpcc(mov);
  399. mov_write_size(mov, offset, size); /* update size */
  400. return size;
  401. }
  402. static size_t mov_write_audio(const struct mov_t* mov, const struct mov_sample_entry_t* entry)
  403. {
  404. size_t size;
  405. uint64_t offset;
  406. size = 8 /* Box */ + 8 /* SampleEntry */ + 20 /* AudioSampleEntry */;
  407. offset = mov_buffer_tell(&mov->io);
  408. mov_buffer_w32(&mov->io, 0); /* size */
  409. mov_buffer_w32(&mov->io, mov->track->tag); // "mp4a"
  410. mov_buffer_w32(&mov->io, 0); /* Reserved */
  411. mov_buffer_w16(&mov->io, 0); /* Reserved */
  412. mov_buffer_w16(&mov->io, 1); /* Data-reference index */
  413. /* SoundDescription */
  414. mov_buffer_w16(&mov->io, 0); /* Version */
  415. mov_buffer_w16(&mov->io, 0); /* Revision level */
  416. mov_buffer_w32(&mov->io, 0); /* Reserved */
  417. mov_buffer_w16(&mov->io, entry->u.audio.channelcount); /* channelcount */
  418. mov_buffer_w16(&mov->io, entry->u.audio.samplesize); /* samplesize */
  419. mov_buffer_w16(&mov->io, 0); /* pre_defined */
  420. mov_buffer_w16(&mov->io, 0); /* reserved / packet size (= 0) */
  421. // https://www.opus-codec.org/docs/opus_in_isobmff.html
  422. // 4.3 Definitions of Opus sample
  423. // OpusSampleEntry:
  424. // 1. The samplesize field shall be set to 16.
  425. // 2. The samplerate field shall be set to 48000<<16.
  426. mov_buffer_w32(&mov->io, entry->u.audio.samplerate); /* samplerate */
  427. if(MOV_OBJECT_AAC == entry->object_type_indication || MOV_OBJECT_MP3 == entry->object_type_indication || MOV_OBJECT_MP1A == entry->object_type_indication)
  428. size += mov_write_esds(mov);
  429. else if(MOV_OBJECT_OPUS == entry->object_type_indication)
  430. size += mov_write_dops(mov);
  431. mov_write_size(mov, offset, size); /* update size */
  432. return size;
  433. }
  434. static int mov_write_subtitle(const struct mov_t* mov, const struct mov_sample_entry_t* entry)
  435. {
  436. int size;
  437. uint64_t offset;
  438. size = 8 /* Box */ + 8 /* SampleEntry */ + entry->extra_data_size;
  439. offset = mov_buffer_tell(&mov->io);
  440. mov_buffer_w32(&mov->io, 0); /* size */
  441. mov_buffer_w32(&mov->io, mov->track->tag); // "tx3g"
  442. mov_buffer_w32(&mov->io, 0); /* Reserved */
  443. mov_buffer_w16(&mov->io, 0); /* Reserved */
  444. mov_buffer_w16(&mov->io, entry->data_reference_index); /* Data-reference index */
  445. if (MOV_TAG('t', 'x', '3', 'g') == mov->track->tag)
  446. {
  447. size += mov_write_tx3g(mov);
  448. }
  449. else if (entry->extra_data_size > 0) // unknown type
  450. {
  451. mov_buffer_write(&mov->io, entry->extra_data, entry->extra_data_size);
  452. size += entry->extra_data_size;
  453. }
  454. mov_write_size(mov, offset, size); /* update size */
  455. return size;
  456. }
  457. size_t mov_write_stsd(const struct mov_t* mov)
  458. {
  459. uint32_t i;
  460. size_t size;
  461. uint64_t offset;
  462. const struct mov_track_t* track = mov->track;
  463. size = 12 /* full box */ + 4 /* entry count */;
  464. offset = mov_buffer_tell(&mov->io);
  465. mov_buffer_w32(&mov->io, 0); /* size */
  466. mov_buffer_write(&mov->io, "stsd", 4);
  467. mov_buffer_w32(&mov->io, 0); /* version & flags */
  468. mov_buffer_w32(&mov->io, track->stsd.entry_count); /* entry count */
  469. for (i = 0; i < track->stsd.entry_count; i++)
  470. {
  471. ((struct mov_track_t*)track)->stsd.current = &track->stsd.entries[i];
  472. if (MOV_VIDEO == track->handler_type)
  473. {
  474. size += mov_write_video(mov, &track->stsd.entries[i]);
  475. }
  476. else if (MOV_AUDIO == track->handler_type)
  477. {
  478. size += mov_write_audio(mov, &track->stsd.entries[i]);
  479. }
  480. else if (MOV_SUBT == track->handler_type || MOV_TEXT == track->handler_type || MOV_SBTL == track->handler_type)
  481. {
  482. size += mov_write_subtitle(mov, &track->stsd.entries[i]);
  483. }
  484. else
  485. {
  486. assert(0);
  487. }
  488. }
  489. mov_write_size(mov, offset, size); /* update size */
  490. return size;
  491. }