nginxtra 1.0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (363) hide show
  1. data/VERSION +1 -0
  2. data/bin/nginxtra +5 -0
  3. data/lib/nginxtra.rb +12 -0
  4. data/lib/nginxtra/action.rb +36 -0
  5. data/lib/nginxtra/actions/compile.rb +60 -0
  6. data/lib/nginxtra/actions/install.rb +99 -0
  7. data/lib/nginxtra/actions/reload.rb +14 -0
  8. data/lib/nginxtra/actions/restart.rb +15 -0
  9. data/lib/nginxtra/actions/start.rb +53 -0
  10. data/lib/nginxtra/actions/status.rb +31 -0
  11. data/lib/nginxtra/actions/stop.rb +14 -0
  12. data/lib/nginxtra/cli.rb +77 -0
  13. data/lib/nginxtra/config.rb +339 -0
  14. data/lib/nginxtra/error.rb +13 -0
  15. data/lib/nginxtra/status.rb +57 -0
  16. data/src/nginx/CHANGES +5630 -0
  17. data/src/nginx/CHANGES.ru +5716 -0
  18. data/src/nginx/LICENSE +25 -0
  19. data/src/nginx/README +3 -0
  20. data/src/nginx/auto/cc/acc +15 -0
  21. data/src/nginx/auto/cc/bcc +72 -0
  22. data/src/nginx/auto/cc/ccc +46 -0
  23. data/src/nginx/auto/cc/conf +189 -0
  24. data/src/nginx/auto/cc/gcc +183 -0
  25. data/src/nginx/auto/cc/icc +121 -0
  26. data/src/nginx/auto/cc/msvc +138 -0
  27. data/src/nginx/auto/cc/name +101 -0
  28. data/src/nginx/auto/cc/owc +104 -0
  29. data/src/nginx/auto/cc/sunc +158 -0
  30. data/src/nginx/auto/define +12 -0
  31. data/src/nginx/auto/endianess +45 -0
  32. data/src/nginx/auto/feature +123 -0
  33. data/src/nginx/auto/have +12 -0
  34. data/src/nginx/auto/have_headers +12 -0
  35. data/src/nginx/auto/headers +13 -0
  36. data/src/nginx/auto/include +61 -0
  37. data/src/nginx/auto/init +51 -0
  38. data/src/nginx/auto/install +184 -0
  39. data/src/nginx/auto/lib/conf +83 -0
  40. data/src/nginx/auto/lib/geoip/conf +79 -0
  41. data/src/nginx/auto/lib/google-perftools/conf +45 -0
  42. data/src/nginx/auto/lib/libatomic/conf +43 -0
  43. data/src/nginx/auto/lib/libatomic/make +14 -0
  44. data/src/nginx/auto/lib/libgd/conf +83 -0
  45. data/src/nginx/auto/lib/libxslt/conf +156 -0
  46. data/src/nginx/auto/lib/make +32 -0
  47. data/src/nginx/auto/lib/md5/conf +103 -0
  48. data/src/nginx/auto/lib/md5/make +96 -0
  49. data/src/nginx/auto/lib/md5/makefile.bcc +22 -0
  50. data/src/nginx/auto/lib/md5/makefile.msvc +22 -0
  51. data/src/nginx/auto/lib/md5/makefile.owc +11 -0
  52. data/src/nginx/auto/lib/openssl/conf +74 -0
  53. data/src/nginx/auto/lib/openssl/make +67 -0
  54. data/src/nginx/auto/lib/openssl/makefile.bcc +18 -0
  55. data/src/nginx/auto/lib/openssl/makefile.msvc +14 -0
  56. data/src/nginx/auto/lib/pcre/conf +180 -0
  57. data/src/nginx/auto/lib/pcre/make +64 -0
  58. data/src/nginx/auto/lib/pcre/makefile.bcc +26 -0
  59. data/src/nginx/auto/lib/pcre/makefile.msvc +22 -0
  60. data/src/nginx/auto/lib/pcre/makefile.owc +24 -0
  61. data/src/nginx/auto/lib/perl/conf +60 -0
  62. data/src/nginx/auto/lib/perl/make +36 -0
  63. data/src/nginx/auto/lib/sha1/conf +79 -0
  64. data/src/nginx/auto/lib/sha1/make +96 -0
  65. data/src/nginx/auto/lib/sha1/makefile.bcc +22 -0
  66. data/src/nginx/auto/lib/sha1/makefile.msvc +22 -0
  67. data/src/nginx/auto/lib/sha1/makefile.owc +11 -0
  68. data/src/nginx/auto/lib/test +40 -0
  69. data/src/nginx/auto/lib/zlib/conf +76 -0
  70. data/src/nginx/auto/lib/zlib/make +114 -0
  71. data/src/nginx/auto/lib/zlib/makefile.bcc +15 -0
  72. data/src/nginx/auto/lib/zlib/makefile.msvc +14 -0
  73. data/src/nginx/auto/lib/zlib/makefile.owc +14 -0
  74. data/src/nginx/auto/lib/zlib/patch.zlib.h +10 -0
  75. data/src/nginx/auto/make +417 -0
  76. data/src/nginx/auto/modules +479 -0
  77. data/src/nginx/auto/nohave +12 -0
  78. data/src/nginx/auto/options +490 -0
  79. data/src/nginx/auto/os/conf +105 -0
  80. data/src/nginx/auto/os/darwin +116 -0
  81. data/src/nginx/auto/os/freebsd +136 -0
  82. data/src/nginx/auto/os/linux +152 -0
  83. data/src/nginx/auto/os/solaris +60 -0
  84. data/src/nginx/auto/os/win32 +29 -0
  85. data/src/nginx/auto/sources +518 -0
  86. data/src/nginx/auto/stubs +8 -0
  87. data/src/nginx/auto/summary +114 -0
  88. data/src/nginx/auto/types/sizeof +83 -0
  89. data/src/nginx/auto/types/typedef +77 -0
  90. data/src/nginx/auto/types/uintptr_t +42 -0
  91. data/src/nginx/auto/types/value +12 -0
  92. data/src/nginx/auto/unix +719 -0
  93. data/src/nginx/conf/fastcgi.conf +24 -0
  94. data/src/nginx/conf/fastcgi_params +23 -0
  95. data/src/nginx/conf/koi-utf +109 -0
  96. data/src/nginx/conf/koi-win +103 -0
  97. data/src/nginx/conf/mime.types +80 -0
  98. data/src/nginx/conf/nginx.conf +118 -0
  99. data/src/nginx/conf/scgi_params +15 -0
  100. data/src/nginx/conf/uwsgi_params +15 -0
  101. data/src/nginx/conf/win-utf +126 -0
  102. data/src/nginx/configure +108 -0
  103. data/src/nginx/contrib/README +15 -0
  104. data/src/nginx/contrib/geo2nginx.pl +58 -0
  105. data/src/nginx/contrib/unicode2nginx/koi-utf +131 -0
  106. data/src/nginx/contrib/unicode2nginx/unicode-to-nginx.pl +45 -0
  107. data/src/nginx/contrib/unicode2nginx/win-utf +130 -0
  108. data/src/nginx/html/50x.html +18 -0
  109. data/src/nginx/html/index.html +8 -0
  110. data/src/nginx/man/nginx.8 +202 -0
  111. data/src/nginx/src/core/nginx.c +1333 -0
  112. data/src/nginx/src/core/nginx.h +20 -0
  113. data/src/nginx/src/core/ngx_array.c +147 -0
  114. data/src/nginx/src/core/ngx_array.h +53 -0
  115. data/src/nginx/src/core/ngx_buf.c +218 -0
  116. data/src/nginx/src/core/ngx_buf.h +162 -0
  117. data/src/nginx/src/core/ngx_conf_file.c +1506 -0
  118. data/src/nginx/src/core/ngx_conf_file.h +348 -0
  119. data/src/nginx/src/core/ngx_config.h +134 -0
  120. data/src/nginx/src/core/ngx_connection.c +1074 -0
  121. data/src/nginx/src/core/ngx_connection.h +195 -0
  122. data/src/nginx/src/core/ngx_core.h +95 -0
  123. data/src/nginx/src/core/ngx_cpuinfo.c +139 -0
  124. data/src/nginx/src/core/ngx_crc.h +39 -0
  125. data/src/nginx/src/core/ngx_crc32.c +129 -0
  126. data/src/nginx/src/core/ngx_crc32.h +79 -0
  127. data/src/nginx/src/core/ngx_crypt.c +238 -0
  128. data/src/nginx/src/core/ngx_crypt.h +20 -0
  129. data/src/nginx/src/core/ngx_cycle.c +1379 -0
  130. data/src/nginx/src/core/ngx_cycle.h +142 -0
  131. data/src/nginx/src/core/ngx_file.c +993 -0
  132. data/src/nginx/src/core/ngx_file.h +151 -0
  133. data/src/nginx/src/core/ngx_hash.c +976 -0
  134. data/src/nginx/src/core/ngx_hash.h +122 -0
  135. data/src/nginx/src/core/ngx_inet.c +1008 -0
  136. data/src/nginx/src/core/ngx_inet.h +120 -0
  137. data/src/nginx/src/core/ngx_list.c +71 -0
  138. data/src/nginx/src/core/ngx_list.h +83 -0
  139. data/src/nginx/src/core/ngx_log.c +459 -0
  140. data/src/nginx/src/core/ngx_log.h +250 -0
  141. data/src/nginx/src/core/ngx_md5.c +289 -0
  142. data/src/nginx/src/core/ngx_md5.h +60 -0
  143. data/src/nginx/src/core/ngx_murmurhash.c +50 -0
  144. data/src/nginx/src/core/ngx_murmurhash.h +19 -0
  145. data/src/nginx/src/core/ngx_open_file_cache.c +882 -0
  146. data/src/nginx/src/core/ngx_open_file_cache.h +119 -0
  147. data/src/nginx/src/core/ngx_output_chain.c +673 -0
  148. data/src/nginx/src/core/ngx_palloc.c +433 -0
  149. data/src/nginx/src/core/ngx_palloc.h +95 -0
  150. data/src/nginx/src/core/ngx_parse.c +249 -0
  151. data/src/nginx/src/core/ngx_parse.h +24 -0
  152. data/src/nginx/src/core/ngx_queue.c +80 -0
  153. data/src/nginx/src/core/ngx_queue.h +112 -0
  154. data/src/nginx/src/core/ngx_radix_tree.c +291 -0
  155. data/src/nginx/src/core/ngx_radix_tree.h +46 -0
  156. data/src/nginx/src/core/ngx_rbtree.c +383 -0
  157. data/src/nginx/src/core/ngx_rbtree.h +84 -0
  158. data/src/nginx/src/core/ngx_regex.c +206 -0
  159. data/src/nginx/src/core/ngx_regex.h +56 -0
  160. data/src/nginx/src/core/ngx_resolver.c +2201 -0
  161. data/src/nginx/src/core/ngx_resolver.h +149 -0
  162. data/src/nginx/src/core/ngx_sha1.h +31 -0
  163. data/src/nginx/src/core/ngx_shmtx.c +284 -0
  164. data/src/nginx/src/core/ngx_shmtx.h +38 -0
  165. data/src/nginx/src/core/ngx_slab.c +701 -0
  166. data/src/nginx/src/core/ngx_slab.h +54 -0
  167. data/src/nginx/src/core/ngx_spinlock.c +53 -0
  168. data/src/nginx/src/core/ngx_string.c +1837 -0
  169. data/src/nginx/src/core/ngx_string.h +231 -0
  170. data/src/nginx/src/core/ngx_times.c +407 -0
  171. data/src/nginx/src/core/ngx_times.h +51 -0
  172. data/src/nginx/src/event/modules/ngx_aio_module.c +171 -0
  173. data/src/nginx/src/event/modules/ngx_devpoll_module.c +569 -0
  174. data/src/nginx/src/event/modules/ngx_epoll_module.c +833 -0
  175. data/src/nginx/src/event/modules/ngx_eventport_module.c +602 -0
  176. data/src/nginx/src/event/modules/ngx_kqueue_module.c +785 -0
  177. data/src/nginx/src/event/modules/ngx_poll_module.c +443 -0
  178. data/src/nginx/src/event/modules/ngx_rtsig_module.c +735 -0
  179. data/src/nginx/src/event/modules/ngx_select_module.c +435 -0
  180. data/src/nginx/src/event/modules/ngx_win32_select_module.c +400 -0
  181. data/src/nginx/src/event/ngx_event.c +1275 -0
  182. data/src/nginx/src/event/ngx_event.h +573 -0
  183. data/src/nginx/src/event/ngx_event_accept.c +428 -0
  184. data/src/nginx/src/event/ngx_event_busy_lock.c +286 -0
  185. data/src/nginx/src/event/ngx_event_busy_lock.h +65 -0
  186. data/src/nginx/src/event/ngx_event_connect.c +258 -0
  187. data/src/nginx/src/event/ngx_event_connect.h +76 -0
  188. data/src/nginx/src/event/ngx_event_mutex.c +70 -0
  189. data/src/nginx/src/event/ngx_event_openssl.c +2382 -0
  190. data/src/nginx/src/event/ngx_event_openssl.h +162 -0
  191. data/src/nginx/src/event/ngx_event_pipe.c +996 -0
  192. data/src/nginx/src/event/ngx_event_pipe.h +95 -0
  193. data/src/nginx/src/event/ngx_event_posted.c +173 -0
  194. data/src/nginx/src/event/ngx_event_posted.h +75 -0
  195. data/src/nginx/src/event/ngx_event_timer.c +159 -0
  196. data/src/nginx/src/event/ngx_event_timer.h +102 -0
  197. data/src/nginx/src/http/modules/ngx_http_access_module.c +384 -0
  198. data/src/nginx/src/http/modules/ngx_http_addition_filter_module.c +250 -0
  199. data/src/nginx/src/http/modules/ngx_http_auth_basic_module.c +478 -0
  200. data/src/nginx/src/http/modules/ngx_http_autoindex_module.c +701 -0
  201. data/src/nginx/src/http/modules/ngx_http_browser_module.c +713 -0
  202. data/src/nginx/src/http/modules/ngx_http_charset_filter_module.c +1681 -0
  203. data/src/nginx/src/http/modules/ngx_http_chunked_filter_module.c +242 -0
  204. data/src/nginx/src/http/modules/ngx_http_dav_module.c +1141 -0
  205. data/src/nginx/src/http/modules/ngx_http_degradation_module.c +243 -0
  206. data/src/nginx/src/http/modules/ngx_http_empty_gif_module.c +140 -0
  207. data/src/nginx/src/http/modules/ngx_http_fastcgi_module.c +2916 -0
  208. data/src/nginx/src/http/modules/ngx_http_flv_module.c +254 -0
  209. data/src/nginx/src/http/modules/ngx_http_geo_module.c +1441 -0
  210. data/src/nginx/src/http/modules/ngx_http_geoip_module.c +671 -0
  211. data/src/nginx/src/http/modules/ngx_http_gzip_filter_module.c +1206 -0
  212. data/src/nginx/src/http/modules/ngx_http_gzip_static_module.c +299 -0
  213. data/src/nginx/src/http/modules/ngx_http_headers_filter_module.c +616 -0
  214. data/src/nginx/src/http/modules/ngx_http_image_filter_module.c +1489 -0
  215. data/src/nginx/src/http/modules/ngx_http_index_module.c +516 -0
  216. data/src/nginx/src/http/modules/ngx_http_limit_req_module.c +809 -0
  217. data/src/nginx/src/http/modules/ngx_http_limit_zone_module.c +553 -0
  218. data/src/nginx/src/http/modules/ngx_http_log_module.c +1357 -0
  219. data/src/nginx/src/http/modules/ngx_http_map_module.c +575 -0
  220. data/src/nginx/src/http/modules/ngx_http_memcached_module.c +624 -0
  221. data/src/nginx/src/http/modules/ngx_http_mp4_module.c +3000 -0
  222. data/src/nginx/src/http/modules/ngx_http_not_modified_filter_module.c +143 -0
  223. data/src/nginx/src/http/modules/ngx_http_proxy_module.c +2831 -0
  224. data/src/nginx/src/http/modules/ngx_http_random_index_module.c +317 -0
  225. data/src/nginx/src/http/modules/ngx_http_range_filter_module.c +855 -0
  226. data/src/nginx/src/http/modules/ngx_http_realip_module.c +476 -0
  227. data/src/nginx/src/http/modules/ngx_http_referer_module.c +613 -0
  228. data/src/nginx/src/http/modules/ngx_http_rewrite_module.c +1019 -0
  229. data/src/nginx/src/http/modules/ngx_http_scgi_module.c +1714 -0
  230. data/src/nginx/src/http/modules/ngx_http_secure_link_module.c +355 -0
  231. data/src/nginx/src/http/modules/ngx_http_split_clients_module.c +242 -0
  232. data/src/nginx/src/http/modules/ngx_http_ssi_filter_module.c +2913 -0
  233. data/src/nginx/src/http/modules/ngx_http_ssi_filter_module.h +114 -0
  234. data/src/nginx/src/http/modules/ngx_http_ssl_module.c +652 -0
  235. data/src/nginx/src/http/modules/ngx_http_ssl_module.h +52 -0
  236. data/src/nginx/src/http/modules/ngx_http_static_module.c +278 -0
  237. data/src/nginx/src/http/modules/ngx_http_stub_status_module.c +144 -0
  238. data/src/nginx/src/http/modules/ngx_http_sub_filter_module.c +716 -0
  239. data/src/nginx/src/http/modules/ngx_http_upstream_ip_hash_module.c +237 -0
  240. data/src/nginx/src/http/modules/ngx_http_userid_filter_module.c +846 -0
  241. data/src/nginx/src/http/modules/ngx_http_uwsgi_module.c +1774 -0
  242. data/src/nginx/src/http/modules/ngx_http_xslt_filter_module.c +984 -0
  243. data/src/nginx/src/http/modules/perl/Makefile.PL +42 -0
  244. data/src/nginx/src/http/modules/perl/nginx.pm +137 -0
  245. data/src/nginx/src/http/modules/perl/nginx.xs +986 -0
  246. data/src/nginx/src/http/modules/perl/ngx_http_perl_module.c +1076 -0
  247. data/src/nginx/src/http/modules/perl/ngx_http_perl_module.h +67 -0
  248. data/src/nginx/src/http/modules/perl/typemap +3 -0
  249. data/src/nginx/src/http/ngx_http.c +2073 -0
  250. data/src/nginx/src/http/ngx_http.h +160 -0
  251. data/src/nginx/src/http/ngx_http_busy_lock.c +307 -0
  252. data/src/nginx/src/http/ngx_http_busy_lock.h +54 -0
  253. data/src/nginx/src/http/ngx_http_cache.h +148 -0
  254. data/src/nginx/src/http/ngx_http_config.h +75 -0
  255. data/src/nginx/src/http/ngx_http_copy_filter_module.c +300 -0
  256. data/src/nginx/src/http/ngx_http_core_module.c +4736 -0
  257. data/src/nginx/src/http/ngx_http_core_module.h +541 -0
  258. data/src/nginx/src/http/ngx_http_file_cache.c +1715 -0
  259. data/src/nginx/src/http/ngx_http_header_filter_module.c +623 -0
  260. data/src/nginx/src/http/ngx_http_parse.c +1734 -0
  261. data/src/nginx/src/http/ngx_http_parse_time.c +276 -0
  262. data/src/nginx/src/http/ngx_http_postpone_filter_module.c +178 -0
  263. data/src/nginx/src/http/ngx_http_request.c +3181 -0
  264. data/src/nginx/src/http/ngx_http_request.h +573 -0
  265. data/src/nginx/src/http/ngx_http_request_body.c +644 -0
  266. data/src/nginx/src/http/ngx_http_script.c +1752 -0
  267. data/src/nginx/src/http/ngx_http_script.h +257 -0
  268. data/src/nginx/src/http/ngx_http_special_response.c +789 -0
  269. data/src/nginx/src/http/ngx_http_upstream.c +4555 -0
  270. data/src/nginx/src/http/ngx_http_upstream.h +350 -0
  271. data/src/nginx/src/http/ngx_http_upstream_round_robin.c +791 -0
  272. data/src/nginx/src/http/ngx_http_upstream_round_robin.h +85 -0
  273. data/src/nginx/src/http/ngx_http_variables.c +2053 -0
  274. data/src/nginx/src/http/ngx_http_variables.h +115 -0
  275. data/src/nginx/src/http/ngx_http_write_filter_module.c +315 -0
  276. data/src/nginx/src/mail/ngx_mail.c +542 -0
  277. data/src/nginx/src/mail/ngx_mail.h +407 -0
  278. data/src/nginx/src/mail/ngx_mail_auth_http_module.c +1452 -0
  279. data/src/nginx/src/mail/ngx_mail_core_module.c +553 -0
  280. data/src/nginx/src/mail/ngx_mail_handler.c +773 -0
  281. data/src/nginx/src/mail/ngx_mail_imap_handler.c +457 -0
  282. data/src/nginx/src/mail/ngx_mail_imap_module.c +253 -0
  283. data/src/nginx/src/mail/ngx_mail_imap_module.h +39 -0
  284. data/src/nginx/src/mail/ngx_mail_parse.c +885 -0
  285. data/src/nginx/src/mail/ngx_mail_pop3_handler.c +500 -0
  286. data/src/nginx/src/mail/ngx_mail_pop3_module.c +264 -0
  287. data/src/nginx/src/mail/ngx_mail_pop3_module.h +38 -0
  288. data/src/nginx/src/mail/ngx_mail_proxy_module.c +1089 -0
  289. data/src/nginx/src/mail/ngx_mail_smtp_handler.c +872 -0
  290. data/src/nginx/src/mail/ngx_mail_smtp_module.c +308 -0
  291. data/src/nginx/src/mail/ngx_mail_smtp_module.h +45 -0
  292. data/src/nginx/src/mail/ngx_mail_ssl_module.c +491 -0
  293. data/src/nginx/src/mail/ngx_mail_ssl_module.h +52 -0
  294. data/src/nginx/src/misc/ngx_cpp_test_module.cpp +27 -0
  295. data/src/nginx/src/misc/ngx_google_perftools_module.c +126 -0
  296. data/src/nginx/src/os/unix/ngx_aio_read.c +109 -0
  297. data/src/nginx/src/os/unix/ngx_aio_read_chain.c +78 -0
  298. data/src/nginx/src/os/unix/ngx_aio_write.c +109 -0
  299. data/src/nginx/src/os/unix/ngx_aio_write_chain.c +100 -0
  300. data/src/nginx/src/os/unix/ngx_alloc.c +90 -0
  301. data/src/nginx/src/os/unix/ngx_alloc.h +45 -0
  302. data/src/nginx/src/os/unix/ngx_atomic.h +311 -0
  303. data/src/nginx/src/os/unix/ngx_channel.c +258 -0
  304. data/src/nginx/src/os/unix/ngx_channel.h +34 -0
  305. data/src/nginx/src/os/unix/ngx_daemon.c +69 -0
  306. data/src/nginx/src/os/unix/ngx_darwin.h +20 -0
  307. data/src/nginx/src/os/unix/ngx_darwin_config.h +96 -0
  308. data/src/nginx/src/os/unix/ngx_darwin_init.c +166 -0
  309. data/src/nginx/src/os/unix/ngx_darwin_sendfile_chain.c +366 -0
  310. data/src/nginx/src/os/unix/ngx_errno.c +87 -0
  311. data/src/nginx/src/os/unix/ngx_errno.h +68 -0
  312. data/src/nginx/src/os/unix/ngx_file_aio_read.c +208 -0
  313. data/src/nginx/src/os/unix/ngx_files.c +566 -0
  314. data/src/nginx/src/os/unix/ngx_files.h +343 -0
  315. data/src/nginx/src/os/unix/ngx_freebsd.h +24 -0
  316. data/src/nginx/src/os/unix/ngx_freebsd_config.h +119 -0
  317. data/src/nginx/src/os/unix/ngx_freebsd_init.c +259 -0
  318. data/src/nginx/src/os/unix/ngx_freebsd_rfork_thread.c +756 -0
  319. data/src/nginx/src/os/unix/ngx_freebsd_rfork_thread.h +122 -0
  320. data/src/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c +436 -0
  321. data/src/nginx/src/os/unix/ngx_gcc_atomic_amd64.h +82 -0
  322. data/src/nginx/src/os/unix/ngx_gcc_atomic_ppc.h +155 -0
  323. data/src/nginx/src/os/unix/ngx_gcc_atomic_sparc64.h +82 -0
  324. data/src/nginx/src/os/unix/ngx_gcc_atomic_x86.h +127 -0
  325. data/src/nginx/src/os/unix/ngx_linux.h +18 -0
  326. data/src/nginx/src/os/unix/ngx_linux_aio_read.c +137 -0
  327. data/src/nginx/src/os/unix/ngx_linux_config.h +117 -0
  328. data/src/nginx/src/os/unix/ngx_linux_init.c +91 -0
  329. data/src/nginx/src/os/unix/ngx_linux_sendfile_chain.c +378 -0
  330. data/src/nginx/src/os/unix/ngx_os.h +84 -0
  331. data/src/nginx/src/os/unix/ngx_posix_config.h +153 -0
  332. data/src/nginx/src/os/unix/ngx_posix_init.c +124 -0
  333. data/src/nginx/src/os/unix/ngx_process.c +590 -0
  334. data/src/nginx/src/os/unix/ngx_process.h +87 -0
  335. data/src/nginx/src/os/unix/ngx_process_cycle.c +1390 -0
  336. data/src/nginx/src/os/unix/ngx_process_cycle.h +61 -0
  337. data/src/nginx/src/os/unix/ngx_pthread_thread.c +278 -0
  338. data/src/nginx/src/os/unix/ngx_readv_chain.c +258 -0
  339. data/src/nginx/src/os/unix/ngx_recv.c +180 -0
  340. data/src/nginx/src/os/unix/ngx_send.c +73 -0
  341. data/src/nginx/src/os/unix/ngx_setproctitle.c +135 -0
  342. data/src/nginx/src/os/unix/ngx_setproctitle.h +52 -0
  343. data/src/nginx/src/os/unix/ngx_shmem.c +126 -0
  344. data/src/nginx/src/os/unix/ngx_shmem.h +29 -0
  345. data/src/nginx/src/os/unix/ngx_socket.c +116 -0
  346. data/src/nginx/src/os/unix/ngx_socket.h +64 -0
  347. data/src/nginx/src/os/unix/ngx_solaris.h +16 -0
  348. data/src/nginx/src/os/unix/ngx_solaris_config.h +107 -0
  349. data/src/nginx/src/os/unix/ngx_solaris_init.c +75 -0
  350. data/src/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c +251 -0
  351. data/src/nginx/src/os/unix/ngx_sunpro_amd64.il +43 -0
  352. data/src/nginx/src/os/unix/ngx_sunpro_atomic_sparc64.h +61 -0
  353. data/src/nginx/src/os/unix/ngx_sunpro_sparc64.il +36 -0
  354. data/src/nginx/src/os/unix/ngx_sunpro_x86.il +44 -0
  355. data/src/nginx/src/os/unix/ngx_thread.h +128 -0
  356. data/src/nginx/src/os/unix/ngx_time.c +104 -0
  357. data/src/nginx/src/os/unix/ngx_time.h +66 -0
  358. data/src/nginx/src/os/unix/ngx_udp_recv.c +115 -0
  359. data/src/nginx/src/os/unix/ngx_user.c +109 -0
  360. data/src/nginx/src/os/unix/ngx_user.h +24 -0
  361. data/src/nginx/src/os/unix/ngx_writev_chain.c +181 -0
  362. data/src/nginx/src/os/unix/rfork_thread.S +73 -0
  363. metadata +419 -0
@@ -0,0 +1,3000 @@
1
+
2
+ /*
3
+ * Copyright (C) Igor Sysoev
4
+ * Copyright (C) Nginx, Inc.
5
+ */
6
+
7
+ #include <ngx_config.h>
8
+ #include <ngx_core.h>
9
+ #include <ngx_http.h>
10
+
11
+
12
+ #define NGX_HTTP_MP4_TRAK_ATOM 0
13
+ #define NGX_HTTP_MP4_TKHD_ATOM 1
14
+ #define NGX_HTTP_MP4_MDIA_ATOM 2
15
+ #define NGX_HTTP_MP4_MDHD_ATOM 3
16
+ #define NGX_HTTP_MP4_HDLR_ATOM 4
17
+ #define NGX_HTTP_MP4_MINF_ATOM 5
18
+ #define NGX_HTTP_MP4_VMHD_ATOM 6
19
+ #define NGX_HTTP_MP4_SMHD_ATOM 7
20
+ #define NGX_HTTP_MP4_DINF_ATOM 8
21
+ #define NGX_HTTP_MP4_STBL_ATOM 9
22
+ #define NGX_HTTP_MP4_STSD_ATOM 10
23
+ #define NGX_HTTP_MP4_STTS_ATOM 11
24
+ #define NGX_HTTP_MP4_STTS_DATA 12
25
+ #define NGX_HTTP_MP4_STSS_ATOM 13
26
+ #define NGX_HTTP_MP4_STSS_DATA 14
27
+ #define NGX_HTTP_MP4_CTTS_ATOM 15
28
+ #define NGX_HTTP_MP4_CTTS_DATA 16
29
+ #define NGX_HTTP_MP4_STSC_ATOM 17
30
+ #define NGX_HTTP_MP4_STSC_CHUNK 18
31
+ #define NGX_HTTP_MP4_STSC_DATA 19
32
+ #define NGX_HTTP_MP4_STSZ_ATOM 20
33
+ #define NGX_HTTP_MP4_STSZ_DATA 21
34
+ #define NGX_HTTP_MP4_STCO_ATOM 22
35
+ #define NGX_HTTP_MP4_STCO_DATA 23
36
+ #define NGX_HTTP_MP4_CO64_ATOM 24
37
+ #define NGX_HTTP_MP4_CO64_DATA 25
38
+
39
+ #define NGX_HTTP_MP4_LAST_ATOM NGX_HTTP_MP4_CO64_DATA
40
+
41
+
42
+ typedef struct {
43
+ size_t buffer_size;
44
+ size_t max_buffer_size;
45
+ } ngx_http_mp4_conf_t;
46
+
47
+
48
+ typedef struct {
49
+ u_char chunk[4];
50
+ u_char samples[4];
51
+ u_char id[4];
52
+ } ngx_mp4_stsc_entry_t;
53
+
54
+
55
+ typedef struct {
56
+ uint32_t timescale;
57
+ uint32_t time_to_sample_entries;
58
+ uint32_t sample_to_chunk_entries;
59
+ uint32_t sync_samples_entries;
60
+ uint32_t composition_offset_entries;
61
+ uint32_t sample_sizes_entries;
62
+ uint32_t chunks;
63
+
64
+ ngx_uint_t start_sample;
65
+ ngx_uint_t start_chunk;
66
+ ngx_uint_t chunk_samples;
67
+ uint64_t chunk_samples_size;
68
+ off_t start_offset;
69
+
70
+ size_t tkhd_size;
71
+ size_t mdhd_size;
72
+ size_t hdlr_size;
73
+ size_t vmhd_size;
74
+ size_t smhd_size;
75
+ size_t dinf_size;
76
+ size_t size;
77
+
78
+ ngx_chain_t out[NGX_HTTP_MP4_LAST_ATOM + 1];
79
+
80
+ ngx_buf_t trak_atom_buf;
81
+ ngx_buf_t tkhd_atom_buf;
82
+ ngx_buf_t mdia_atom_buf;
83
+ ngx_buf_t mdhd_atom_buf;
84
+ ngx_buf_t hdlr_atom_buf;
85
+ ngx_buf_t minf_atom_buf;
86
+ ngx_buf_t vmhd_atom_buf;
87
+ ngx_buf_t smhd_atom_buf;
88
+ ngx_buf_t dinf_atom_buf;
89
+ ngx_buf_t stbl_atom_buf;
90
+ ngx_buf_t stsd_atom_buf;
91
+ ngx_buf_t stts_atom_buf;
92
+ ngx_buf_t stts_data_buf;
93
+ ngx_buf_t stss_atom_buf;
94
+ ngx_buf_t stss_data_buf;
95
+ ngx_buf_t ctts_atom_buf;
96
+ ngx_buf_t ctts_data_buf;
97
+ ngx_buf_t stsc_atom_buf;
98
+ ngx_buf_t stsc_chunk_buf;
99
+ ngx_buf_t stsc_data_buf;
100
+ ngx_buf_t stsz_atom_buf;
101
+ ngx_buf_t stsz_data_buf;
102
+ ngx_buf_t stco_atom_buf;
103
+ ngx_buf_t stco_data_buf;
104
+ ngx_buf_t co64_atom_buf;
105
+ ngx_buf_t co64_data_buf;
106
+
107
+ ngx_mp4_stsc_entry_t stsc_chunk_entry;
108
+ } ngx_http_mp4_trak_t;
109
+
110
+
111
+ typedef struct {
112
+ ngx_file_t file;
113
+
114
+ u_char *buffer;
115
+ u_char *buffer_start;
116
+ u_char *buffer_pos;
117
+ u_char *buffer_end;
118
+ size_t buffer_size;
119
+
120
+ off_t offset;
121
+ off_t end;
122
+ off_t content_length;
123
+ ngx_uint_t start;
124
+ uint32_t timescale;
125
+ ngx_http_request_t *request;
126
+ ngx_array_t trak;
127
+ ngx_http_mp4_trak_t traks[2];
128
+
129
+ size_t ftyp_size;
130
+ size_t moov_size;
131
+
132
+ ngx_chain_t *out;
133
+ ngx_chain_t ftyp_atom;
134
+ ngx_chain_t moov_atom;
135
+ ngx_chain_t mvhd_atom;
136
+ ngx_chain_t mdat_atom;
137
+ ngx_chain_t mdat_data;
138
+
139
+ ngx_buf_t ftyp_atom_buf;
140
+ ngx_buf_t moov_atom_buf;
141
+ ngx_buf_t mvhd_atom_buf;
142
+ ngx_buf_t mdat_atom_buf;
143
+ ngx_buf_t mdat_data_buf;
144
+
145
+ u_char moov_atom_header[8];
146
+ u_char mdat_atom_header[16];
147
+ } ngx_http_mp4_file_t;
148
+
149
+
150
+ typedef struct {
151
+ char *name;
152
+ ngx_int_t (*handler)(ngx_http_mp4_file_t *mp4,
153
+ uint64_t atom_data_size);
154
+ } ngx_http_mp4_atom_handler_t;
155
+
156
+
157
+ #define ngx_mp4_atom_header(mp4) (mp4->buffer_pos - 8)
158
+ #define ngx_mp4_atom_data(mp4) mp4->buffer_pos
159
+ #define ngx_mp4_atom_data_size(t) (uint64_t) (sizeof(t) - 8)
160
+ #define ngx_mp4_atom_next(mp4, n) mp4->buffer_pos += n; mp4->offset += n
161
+
162
+
163
+ #define ngx_mp4_set_atom_name(p, n1, n2, n3, n4) \
164
+ ((u_char *) (p))[4] = n1; \
165
+ ((u_char *) (p))[5] = n2; \
166
+ ((u_char *) (p))[6] = n3; \
167
+ ((u_char *) (p))[7] = n4
168
+
169
+ #define ngx_mp4_get_32value(p) \
170
+ ( ((uint32_t) ((u_char *) (p))[0] << 24) \
171
+ + ( ((u_char *) (p))[1] << 16) \
172
+ + ( ((u_char *) (p))[2] << 8) \
173
+ + ( ((u_char *) (p))[3]) )
174
+
175
+ #define ngx_mp4_set_32value(p, n) \
176
+ ((u_char *) (p))[0] = (u_char) ((n) >> 24); \
177
+ ((u_char *) (p))[1] = (u_char) ((n) >> 16); \
178
+ ((u_char *) (p))[2] = (u_char) ((n) >> 8); \
179
+ ((u_char *) (p))[3] = (u_char) (n)
180
+
181
+ #define ngx_mp4_get_64value(p) \
182
+ ( ((uint64_t) ((u_char *) (p))[0] << 56) \
183
+ + ((uint64_t) ((u_char *) (p))[1] << 48) \
184
+ + ((uint64_t) ((u_char *) (p))[2] << 40) \
185
+ + ((uint64_t) ((u_char *) (p))[3] << 32) \
186
+ + ((uint64_t) ((u_char *) (p))[4] << 24) \
187
+ + ( ((u_char *) (p))[5] << 16) \
188
+ + ( ((u_char *) (p))[6] << 8) \
189
+ + ( ((u_char *) (p))[7]) )
190
+
191
+ #define ngx_mp4_set_64value(p, n) \
192
+ ((u_char *) (p))[0] = (u_char) ((uint64_t) (n) >> 56); \
193
+ ((u_char *) (p))[1] = (u_char) ((uint64_t) (n) >> 48); \
194
+ ((u_char *) (p))[2] = (u_char) ((uint64_t) (n) >> 40); \
195
+ ((u_char *) (p))[3] = (u_char) ((uint64_t) (n) >> 32); \
196
+ ((u_char *) (p))[4] = (u_char) ( (n) >> 24); \
197
+ ((u_char *) (p))[5] = (u_char) ( (n) >> 16); \
198
+ ((u_char *) (p))[6] = (u_char) ( (n) >> 8); \
199
+ ((u_char *) (p))[7] = (u_char) (n)
200
+
201
+ #define ngx_mp4_last_trak(mp4) \
202
+ &((ngx_http_mp4_trak_t *) mp4->trak.elts)[mp4->trak.nelts - 1]
203
+
204
+
205
+ static ngx_int_t ngx_http_mp4_process(ngx_http_mp4_file_t *mp4);
206
+ static ngx_int_t ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4,
207
+ ngx_http_mp4_atom_handler_t *atom, uint64_t atom_data_size);
208
+ static ngx_int_t ngx_http_mp4_read(ngx_http_mp4_file_t *mp4, size_t size);
209
+ static ngx_int_t ngx_http_mp4_read_ftyp_atom(ngx_http_mp4_file_t *mp4,
210
+ uint64_t atom_data_size);
211
+ static ngx_int_t ngx_http_mp4_read_moov_atom(ngx_http_mp4_file_t *mp4,
212
+ uint64_t atom_data_size);
213
+ static ngx_int_t ngx_http_mp4_read_mdat_atom(ngx_http_mp4_file_t *mp4,
214
+ uint64_t atom_data_size);
215
+ static size_t ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4,
216
+ off_t start_offset);
217
+ static ngx_int_t ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4,
218
+ uint64_t atom_data_size);
219
+ static ngx_int_t ngx_http_mp4_read_trak_atom(ngx_http_mp4_file_t *mp4,
220
+ uint64_t atom_data_size);
221
+ static void ngx_http_mp4_update_trak_atom(ngx_http_mp4_file_t *mp4,
222
+ ngx_http_mp4_trak_t *trak);
223
+ static ngx_int_t ngx_http_mp4_read_cmov_atom(ngx_http_mp4_file_t *mp4,
224
+ uint64_t atom_data_size);
225
+ static ngx_int_t ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4,
226
+ uint64_t atom_data_size);
227
+ static ngx_int_t ngx_http_mp4_read_mdia_atom(ngx_http_mp4_file_t *mp4,
228
+ uint64_t atom_data_size);
229
+ static void ngx_http_mp4_update_mdia_atom(ngx_http_mp4_file_t *mp4,
230
+ ngx_http_mp4_trak_t *trak);
231
+ static ngx_int_t ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4,
232
+ uint64_t atom_data_size);
233
+ static ngx_int_t ngx_http_mp4_read_hdlr_atom(ngx_http_mp4_file_t *mp4,
234
+ uint64_t atom_data_size);
235
+ static ngx_int_t ngx_http_mp4_read_minf_atom(ngx_http_mp4_file_t *mp4,
236
+ uint64_t atom_data_size);
237
+ static void ngx_http_mp4_update_minf_atom(ngx_http_mp4_file_t *mp4,
238
+ ngx_http_mp4_trak_t *trak);
239
+ static ngx_int_t ngx_http_mp4_read_dinf_atom(ngx_http_mp4_file_t *mp4,
240
+ uint64_t atom_data_size);
241
+ static ngx_int_t ngx_http_mp4_read_vmhd_atom(ngx_http_mp4_file_t *mp4,
242
+ uint64_t atom_data_size);
243
+ static ngx_int_t ngx_http_mp4_read_smhd_atom(ngx_http_mp4_file_t *mp4,
244
+ uint64_t atom_data_size);
245
+ static ngx_int_t ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4,
246
+ uint64_t atom_data_size);
247
+ static void ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4,
248
+ ngx_http_mp4_trak_t *trak);
249
+ static ngx_int_t ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *mp4,
250
+ uint64_t atom_data_size);
251
+ static ngx_int_t ngx_http_mp4_read_stts_atom(ngx_http_mp4_file_t *mp4,
252
+ uint64_t atom_data_size);
253
+ static ngx_int_t ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4,
254
+ ngx_http_mp4_trak_t *trak);
255
+ static ngx_int_t ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4,
256
+ uint64_t atom_data_size);
257
+ static ngx_int_t ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4,
258
+ ngx_http_mp4_trak_t *trak);
259
+ static ngx_int_t ngx_http_mp4_read_ctts_atom(ngx_http_mp4_file_t *mp4,
260
+ uint64_t atom_data_size);
261
+ static void ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4,
262
+ ngx_http_mp4_trak_t *trak);
263
+ static ngx_int_t ngx_http_mp4_read_stsc_atom(ngx_http_mp4_file_t *mp4,
264
+ uint64_t atom_data_size);
265
+ static ngx_int_t ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4,
266
+ ngx_http_mp4_trak_t *trak);
267
+ static ngx_int_t ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *mp4,
268
+ uint64_t atom_data_size);
269
+ static ngx_int_t ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4,
270
+ ngx_http_mp4_trak_t *trak);
271
+ static ngx_int_t ngx_http_mp4_read_stco_atom(ngx_http_mp4_file_t *mp4,
272
+ uint64_t atom_data_size);
273
+ static ngx_int_t ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4,
274
+ ngx_http_mp4_trak_t *trak);
275
+ static void ngx_http_mp4_adjust_stco_atom(ngx_http_mp4_file_t *mp4,
276
+ ngx_http_mp4_trak_t *trak, int32_t adjustment);
277
+ static ngx_int_t ngx_http_mp4_read_co64_atom(ngx_http_mp4_file_t *mp4,
278
+ uint64_t atom_data_size);
279
+ static ngx_int_t ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4,
280
+ ngx_http_mp4_trak_t *trak);
281
+ static void ngx_http_mp4_adjust_co64_atom(ngx_http_mp4_file_t *mp4,
282
+ ngx_http_mp4_trak_t *trak, off_t adjustment);
283
+ static char *ngx_http_mp4(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
284
+ static void *ngx_http_mp4_create_conf(ngx_conf_t *cf);
285
+ static char *ngx_http_mp4_merge_conf(ngx_conf_t *cf, void *parent, void *child);
286
+
287
+ static ngx_command_t ngx_http_mp4_commands[] = {
288
+
289
+ { ngx_string("mp4"),
290
+ NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
291
+ ngx_http_mp4,
292
+ 0,
293
+ 0,
294
+ NULL },
295
+
296
+ { ngx_string("mp4_buffer_size"),
297
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
298
+ ngx_conf_set_size_slot,
299
+ NGX_HTTP_LOC_CONF_OFFSET,
300
+ offsetof(ngx_http_mp4_conf_t, buffer_size),
301
+ NULL },
302
+
303
+ { ngx_string("mp4_max_buffer_size"),
304
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
305
+ ngx_conf_set_size_slot,
306
+ NGX_HTTP_LOC_CONF_OFFSET,
307
+ offsetof(ngx_http_mp4_conf_t, max_buffer_size),
308
+ NULL },
309
+
310
+ ngx_null_command
311
+ };
312
+
313
+
314
+ static ngx_http_module_t ngx_http_mp4_module_ctx = {
315
+ NULL, /* preconfiguration */
316
+ NULL, /* postconfiguration */
317
+
318
+ NULL, /* create main configuration */
319
+ NULL, /* init main configuration */
320
+
321
+ NULL, /* create server configuration */
322
+ NULL, /* merge server configuration */
323
+
324
+ ngx_http_mp4_create_conf, /* create location configuration */
325
+ ngx_http_mp4_merge_conf /* merge location configuration */
326
+ };
327
+
328
+
329
+ ngx_module_t ngx_http_mp4_module = {
330
+ NGX_MODULE_V1,
331
+ &ngx_http_mp4_module_ctx, /* module context */
332
+ ngx_http_mp4_commands, /* module directives */
333
+ NGX_HTTP_MODULE, /* module type */
334
+ NULL, /* init master */
335
+ NULL, /* init module */
336
+ NULL, /* init process */
337
+ NULL, /* init thread */
338
+ NULL, /* exit thread */
339
+ NULL, /* exit process */
340
+ NULL, /* exit master */
341
+ NGX_MODULE_V1_PADDING
342
+ };
343
+
344
+
345
+ static ngx_http_mp4_atom_handler_t ngx_http_mp4_atoms[] = {
346
+ { "ftyp", ngx_http_mp4_read_ftyp_atom },
347
+ { "moov", ngx_http_mp4_read_moov_atom },
348
+ { "mdat", ngx_http_mp4_read_mdat_atom },
349
+ { NULL, NULL }
350
+ };
351
+
352
+ static ngx_http_mp4_atom_handler_t ngx_http_mp4_moov_atoms[] = {
353
+ { "mvhd", ngx_http_mp4_read_mvhd_atom },
354
+ { "trak", ngx_http_mp4_read_trak_atom },
355
+ { "cmov", ngx_http_mp4_read_cmov_atom },
356
+ { NULL, NULL }
357
+ };
358
+
359
+ static ngx_http_mp4_atom_handler_t ngx_http_mp4_trak_atoms[] = {
360
+ { "tkhd", ngx_http_mp4_read_tkhd_atom },
361
+ { "mdia", ngx_http_mp4_read_mdia_atom },
362
+ { NULL, NULL }
363
+ };
364
+
365
+ static ngx_http_mp4_atom_handler_t ngx_http_mp4_mdia_atoms[] = {
366
+ { "mdhd", ngx_http_mp4_read_mdhd_atom },
367
+ { "hdlr", ngx_http_mp4_read_hdlr_atom },
368
+ { "minf", ngx_http_mp4_read_minf_atom },
369
+ { NULL, NULL }
370
+ };
371
+
372
+ static ngx_http_mp4_atom_handler_t ngx_http_mp4_minf_atoms[] = {
373
+ { "vmhd", ngx_http_mp4_read_vmhd_atom },
374
+ { "smhd", ngx_http_mp4_read_smhd_atom },
375
+ { "dinf", ngx_http_mp4_read_dinf_atom },
376
+ { "stbl", ngx_http_mp4_read_stbl_atom },
377
+ { NULL, NULL }
378
+ };
379
+
380
+ static ngx_http_mp4_atom_handler_t ngx_http_mp4_stbl_atoms[] = {
381
+ { "stsd", ngx_http_mp4_read_stsd_atom },
382
+ { "stts", ngx_http_mp4_read_stts_atom },
383
+ { "stss", ngx_http_mp4_read_stss_atom },
384
+ { "ctts", ngx_http_mp4_read_ctts_atom },
385
+ { "stsc", ngx_http_mp4_read_stsc_atom },
386
+ { "stsz", ngx_http_mp4_read_stsz_atom },
387
+ { "stco", ngx_http_mp4_read_stco_atom },
388
+ { "co64", ngx_http_mp4_read_co64_atom },
389
+ { NULL, NULL }
390
+ };
391
+
392
+
393
+ static ngx_int_t
394
+ ngx_http_mp4_handler(ngx_http_request_t *r)
395
+ {
396
+ u_char *last;
397
+ size_t root;
398
+ ngx_int_t rc, start;
399
+ ngx_uint_t level;
400
+ ngx_str_t path, value;
401
+ ngx_log_t *log;
402
+ ngx_buf_t *b;
403
+ ngx_chain_t out;
404
+ ngx_http_mp4_file_t *mp4;
405
+ ngx_open_file_info_t of;
406
+ ngx_http_core_loc_conf_t *clcf;
407
+
408
+ if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
409
+ return NGX_HTTP_NOT_ALLOWED;
410
+ }
411
+
412
+ if (r->uri.data[r->uri.len - 1] == '/') {
413
+ return NGX_DECLINED;
414
+ }
415
+
416
+ rc = ngx_http_discard_request_body(r);
417
+
418
+ if (rc != NGX_OK) {
419
+ return rc;
420
+ }
421
+
422
+ last = ngx_http_map_uri_to_path(r, &path, &root, 0);
423
+ if (last == NULL) {
424
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
425
+ }
426
+
427
+ log = r->connection->log;
428
+
429
+ path.len = last - path.data;
430
+
431
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
432
+ "http mp4 filename: \"%V\"", &path);
433
+
434
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
435
+
436
+ ngx_memzero(&of, sizeof(ngx_open_file_info_t));
437
+
438
+ of.read_ahead = clcf->read_ahead;
439
+ of.directio = NGX_MAX_OFF_T_VALUE;
440
+ of.valid = clcf->open_file_cache_valid;
441
+ of.min_uses = clcf->open_file_cache_min_uses;
442
+ of.errors = clcf->open_file_cache_errors;
443
+ of.events = clcf->open_file_cache_events;
444
+
445
+ if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
446
+ != NGX_OK)
447
+ {
448
+ switch (of.err) {
449
+
450
+ case 0:
451
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
452
+
453
+ case NGX_ENOENT:
454
+ case NGX_ENOTDIR:
455
+ case NGX_ENAMETOOLONG:
456
+
457
+ level = NGX_LOG_ERR;
458
+ rc = NGX_HTTP_NOT_FOUND;
459
+ break;
460
+
461
+ case NGX_EACCES:
462
+
463
+ level = NGX_LOG_ERR;
464
+ rc = NGX_HTTP_FORBIDDEN;
465
+ break;
466
+
467
+ default:
468
+
469
+ level = NGX_LOG_CRIT;
470
+ rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
471
+ break;
472
+ }
473
+
474
+ if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
475
+ ngx_log_error(level, log, of.err,
476
+ "%s \"%s\" failed", of.failed, path.data);
477
+ }
478
+
479
+ return rc;
480
+ }
481
+
482
+ if (!of.is_file) {
483
+
484
+ if (ngx_close_file(of.fd) == NGX_FILE_ERROR) {
485
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
486
+ ngx_close_file_n " \"%s\" failed", path.data);
487
+ }
488
+
489
+ return NGX_DECLINED;
490
+ }
491
+
492
+ r->root_tested = !r->error_page;
493
+ r->allow_ranges = 1;
494
+
495
+ start = -1;
496
+ r->headers_out.content_length_n = of.size;
497
+ mp4 = NULL;
498
+ b = NULL;
499
+
500
+ if (r->args.len) {
501
+
502
+ if (ngx_http_arg(r, (u_char *) "start", 5, &value) == NGX_OK) {
503
+
504
+ /*
505
+ * A Flash player may send start value with a lot of digits
506
+ * after dot so strtod() is used instead of atofp(). NaNs and
507
+ * infinities become negative numbers after (int) conversion.
508
+ */
509
+
510
+ ngx_set_errno(0);
511
+ start = (int) (strtod((char *) value.data, NULL) * 1000);
512
+
513
+ if (ngx_errno == 0 && start >= 0) {
514
+ r->allow_ranges = 0;
515
+
516
+ mp4 = ngx_pcalloc(r->pool, sizeof(ngx_http_mp4_file_t));
517
+ if (mp4 == NULL) {
518
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
519
+ }
520
+
521
+ mp4->file.fd = of.fd;
522
+ mp4->file.name = path;
523
+ mp4->file.log = r->connection->log;;
524
+ mp4->end = of.size;
525
+ mp4->start = (ngx_uint_t) start;
526
+ mp4->request = r;
527
+
528
+ switch (ngx_http_mp4_process(mp4)) {
529
+
530
+ case NGX_DECLINED:
531
+ if (mp4->buffer) {
532
+ ngx_pfree(r->pool, mp4->buffer);
533
+ }
534
+
535
+ ngx_pfree(r->pool, mp4);
536
+ mp4 = NULL;
537
+
538
+ break;
539
+
540
+ case NGX_OK:
541
+ r->headers_out.content_length_n = mp4->content_length;
542
+ break;
543
+
544
+ default: /* NGX_ERROR */
545
+ if (mp4->buffer) {
546
+ ngx_pfree(r->pool, mp4->buffer);
547
+ }
548
+
549
+ ngx_pfree(r->pool, mp4);
550
+
551
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
552
+ }
553
+ }
554
+ }
555
+ }
556
+
557
+ log->action = "sending mp4 to client";
558
+
559
+ if (clcf->directio <= of.size) {
560
+
561
+ /*
562
+ * DIRECTIO is set on transfer only
563
+ * to allow kernel to cache "moov" atom
564
+ */
565
+
566
+ if (ngx_directio_on(of.fd) == NGX_FILE_ERROR) {
567
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
568
+ ngx_directio_on_n " \"%s\" failed", path.data);
569
+ }
570
+
571
+ of.is_directio = 1;
572
+
573
+ if (mp4) {
574
+ mp4->file.directio = 1;
575
+ }
576
+ }
577
+
578
+ r->headers_out.status = NGX_HTTP_OK;
579
+ r->headers_out.last_modified_time = of.mtime;
580
+
581
+ if (ngx_http_set_content_type(r) != NGX_OK) {
582
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
583
+ }
584
+
585
+ if (mp4 == NULL) {
586
+ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
587
+ if (b == NULL) {
588
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
589
+ }
590
+
591
+ b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
592
+ if (b->file == NULL) {
593
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
594
+ }
595
+ }
596
+
597
+ rc = ngx_http_send_header(r);
598
+
599
+ if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
600
+ return rc;
601
+ }
602
+
603
+ if (mp4) {
604
+ return ngx_http_output_filter(r, mp4->out);
605
+ }
606
+
607
+ b->file_pos = 0;
608
+ b->file_last = of.size;
609
+
610
+ b->in_file = b->file_last ? 1 : 0;
611
+ b->last_buf = 1;
612
+ b->last_in_chain = 1;
613
+
614
+ b->file->fd = of.fd;
615
+ b->file->name = path;
616
+ b->file->log = log;
617
+ b->file->directio = of.is_directio;
618
+
619
+ out.buf = b;
620
+ out.next = NULL;
621
+
622
+ return ngx_http_output_filter(r, &out);
623
+ }
624
+
625
+
626
+ static ngx_int_t
627
+ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4)
628
+ {
629
+ off_t start_offset, adjustment;
630
+ ngx_int_t rc;
631
+ ngx_uint_t i, j;
632
+ ngx_chain_t **prev;
633
+ ngx_http_mp4_trak_t *trak;
634
+ ngx_http_mp4_conf_t *conf;
635
+
636
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
637
+ "mp4 start:%ui", mp4->start);
638
+
639
+ conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module);
640
+
641
+ mp4->buffer_size = conf->buffer_size;
642
+
643
+ rc = ngx_http_mp4_read_atom(mp4, ngx_http_mp4_atoms, mp4->end);
644
+ if (rc != NGX_OK) {
645
+ return rc;
646
+ }
647
+
648
+ if (mp4->trak.nelts == 0) {
649
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
650
+ "no mp4 trak atoms were found in \"%s\"",
651
+ mp4->file.name.data);
652
+ return NGX_ERROR;
653
+ }
654
+
655
+ if (mp4->mdat_atom.buf == NULL) {
656
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
657
+ "no mp4 mdat atom was found in \"%s\"",
658
+ mp4->file.name.data);
659
+ return NGX_ERROR;
660
+ }
661
+
662
+ prev = &mp4->out;
663
+
664
+ if (mp4->ftyp_atom.buf) {
665
+ *prev = &mp4->ftyp_atom;
666
+ prev = &mp4->ftyp_atom.next;
667
+ }
668
+
669
+ *prev = &mp4->moov_atom;
670
+ prev = &mp4->moov_atom.next;
671
+
672
+ if (mp4->mvhd_atom.buf) {
673
+ mp4->moov_size += mp4->mvhd_atom_buf.last - mp4->mvhd_atom_buf.pos;
674
+ *prev = &mp4->mvhd_atom;
675
+ prev = &mp4->mvhd_atom.next;
676
+ }
677
+
678
+ start_offset = mp4->end;
679
+ trak = mp4->trak.elts;
680
+
681
+ for (i = 0; i < mp4->trak.nelts; i++) {
682
+
683
+ if (ngx_http_mp4_update_stts_atom(mp4, &trak[i]) != NGX_OK) {
684
+ return NGX_ERROR;
685
+ }
686
+
687
+ if (ngx_http_mp4_update_stss_atom(mp4, &trak[i]) != NGX_OK) {
688
+ return NGX_ERROR;
689
+ }
690
+
691
+ ngx_http_mp4_update_ctts_atom(mp4, &trak[i]);
692
+
693
+ if (ngx_http_mp4_update_stsc_atom(mp4, &trak[i]) != NGX_OK) {
694
+ return NGX_ERROR;
695
+ }
696
+
697
+ if (ngx_http_mp4_update_stsz_atom(mp4, &trak[i]) != NGX_OK) {
698
+ return NGX_ERROR;
699
+ }
700
+
701
+ if (trak[i].out[NGX_HTTP_MP4_CO64_DATA].buf) {
702
+ if (ngx_http_mp4_update_co64_atom(mp4, &trak[i]) != NGX_OK) {
703
+ return NGX_ERROR;
704
+ }
705
+
706
+ } else {
707
+ if (ngx_http_mp4_update_stco_atom(mp4, &trak[i]) != NGX_OK) {
708
+ return NGX_ERROR;
709
+ }
710
+ }
711
+
712
+ ngx_http_mp4_update_stbl_atom(mp4, &trak[i]);
713
+ ngx_http_mp4_update_minf_atom(mp4, &trak[i]);
714
+ trak[i].size += trak[i].mdhd_size;
715
+ trak[i].size += trak[i].hdlr_size;
716
+ ngx_http_mp4_update_mdia_atom(mp4, &trak[i]);
717
+ trak[i].size += trak[i].tkhd_size;
718
+ ngx_http_mp4_update_trak_atom(mp4, &trak[i]);
719
+
720
+ mp4->moov_size += trak[i].size;
721
+
722
+ if (start_offset > trak[i].start_offset) {
723
+ start_offset = trak[i].start_offset;
724
+ }
725
+
726
+ *prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM];
727
+ prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM].next;
728
+
729
+ for (j = 0; j < NGX_HTTP_MP4_LAST_ATOM + 1; j++) {
730
+ if (trak[i].out[j].buf) {
731
+ *prev = &trak[i].out[j];
732
+ prev = &trak[i].out[j].next;
733
+ }
734
+ }
735
+ }
736
+
737
+ mp4->moov_size += 8;
738
+
739
+ ngx_mp4_set_32value(mp4->moov_atom_header, mp4->moov_size);
740
+ ngx_mp4_set_atom_name(mp4->moov_atom_header, 'm', 'o', 'o', 'v');
741
+ mp4->content_length += mp4->moov_size;
742
+
743
+ *prev = &mp4->mdat_atom;
744
+
745
+ adjustment = mp4->ftyp_size + mp4->moov_size
746
+ + ngx_http_mp4_update_mdat_atom(mp4, start_offset)
747
+ - start_offset;
748
+
749
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
750
+ "mp4 adjustment:%O", adjustment);
751
+
752
+ for (i = 0; i < mp4->trak.nelts; i++) {
753
+ if (trak[i].out[NGX_HTTP_MP4_CO64_DATA].buf) {
754
+ ngx_http_mp4_adjust_co64_atom(mp4, &trak[i], adjustment);
755
+ } else {
756
+ ngx_http_mp4_adjust_stco_atom(mp4, &trak[i], (int32_t) adjustment);
757
+ }
758
+ }
759
+
760
+ return NGX_OK;
761
+ }
762
+
763
+
764
+ typedef struct {
765
+ u_char size[4];
766
+ u_char name[4];
767
+ } ngx_mp4_atom_header_t;
768
+
769
+ typedef struct {
770
+ u_char size[4];
771
+ u_char name[4];
772
+ u_char size64[8];
773
+ } ngx_mp4_atom_header64_t;
774
+
775
+
776
+ static ngx_int_t
777
+ ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4,
778
+ ngx_http_mp4_atom_handler_t *atom, uint64_t atom_data_size)
779
+ {
780
+ off_t end;
781
+ size_t atom_header_size;
782
+ u_char *atom_header, *atom_name;
783
+ uint64_t atom_size;
784
+ ngx_int_t rc;
785
+ ngx_uint_t n;
786
+
787
+ end = mp4->offset + atom_data_size;
788
+
789
+ while (mp4->offset < end) {
790
+
791
+ if (ngx_http_mp4_read(mp4, sizeof(uint32_t)) != NGX_OK) {
792
+ return NGX_ERROR;
793
+ }
794
+
795
+ atom_header = mp4->buffer_pos;
796
+ atom_size = ngx_mp4_get_32value(atom_header);
797
+ atom_header_size = sizeof(ngx_mp4_atom_header_t);
798
+
799
+ if (atom_size == 0) {
800
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
801
+ "mp4 atom end");
802
+ return NGX_OK;
803
+ }
804
+
805
+ if (atom_size < sizeof(ngx_mp4_atom_header_t)) {
806
+
807
+ if (atom_size == 1) {
808
+
809
+ if (ngx_http_mp4_read(mp4, sizeof(ngx_mp4_atom_header64_t))
810
+ != NGX_OK)
811
+ {
812
+ return NGX_ERROR;
813
+ }
814
+
815
+ /* 64-bit atom size */
816
+ atom_header = mp4->buffer_pos;
817
+ atom_size = ngx_mp4_get_64value(atom_header + 8);
818
+ atom_header_size = sizeof(ngx_mp4_atom_header64_t);
819
+
820
+ } else {
821
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
822
+ "\"%s\" mp4 atom is too small:%uL",
823
+ mp4->file.name.data, atom_size);
824
+ return NGX_ERROR;
825
+ }
826
+ }
827
+
828
+ if (ngx_http_mp4_read(mp4, sizeof(ngx_mp4_atom_header_t)) != NGX_OK) {
829
+ return NGX_ERROR;
830
+ }
831
+
832
+ atom_header = mp4->buffer_pos;
833
+ atom_name = atom_header + sizeof(uint32_t);
834
+
835
+ ngx_log_debug4(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
836
+ "mp4 atom: %*s @%O:%uL",
837
+ 4, atom_name, mp4->offset, atom_size);
838
+
839
+ if (atom_size > (uint64_t) (NGX_MAX_OFF_T_VALUE - mp4->offset)
840
+ || mp4->offset + (off_t) atom_size > end)
841
+ {
842
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
843
+ "\"%s\" mp4 atom too large:%uL",
844
+ mp4->file.name.data, atom_size);
845
+ return NGX_ERROR;
846
+ }
847
+
848
+ for (n = 0; atom[n].name; n++) {
849
+
850
+ if (ngx_strncmp(atom_name, atom[n].name, 4) == 0) {
851
+
852
+ ngx_mp4_atom_next(mp4, atom_header_size);
853
+
854
+ rc = atom[n].handler(mp4, atom_size - atom_header_size);
855
+ if (rc != NGX_OK) {
856
+ return rc;
857
+ }
858
+
859
+ goto next;
860
+ }
861
+ }
862
+
863
+ ngx_mp4_atom_next(mp4, atom_size);
864
+
865
+ next:
866
+ continue;
867
+ }
868
+
869
+ return NGX_OK;
870
+ }
871
+
872
+
873
+ static ngx_int_t
874
+ ngx_http_mp4_read(ngx_http_mp4_file_t *mp4, size_t size)
875
+ {
876
+ ssize_t n;
877
+
878
+ if (mp4->buffer_pos + size <= mp4->buffer_end) {
879
+ return NGX_OK;
880
+ }
881
+
882
+ if (mp4->offset + (off_t) mp4->buffer_size > mp4->end) {
883
+ mp4->buffer_size = (size_t) (mp4->end - mp4->offset);
884
+ }
885
+
886
+ if (mp4->buffer_size < size) {
887
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
888
+ "\"%s\" mp4 file truncated", mp4->file.name.data);
889
+ return NGX_ERROR;
890
+ }
891
+
892
+ if (mp4->buffer == NULL) {
893
+ mp4->buffer = ngx_palloc(mp4->request->pool, mp4->buffer_size);
894
+ if (mp4->buffer == NULL) {
895
+ return NGX_ERROR;
896
+ }
897
+
898
+ mp4->buffer_start = mp4->buffer;
899
+ }
900
+
901
+ n = ngx_read_file(&mp4->file, mp4->buffer_start, mp4->buffer_size,
902
+ mp4->offset);
903
+
904
+ if (n == NGX_ERROR) {
905
+ return NGX_ERROR;
906
+ }
907
+
908
+ if ((size_t) n != mp4->buffer_size) {
909
+ ngx_log_error(NGX_LOG_CRIT, mp4->file.log, 0,
910
+ ngx_read_file_n " read only %z of %z from \"%s\"",
911
+ n, mp4->buffer_size, mp4->file.name.data);
912
+ return NGX_ERROR;
913
+ }
914
+
915
+ mp4->buffer_pos = mp4->buffer_start;
916
+ mp4->buffer_end = mp4->buffer_start + mp4->buffer_size;
917
+
918
+ return NGX_OK;
919
+ }
920
+
921
+
922
+ static ngx_int_t
923
+ ngx_http_mp4_read_ftyp_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
924
+ {
925
+ u_char *ftyp_atom;
926
+ size_t atom_size;
927
+ ngx_buf_t *atom;
928
+
929
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 ftyp atom");
930
+
931
+ if (atom_data_size > 1024
932
+ || ngx_mp4_atom_data(mp4) + atom_data_size > mp4->buffer_end)
933
+ {
934
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
935
+ "\"%s\" mp4 ftyp atom is too large:%uL",
936
+ mp4->file.name.data, atom_data_size);
937
+ return NGX_ERROR;
938
+ }
939
+
940
+ atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size;
941
+
942
+ ftyp_atom = ngx_palloc(mp4->request->pool, atom_size);
943
+ if (ftyp_atom == NULL) {
944
+ return NGX_ERROR;
945
+ }
946
+
947
+ ngx_mp4_set_32value(ftyp_atom, atom_size);
948
+ ngx_mp4_set_atom_name(ftyp_atom, 'f', 't', 'y', 'p');
949
+
950
+ /*
951
+ * only moov atom content is guaranteed to be in mp4->buffer
952
+ * during sending response, so ftyp atom content should be copied
953
+ */
954
+ ngx_memcpy(ftyp_atom + sizeof(ngx_mp4_atom_header_t),
955
+ ngx_mp4_atom_data(mp4), (size_t) atom_data_size);
956
+
957
+ atom = &mp4->ftyp_atom_buf;
958
+ atom->temporary = 1;
959
+ atom->pos = ftyp_atom;
960
+ atom->last = ftyp_atom + atom_size;
961
+
962
+ mp4->ftyp_atom.buf = atom;
963
+ mp4->ftyp_size = atom_size;
964
+ mp4->content_length = atom_size;
965
+
966
+ ngx_mp4_atom_next(mp4, atom_data_size);
967
+
968
+ return NGX_OK;
969
+ }
970
+
971
+
972
+ /*
973
+ * Small excess buffer to process atoms after moov atom, mp4->buffer_start
974
+ * will be set to this buffer part after moov atom processing.
975
+ */
976
+ #define NGX_HTTP_MP4_MOOV_BUFFER_EXCESS (4 * 1024)
977
+
978
+ static ngx_int_t
979
+ ngx_http_mp4_read_moov_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
980
+ {
981
+ ngx_int_t rc;
982
+ ngx_uint_t no_mdat;
983
+ ngx_buf_t *atom;
984
+ ngx_http_mp4_conf_t *conf;
985
+
986
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 moov atom");
987
+
988
+ no_mdat = (mp4->mdat_atom.buf == NULL);
989
+
990
+ if (no_mdat && mp4->start == 0) {
991
+ /*
992
+ * send original file if moov atom resides before
993
+ * mdat atom and client requests integral file
994
+ */
995
+ return NGX_DECLINED;
996
+ }
997
+
998
+ conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module);
999
+
1000
+ if (atom_data_size > mp4->buffer_size) {
1001
+
1002
+ if (atom_data_size > conf->max_buffer_size) {
1003
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
1004
+ "\"%s\" mp4 moov atom is too large:%uL, "
1005
+ "you may want to increase mp4_max_buffer_size",
1006
+ mp4->file.name.data, atom_data_size);
1007
+ return NGX_ERROR;
1008
+ }
1009
+
1010
+ ngx_pfree(mp4->request->pool, mp4->buffer);
1011
+ mp4->buffer = NULL;
1012
+ mp4->buffer_pos = NULL;
1013
+ mp4->buffer_end = NULL;
1014
+
1015
+ mp4->buffer_size = (size_t) atom_data_size
1016
+ + NGX_HTTP_MP4_MOOV_BUFFER_EXCESS * no_mdat;
1017
+ }
1018
+
1019
+ mp4->trak.elts = &mp4->traks;
1020
+ mp4->trak.size = sizeof(ngx_http_mp4_trak_t);
1021
+ mp4->trak.nalloc = 2;
1022
+ mp4->trak.pool = mp4->request->pool;
1023
+
1024
+ atom = &mp4->moov_atom_buf;
1025
+ atom->temporary = 1;
1026
+ atom->pos = mp4->moov_atom_header;
1027
+ atom->last = mp4->moov_atom_header + 8;
1028
+
1029
+ mp4->moov_atom.buf = &mp4->moov_atom_buf;
1030
+
1031
+ rc = ngx_http_mp4_read_atom(mp4, ngx_http_mp4_moov_atoms, atom_data_size);
1032
+
1033
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 moov atom done");
1034
+
1035
+ if (no_mdat) {
1036
+ mp4->buffer_start = mp4->buffer_pos;
1037
+ mp4->buffer_size = NGX_HTTP_MP4_MOOV_BUFFER_EXCESS;
1038
+
1039
+ } else {
1040
+ /* skip atoms after moov atom */
1041
+ mp4->offset = mp4->end;
1042
+ }
1043
+
1044
+ return rc;
1045
+ }
1046
+
1047
+
1048
+ static ngx_int_t
1049
+ ngx_http_mp4_read_mdat_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
1050
+ {
1051
+ ngx_buf_t *data;
1052
+
1053
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 mdat atom");
1054
+
1055
+ data = &mp4->mdat_data_buf;
1056
+ data->file = &mp4->file;
1057
+ data->in_file = 1;
1058
+ data->last_buf = 1;
1059
+ data->last_in_chain = 1;
1060
+ data->file_last = mp4->offset + atom_data_size;
1061
+
1062
+ mp4->mdat_atom.buf = &mp4->mdat_atom_buf;
1063
+ mp4->mdat_atom.next = &mp4->mdat_data;
1064
+ mp4->mdat_data.buf = data;
1065
+
1066
+ if (mp4->trak.nelts) {
1067
+ /* skip atoms after mdat atom */
1068
+ mp4->offset = mp4->end;
1069
+
1070
+ } else {
1071
+ ngx_mp4_atom_next(mp4, atom_data_size);
1072
+ }
1073
+
1074
+ return NGX_OK;
1075
+ }
1076
+
1077
+
1078
+ static size_t
1079
+ ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset)
1080
+ {
1081
+ off_t atom_data_size;
1082
+ u_char *atom_header;
1083
+ uint32_t atom_header_size;
1084
+ uint64_t atom_size;
1085
+ ngx_buf_t *atom;
1086
+
1087
+ atom_data_size = mp4->mdat_data.buf->file_last - start_offset;
1088
+ mp4->mdat_data.buf->file_pos = start_offset;
1089
+
1090
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
1091
+ "mdat new offset @%O:%O", start_offset, atom_data_size);
1092
+
1093
+ atom_header = mp4->mdat_atom_header;
1094
+
1095
+ if ((uint64_t) atom_data_size > 0xffffffff) {
1096
+ atom_size = 1;
1097
+ atom_header_size = sizeof(ngx_mp4_atom_header64_t);
1098
+ ngx_mp4_set_64value(atom_header + sizeof(ngx_mp4_atom_header_t),
1099
+ sizeof(ngx_mp4_atom_header64_t) + atom_data_size);
1100
+ } else {
1101
+ atom_size = sizeof(ngx_mp4_atom_header_t) + atom_data_size;
1102
+ atom_header_size = sizeof(ngx_mp4_atom_header_t);
1103
+ }
1104
+
1105
+ mp4->content_length += atom_header_size + atom_data_size;
1106
+
1107
+ ngx_mp4_set_32value(atom_header, atom_size);
1108
+ ngx_mp4_set_atom_name(atom_header, 'm', 'd', 'a', 't');
1109
+
1110
+ atom = &mp4->mdat_atom_buf;
1111
+ atom->temporary = 1;
1112
+ atom->pos = atom_header;
1113
+ atom->last = atom_header + atom_header_size;
1114
+
1115
+ return atom_header_size;
1116
+ }
1117
+
1118
+
1119
+ typedef struct {
1120
+ u_char size[4];
1121
+ u_char name[4];
1122
+ u_char version[1];
1123
+ u_char flags[3];
1124
+ u_char creation_time[4];
1125
+ u_char modification_time[4];
1126
+ u_char timescale[4];
1127
+ u_char duration[4];
1128
+ u_char rate[4];
1129
+ u_char volume[2];
1130
+ u_char reserved[10];
1131
+ u_char matrix[36];
1132
+ u_char preview_time[4];
1133
+ u_char preview_duration[4];
1134
+ u_char poster_time[4];
1135
+ u_char selection_time[4];
1136
+ u_char selection_duration[4];
1137
+ u_char current_time[4];
1138
+ u_char next_track_id[4];
1139
+ } ngx_mp4_mvhd_atom_t;
1140
+
1141
+ typedef struct {
1142
+ u_char size[4];
1143
+ u_char name[4];
1144
+ u_char version[1];
1145
+ u_char flags[3];
1146
+ u_char creation_time[8];
1147
+ u_char modification_time[8];
1148
+ u_char timescale[4];
1149
+ u_char duration[8];
1150
+ u_char rate[4];
1151
+ u_char volume[2];
1152
+ u_char reserved[10];
1153
+ u_char matrix[36];
1154
+ u_char preview_time[4];
1155
+ u_char preview_duration[4];
1156
+ u_char poster_time[4];
1157
+ u_char selection_time[4];
1158
+ u_char selection_duration[4];
1159
+ u_char current_time[4];
1160
+ u_char next_track_id[4];
1161
+ } ngx_mp4_mvhd64_atom_t;
1162
+
1163
+
1164
+ static ngx_int_t
1165
+ ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
1166
+ {
1167
+ u_char *atom_header;
1168
+ size_t atom_size;
1169
+ uint32_t timescale;
1170
+ uint64_t duration;
1171
+ ngx_buf_t *atom;
1172
+ ngx_mp4_mvhd_atom_t *mvhd_atom;
1173
+ ngx_mp4_mvhd64_atom_t *mvhd64_atom;
1174
+
1175
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 mvhd atom");
1176
+
1177
+ atom_header = ngx_mp4_atom_header(mp4);
1178
+ mvhd_atom = (ngx_mp4_mvhd_atom_t *) atom_header;
1179
+ mvhd64_atom = (ngx_mp4_mvhd64_atom_t *) atom_header;
1180
+ ngx_mp4_set_atom_name(atom_header, 'm', 'v', 'h', 'd');
1181
+
1182
+ if (ngx_mp4_atom_data_size(ngx_mp4_mvhd_atom_t) > atom_data_size) {
1183
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
1184
+ "\"%s\" mp4 mvhd atom too small", mp4->file.name.data);
1185
+ return NGX_ERROR;
1186
+ }
1187
+
1188
+ if (mvhd_atom->version[0] == 0) {
1189
+ /* version 0: 32-bit duration */
1190
+ timescale = ngx_mp4_get_32value(mvhd_atom->timescale);
1191
+ duration = ngx_mp4_get_32value(mvhd_atom->duration);
1192
+
1193
+ } else {
1194
+ /* version 1: 64-bit duration */
1195
+
1196
+ if (ngx_mp4_atom_data_size(ngx_mp4_mvhd64_atom_t) > atom_data_size) {
1197
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
1198
+ "\"%s\" mp4 mvhd atom too small",
1199
+ mp4->file.name.data);
1200
+ return NGX_ERROR;
1201
+ }
1202
+
1203
+ timescale = ngx_mp4_get_32value(mvhd64_atom->timescale);
1204
+ duration = ngx_mp4_get_64value(mvhd64_atom->duration);
1205
+ }
1206
+
1207
+ mp4->timescale = timescale;
1208
+
1209
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
1210
+ "mvhd timescale:%uD, duration:%uL, time:%.3fs",
1211
+ timescale, duration, (double) duration / timescale);
1212
+
1213
+ duration -= (uint64_t) mp4->start * timescale / 1000;
1214
+
1215
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
1216
+ "mvhd new duration:%uL, time:%.3fs",
1217
+ duration, (double) duration / timescale);
1218
+
1219
+ atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size;
1220
+ ngx_mp4_set_32value(mvhd_atom->size, atom_size);
1221
+
1222
+ if (mvhd_atom->version[0] == 0) {
1223
+ ngx_mp4_set_32value(mvhd_atom->duration, duration);
1224
+
1225
+ } else {
1226
+ ngx_mp4_set_64value(mvhd64_atom->duration, duration);
1227
+ }
1228
+
1229
+ atom = &mp4->mvhd_atom_buf;
1230
+ atom->temporary = 1;
1231
+ atom->pos = atom_header;
1232
+ atom->last = atom_header + atom_size;
1233
+
1234
+ mp4->mvhd_atom.buf = atom;
1235
+
1236
+ ngx_mp4_atom_next(mp4, atom_data_size);
1237
+
1238
+ return NGX_OK;
1239
+ }
1240
+
1241
+
1242
+ static ngx_int_t
1243
+ ngx_http_mp4_read_trak_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
1244
+ {
1245
+ u_char *atom_header, *atom_end;
1246
+ off_t atom_file_end;
1247
+ ngx_int_t rc;
1248
+ ngx_buf_t *atom;
1249
+ ngx_http_mp4_trak_t *trak;
1250
+
1251
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 trak atom");
1252
+
1253
+ trak = ngx_array_push(&mp4->trak);
1254
+ if (trak == NULL) {
1255
+ return NGX_ERROR;
1256
+ }
1257
+
1258
+ ngx_memzero(trak, sizeof(ngx_http_mp4_trak_t));
1259
+
1260
+ atom_header = ngx_mp4_atom_header(mp4);
1261
+ ngx_mp4_set_atom_name(atom_header, 't', 'r', 'a', 'k');
1262
+
1263
+ atom = &trak->trak_atom_buf;
1264
+ atom->temporary = 1;
1265
+ atom->pos = atom_header;
1266
+ atom->last = atom_header + sizeof(ngx_mp4_atom_header_t);
1267
+
1268
+ trak->out[NGX_HTTP_MP4_TRAK_ATOM].buf = atom;
1269
+
1270
+ atom_end = mp4->buffer_pos + atom_data_size;
1271
+ atom_file_end = mp4->offset + atom_data_size;
1272
+
1273
+ rc = ngx_http_mp4_read_atom(mp4, ngx_http_mp4_trak_atoms, atom_data_size);
1274
+
1275
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
1276
+ "mp4 trak atom: %i", rc);
1277
+
1278
+ if (rc == NGX_DECLINED) {
1279
+ /* skip this trak */
1280
+ ngx_memzero(trak, sizeof(ngx_http_mp4_trak_t));
1281
+ mp4->trak.nelts--;
1282
+ mp4->buffer_pos = atom_end;
1283
+ mp4->offset = atom_file_end;
1284
+ return NGX_OK;
1285
+ }
1286
+
1287
+ return rc;
1288
+ }
1289
+
1290
+
1291
+ static void
1292
+ ngx_http_mp4_update_trak_atom(ngx_http_mp4_file_t *mp4,
1293
+ ngx_http_mp4_trak_t *trak)
1294
+ {
1295
+ ngx_buf_t *atom;
1296
+
1297
+ trak->size += sizeof(ngx_mp4_atom_header_t);
1298
+ atom = &trak->trak_atom_buf;
1299
+ ngx_mp4_set_32value(atom->pos, trak->size);
1300
+ }
1301
+
1302
+
1303
+ static ngx_int_t
1304
+ ngx_http_mp4_read_cmov_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
1305
+ {
1306
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
1307
+ "\"%s\" mp4 compressed moov atom (cmov) is not supported",
1308
+ mp4->file.name.data);
1309
+
1310
+ return NGX_ERROR;
1311
+ }
1312
+
1313
+
1314
+ typedef struct {
1315
+ u_char size[4];
1316
+ u_char name[4];
1317
+ u_char version[1];
1318
+ u_char flags[3];
1319
+ u_char creation_time[4];
1320
+ u_char modification_time[4];
1321
+ u_char track_id[4];
1322
+ u_char reserved1[4];
1323
+ u_char duration[4];
1324
+ u_char reserved2[8];
1325
+ u_char layer[2];
1326
+ u_char group[2];
1327
+ u_char volume[2];
1328
+ u_char reverved3[2];
1329
+ u_char matrix[36];
1330
+ u_char width[4];
1331
+ u_char heigth[4];
1332
+ } ngx_mp4_tkhd_atom_t;
1333
+
1334
+ typedef struct {
1335
+ u_char size[4];
1336
+ u_char name[4];
1337
+ u_char version[1];
1338
+ u_char flags[3];
1339
+ u_char creation_time[8];
1340
+ u_char modification_time[8];
1341
+ u_char track_id[4];
1342
+ u_char reserved1[4];
1343
+ u_char duration[8];
1344
+ u_char reserved2[8];
1345
+ u_char layer[2];
1346
+ u_char group[2];
1347
+ u_char volume[2];
1348
+ u_char reverved3[2];
1349
+ u_char matrix[36];
1350
+ u_char width[4];
1351
+ u_char heigth[4];
1352
+ } ngx_mp4_tkhd64_atom_t;
1353
+
1354
+
1355
+ static ngx_int_t
1356
+ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
1357
+ {
1358
+ u_char *atom_header;
1359
+ size_t atom_size;
1360
+ uint64_t duration;
1361
+ ngx_buf_t *atom;
1362
+ ngx_http_mp4_trak_t *trak;
1363
+ ngx_mp4_tkhd_atom_t *tkhd_atom;
1364
+ ngx_mp4_tkhd64_atom_t *tkhd64_atom;
1365
+
1366
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 tkhd atom");
1367
+
1368
+ atom_header = ngx_mp4_atom_header(mp4);
1369
+ tkhd_atom = (ngx_mp4_tkhd_atom_t *) atom_header;
1370
+ tkhd64_atom = (ngx_mp4_tkhd64_atom_t *) atom_header;
1371
+ ngx_mp4_set_atom_name(tkhd_atom, 't', 'k', 'h', 'd');
1372
+
1373
+ if (ngx_mp4_atom_data_size(ngx_mp4_tkhd_atom_t) > atom_data_size) {
1374
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
1375
+ "\"%s\" mp4 tkhd atom too small", mp4->file.name.data);
1376
+ return NGX_ERROR;
1377
+ }
1378
+
1379
+ if (tkhd_atom->version[0] == 0) {
1380
+ /* version 0: 32-bit duration */
1381
+ duration = ngx_mp4_get_32value(tkhd_atom->duration);
1382
+
1383
+ } else {
1384
+ /* version 1: 64-bit duration */
1385
+
1386
+ if (ngx_mp4_atom_data_size(ngx_mp4_tkhd64_atom_t) > atom_data_size) {
1387
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
1388
+ "\"%s\" mp4 tkhd atom too small",
1389
+ mp4->file.name.data);
1390
+ return NGX_ERROR;
1391
+ }
1392
+
1393
+ duration = ngx_mp4_get_64value(tkhd64_atom->duration);
1394
+ }
1395
+
1396
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
1397
+ "tkhd duration:%uL, time:%.3fs",
1398
+ duration, (double) duration / mp4->timescale);
1399
+
1400
+ duration -= (uint64_t) mp4->start * mp4->timescale / 1000;
1401
+
1402
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
1403
+ "tkhd new duration:%uL, time:%.3fs",
1404
+ duration, (double) duration / mp4->timescale);
1405
+
1406
+ atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size;
1407
+
1408
+ trak = ngx_mp4_last_trak(mp4);
1409
+ trak->tkhd_size = atom_size;
1410
+
1411
+ ngx_mp4_set_32value(tkhd_atom->size, atom_size);
1412
+
1413
+ if (tkhd_atom->version[0] == 0) {
1414
+ ngx_mp4_set_32value(tkhd_atom->duration, duration);
1415
+
1416
+ } else {
1417
+ ngx_mp4_set_64value(tkhd64_atom->duration, duration);
1418
+ }
1419
+
1420
+ atom = &trak->tkhd_atom_buf;
1421
+ atom->temporary = 1;
1422
+ atom->pos = atom_header;
1423
+ atom->last = atom_header + atom_size;
1424
+
1425
+ trak->out[NGX_HTTP_MP4_TKHD_ATOM].buf = atom;
1426
+
1427
+ ngx_mp4_atom_next(mp4, atom_data_size);
1428
+
1429
+ return NGX_OK;
1430
+ }
1431
+
1432
+
1433
+ static ngx_int_t
1434
+ ngx_http_mp4_read_mdia_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
1435
+ {
1436
+ u_char *atom_header;
1437
+ ngx_buf_t *atom;
1438
+ ngx_http_mp4_trak_t *trak;
1439
+
1440
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "process mdia atom");
1441
+
1442
+ atom_header = ngx_mp4_atom_header(mp4);
1443
+ ngx_mp4_set_atom_name(atom_header, 'm', 'd', 'i', 'a');
1444
+
1445
+ trak = ngx_mp4_last_trak(mp4);
1446
+
1447
+ atom = &trak->mdia_atom_buf;
1448
+ atom->temporary = 1;
1449
+ atom->pos = atom_header;
1450
+ atom->last = atom_header + sizeof(ngx_mp4_atom_header_t);
1451
+
1452
+ trak->out[NGX_HTTP_MP4_MDIA_ATOM].buf = atom;
1453
+
1454
+ return ngx_http_mp4_read_atom(mp4, ngx_http_mp4_mdia_atoms, atom_data_size);
1455
+ }
1456
+
1457
+
1458
+ static void
1459
+ ngx_http_mp4_update_mdia_atom(ngx_http_mp4_file_t *mp4,
1460
+ ngx_http_mp4_trak_t *trak)
1461
+ {
1462
+ ngx_buf_t *atom;
1463
+
1464
+ trak->size += sizeof(ngx_mp4_atom_header_t);
1465
+ atom = &trak->mdia_atom_buf;
1466
+ ngx_mp4_set_32value(atom->pos, trak->size);
1467
+ }
1468
+
1469
+
1470
+ typedef struct {
1471
+ u_char size[4];
1472
+ u_char name[4];
1473
+ u_char version[1];
1474
+ u_char flags[3];
1475
+ u_char creation_time[4];
1476
+ u_char modification_time[4];
1477
+ u_char timescale[4];
1478
+ u_char duration[4];
1479
+ u_char language[2];
1480
+ u_char quality[2];
1481
+ } ngx_mp4_mdhd_atom_t;
1482
+
1483
+ typedef struct {
1484
+ u_char size[4];
1485
+ u_char name[4];
1486
+ u_char version[1];
1487
+ u_char flags[3];
1488
+ u_char creation_time[8];
1489
+ u_char modification_time[8];
1490
+ u_char timescale[4];
1491
+ u_char duration[8];
1492
+ u_char language[2];
1493
+ u_char quality[2];
1494
+ } ngx_mp4_mdhd64_atom_t;
1495
+
1496
+
1497
+ static ngx_int_t
1498
+ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
1499
+ {
1500
+ u_char *atom_header;
1501
+ size_t atom_size;
1502
+ uint32_t timescale;
1503
+ uint64_t duration;
1504
+ ngx_buf_t *atom;
1505
+ ngx_http_mp4_trak_t *trak;
1506
+ ngx_mp4_mdhd_atom_t *mdhd_atom;
1507
+ ngx_mp4_mdhd64_atom_t *mdhd64_atom;
1508
+
1509
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 mdhd atom");
1510
+
1511
+ atom_header = ngx_mp4_atom_header(mp4);
1512
+ mdhd_atom = (ngx_mp4_mdhd_atom_t *) atom_header;
1513
+ mdhd64_atom = (ngx_mp4_mdhd64_atom_t *) atom_header;
1514
+ ngx_mp4_set_atom_name(mdhd_atom, 'm', 'd', 'h', 'd');
1515
+
1516
+ if (ngx_mp4_atom_data_size(ngx_mp4_mdhd_atom_t) > atom_data_size) {
1517
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
1518
+ "\"%s\" mp4 mdhd atom too small", mp4->file.name.data);
1519
+ return NGX_ERROR;
1520
+ }
1521
+
1522
+ if (mdhd_atom->version[0] == 0) {
1523
+ /* version 0: everything is 32-bit */
1524
+ timescale = ngx_mp4_get_32value(mdhd_atom->timescale);
1525
+ duration = ngx_mp4_get_32value(mdhd_atom->duration);
1526
+
1527
+ } else {
1528
+ /* version 1: 64-bit duration and 32-bit timescale */
1529
+
1530
+ if (ngx_mp4_atom_data_size(ngx_mp4_mdhd64_atom_t) > atom_data_size) {
1531
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
1532
+ "\"%s\" mp4 mdhd atom too small",
1533
+ mp4->file.name.data);
1534
+ return NGX_ERROR;
1535
+ }
1536
+
1537
+ timescale = ngx_mp4_get_32value(mdhd64_atom->timescale);
1538
+ duration = ngx_mp4_get_64value(mdhd64_atom->duration);
1539
+ }
1540
+
1541
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
1542
+ "mdhd timescale:%uD, duration:%uL, time:%.3fs",
1543
+ timescale, duration, (double) duration / timescale);
1544
+
1545
+ duration -= (uint64_t) mp4->start * timescale / 1000;
1546
+
1547
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
1548
+ "mdhd new duration:%uL, time:%.3fs",
1549
+ duration, (double) duration / timescale);
1550
+
1551
+ atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size;
1552
+
1553
+ trak = ngx_mp4_last_trak(mp4);
1554
+ trak->mdhd_size = atom_size;
1555
+ trak->timescale = timescale;
1556
+
1557
+ ngx_mp4_set_32value(mdhd_atom->size, atom_size);
1558
+
1559
+ if (mdhd_atom->version[0] == 0) {
1560
+ ngx_mp4_set_32value(mdhd_atom->duration, duration);
1561
+
1562
+ } else {
1563
+ ngx_mp4_set_64value(mdhd64_atom->duration, duration);
1564
+ }
1565
+
1566
+ atom = &trak->mdhd_atom_buf;
1567
+ atom->temporary = 1;
1568
+ atom->pos = atom_header;
1569
+ atom->last = atom_header + atom_size;
1570
+
1571
+ trak->out[NGX_HTTP_MP4_MDHD_ATOM].buf = atom;
1572
+
1573
+ ngx_mp4_atom_next(mp4, atom_data_size);
1574
+
1575
+ return NGX_OK;
1576
+ }
1577
+
1578
+
1579
+ static ngx_int_t
1580
+ ngx_http_mp4_read_hdlr_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
1581
+ {
1582
+ u_char *atom_header;
1583
+ size_t atom_size;
1584
+ ngx_buf_t *atom;
1585
+ ngx_http_mp4_trak_t *trak;
1586
+
1587
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 hdlr atom");
1588
+
1589
+ atom_header = ngx_mp4_atom_header(mp4);
1590
+ atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size;
1591
+ ngx_mp4_set_32value(atom_header, atom_size);
1592
+ ngx_mp4_set_atom_name(atom_header, 'h', 'd', 'l', 'r');
1593
+
1594
+ trak = ngx_mp4_last_trak(mp4);
1595
+
1596
+ atom = &trak->hdlr_atom_buf;
1597
+ atom->temporary = 1;
1598
+ atom->pos = atom_header;
1599
+ atom->last = atom_header + atom_size;
1600
+
1601
+ trak->hdlr_size = atom_size;
1602
+ trak->out[NGX_HTTP_MP4_HDLR_ATOM].buf = atom;
1603
+
1604
+ ngx_mp4_atom_next(mp4, atom_data_size);
1605
+
1606
+ return NGX_OK;
1607
+ }
1608
+
1609
+
1610
+ static ngx_int_t
1611
+ ngx_http_mp4_read_minf_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
1612
+ {
1613
+ u_char *atom_header;
1614
+ ngx_buf_t *atom;
1615
+ ngx_http_mp4_trak_t *trak;
1616
+
1617
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "process minf atom");
1618
+
1619
+ atom_header = ngx_mp4_atom_header(mp4);
1620
+ ngx_mp4_set_atom_name(atom_header, 'm', 'i', 'n', 'f');
1621
+
1622
+ trak = ngx_mp4_last_trak(mp4);
1623
+
1624
+ atom = &trak->minf_atom_buf;
1625
+ atom->temporary = 1;
1626
+ atom->pos = atom_header;
1627
+ atom->last = atom_header + sizeof(ngx_mp4_atom_header_t);
1628
+
1629
+ trak->out[NGX_HTTP_MP4_MINF_ATOM].buf = atom;
1630
+
1631
+ return ngx_http_mp4_read_atom(mp4, ngx_http_mp4_minf_atoms, atom_data_size);
1632
+ }
1633
+
1634
+
1635
+ static void
1636
+ ngx_http_mp4_update_minf_atom(ngx_http_mp4_file_t *mp4,
1637
+ ngx_http_mp4_trak_t *trak)
1638
+ {
1639
+ ngx_buf_t *atom;
1640
+
1641
+ trak->size += sizeof(ngx_mp4_atom_header_t)
1642
+ + trak->vmhd_size
1643
+ + trak->smhd_size
1644
+ + trak->dinf_size;
1645
+ atom = &trak->minf_atom_buf;
1646
+ ngx_mp4_set_32value(atom->pos, trak->size);
1647
+ }
1648
+
1649
+
1650
+ static ngx_int_t
1651
+ ngx_http_mp4_read_vmhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
1652
+ {
1653
+ u_char *atom_header;
1654
+ size_t atom_size;
1655
+ ngx_buf_t *atom;
1656
+ ngx_http_mp4_trak_t *trak;
1657
+
1658
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 vmhd atom");
1659
+
1660
+ atom_header = ngx_mp4_atom_header(mp4);
1661
+ atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size;
1662
+ ngx_mp4_set_32value(atom_header, atom_size);
1663
+ ngx_mp4_set_atom_name(atom_header, 'v', 'm', 'h', 'd');
1664
+
1665
+ trak = ngx_mp4_last_trak(mp4);
1666
+
1667
+ atom = &trak->vmhd_atom_buf;
1668
+ atom->temporary = 1;
1669
+ atom->pos = atom_header;
1670
+ atom->last = atom_header + atom_size;
1671
+
1672
+ trak->vmhd_size += atom_size;
1673
+ trak->out[NGX_HTTP_MP4_VMHD_ATOM].buf = atom;
1674
+
1675
+ ngx_mp4_atom_next(mp4, atom_data_size);
1676
+
1677
+ return NGX_OK;
1678
+ }
1679
+
1680
+
1681
+ static ngx_int_t
1682
+ ngx_http_mp4_read_smhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
1683
+ {
1684
+ u_char *atom_header;
1685
+ size_t atom_size;
1686
+ ngx_buf_t *atom;
1687
+ ngx_http_mp4_trak_t *trak;
1688
+
1689
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 smhd atom");
1690
+
1691
+ atom_header = ngx_mp4_atom_header(mp4);
1692
+ atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size;
1693
+ ngx_mp4_set_32value(atom_header, atom_size);
1694
+ ngx_mp4_set_atom_name(atom_header, 's', 'm', 'h', 'd');
1695
+
1696
+ trak = ngx_mp4_last_trak(mp4);
1697
+
1698
+ atom = &trak->smhd_atom_buf;
1699
+ atom->temporary = 1;
1700
+ atom->pos = atom_header;
1701
+ atom->last = atom_header + atom_size;
1702
+
1703
+ trak->vmhd_size += atom_size;
1704
+ trak->out[NGX_HTTP_MP4_SMHD_ATOM].buf = atom;
1705
+
1706
+ ngx_mp4_atom_next(mp4, atom_data_size);
1707
+
1708
+ return NGX_OK;
1709
+ }
1710
+
1711
+
1712
+ static ngx_int_t
1713
+ ngx_http_mp4_read_dinf_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
1714
+ {
1715
+ u_char *atom_header;
1716
+ size_t atom_size;
1717
+ ngx_buf_t *atom;
1718
+ ngx_http_mp4_trak_t *trak;
1719
+
1720
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 dinf atom");
1721
+
1722
+ atom_header = ngx_mp4_atom_header(mp4);
1723
+ atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size;
1724
+ ngx_mp4_set_32value(atom_header, atom_size);
1725
+ ngx_mp4_set_atom_name(atom_header, 'd', 'i', 'n', 'f');
1726
+
1727
+ trak = ngx_mp4_last_trak(mp4);
1728
+
1729
+ atom = &trak->dinf_atom_buf;
1730
+ atom->temporary = 1;
1731
+ atom->pos = atom_header;
1732
+ atom->last = atom_header + atom_size;
1733
+
1734
+ trak->dinf_size += atom_size;
1735
+ trak->out[NGX_HTTP_MP4_DINF_ATOM].buf = atom;
1736
+
1737
+ ngx_mp4_atom_next(mp4, atom_data_size);
1738
+
1739
+ return NGX_OK;
1740
+ }
1741
+
1742
+
1743
+ static ngx_int_t
1744
+ ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
1745
+ {
1746
+ u_char *atom_header;
1747
+ ngx_buf_t *atom;
1748
+ ngx_http_mp4_trak_t *trak;
1749
+
1750
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "process stbl atom");
1751
+
1752
+ atom_header = ngx_mp4_atom_header(mp4);
1753
+ ngx_mp4_set_atom_name(atom_header, 's', 't', 'b', 'l');
1754
+
1755
+ trak = ngx_mp4_last_trak(mp4);
1756
+
1757
+ atom = &trak->stbl_atom_buf;
1758
+ atom->temporary = 1;
1759
+ atom->pos = atom_header;
1760
+ atom->last = atom_header + sizeof(ngx_mp4_atom_header_t);
1761
+
1762
+ trak->out[NGX_HTTP_MP4_STBL_ATOM].buf = atom;
1763
+
1764
+ return ngx_http_mp4_read_atom(mp4, ngx_http_mp4_stbl_atoms, atom_data_size);
1765
+ }
1766
+
1767
+
1768
+ static void
1769
+ ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4,
1770
+ ngx_http_mp4_trak_t *trak)
1771
+ {
1772
+ ngx_buf_t *atom;
1773
+
1774
+ trak->size += sizeof(ngx_mp4_atom_header_t);
1775
+ atom = &trak->stbl_atom_buf;
1776
+ ngx_mp4_set_32value(atom->pos, trak->size);
1777
+ }
1778
+
1779
+
1780
+ typedef struct {
1781
+ u_char size[4];
1782
+ u_char name[4];
1783
+ u_char version[1];
1784
+ u_char flags[3];
1785
+ u_char entries[4];
1786
+
1787
+ u_char media_size[4];
1788
+ u_char media_name[4];
1789
+ } ngx_mp4_stsd_atom_t;
1790
+
1791
+
1792
+ static ngx_int_t
1793
+ ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
1794
+ {
1795
+ u_char *atom_header, *atom_table;
1796
+ size_t atom_size;
1797
+ ngx_buf_t *atom;
1798
+ ngx_mp4_stsd_atom_t *stsd_atom;
1799
+ ngx_http_mp4_trak_t *trak;
1800
+
1801
+ /* sample description atom */
1802
+
1803
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stsd atom");
1804
+
1805
+ atom_header = ngx_mp4_atom_header(mp4);
1806
+ stsd_atom = (ngx_mp4_stsd_atom_t *) atom_header;
1807
+ atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size;
1808
+ atom_table = atom_header + atom_size;
1809
+ ngx_mp4_set_32value(stsd_atom->size, atom_size);
1810
+ ngx_mp4_set_atom_name(stsd_atom, 's', 't', 's', 'd');
1811
+
1812
+ if (ngx_mp4_atom_data_size(ngx_mp4_stsd_atom_t) > atom_data_size) {
1813
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
1814
+ "\"%s\" mp4 stsd atom too small", mp4->file.name.data);
1815
+ return NGX_ERROR;
1816
+ }
1817
+
1818
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
1819
+ "stsd entries:%uD, media:%*s",
1820
+ ngx_mp4_get_32value(stsd_atom->entries),
1821
+ 4, stsd_atom->media_name);
1822
+
1823
+ /* supported media format: "avc1" (H.264) and "mp4a" (MPEG-4/AAC) */
1824
+
1825
+ if (ngx_strncmp(stsd_atom->media_name, "avc1", 4) != 0
1826
+ && ngx_strncmp(stsd_atom->media_name, "mp4a", 4) != 0)
1827
+ {
1828
+ return NGX_DECLINED;
1829
+ }
1830
+
1831
+ trak = ngx_mp4_last_trak(mp4);
1832
+
1833
+ atom = &trak->stsd_atom_buf;
1834
+ atom->temporary = 1;
1835
+ atom->pos = atom_header;
1836
+ atom->last = atom_table;
1837
+
1838
+ trak->out[NGX_HTTP_MP4_STSD_ATOM].buf = atom;
1839
+ trak->size += atom_size;
1840
+
1841
+ ngx_mp4_atom_next(mp4, atom_data_size);
1842
+
1843
+ return NGX_OK;
1844
+ }
1845
+
1846
+
1847
+ typedef struct {
1848
+ u_char size[4];
1849
+ u_char name[4];
1850
+ u_char version[1];
1851
+ u_char flags[3];
1852
+ u_char entries[4];
1853
+ } ngx_mp4_stts_atom_t;
1854
+
1855
+ typedef struct {
1856
+ u_char count[4];
1857
+ u_char duration[4];
1858
+ } ngx_mp4_stts_entry_t;
1859
+
1860
+
1861
+ static ngx_int_t
1862
+ ngx_http_mp4_read_stts_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
1863
+ {
1864
+ u_char *atom_header, *atom_table, *atom_end;
1865
+ uint32_t entries;
1866
+ ngx_buf_t *atom, *data;
1867
+ ngx_mp4_stts_atom_t *stts_atom;
1868
+ ngx_http_mp4_trak_t *trak;
1869
+
1870
+ /* time-to-sample atom */
1871
+
1872
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stts atom");
1873
+
1874
+ atom_header = ngx_mp4_atom_header(mp4);
1875
+ stts_atom = (ngx_mp4_stts_atom_t *) atom_header;
1876
+ ngx_mp4_set_atom_name(stts_atom, 's', 't', 't', 's');
1877
+
1878
+ if (ngx_mp4_atom_data_size(ngx_mp4_stts_atom_t) > atom_data_size) {
1879
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
1880
+ "\"%s\" mp4 stts atom too small", mp4->file.name.data);
1881
+ return NGX_ERROR;
1882
+ }
1883
+
1884
+ entries = ngx_mp4_get_32value(stts_atom->entries);
1885
+
1886
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
1887
+ "mp4 time-to-sample entries:%uD", entries);
1888
+
1889
+ if (ngx_mp4_atom_data_size(ngx_mp4_stts_atom_t)
1890
+ + entries * sizeof(ngx_mp4_stts_entry_t) > atom_data_size)
1891
+ {
1892
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
1893
+ "\"%s\" mp4 stts atom too small", mp4->file.name.data);
1894
+ return NGX_ERROR;
1895
+ }
1896
+
1897
+ atom_table = atom_header + sizeof(ngx_mp4_stts_atom_t);
1898
+ atom_end = atom_table + entries * sizeof(ngx_mp4_stts_entry_t);
1899
+
1900
+ trak = ngx_mp4_last_trak(mp4);
1901
+ trak->time_to_sample_entries = entries;
1902
+
1903
+ atom = &trak->stts_atom_buf;
1904
+ atom->temporary = 1;
1905
+ atom->pos = atom_header;
1906
+ atom->last = atom_table;
1907
+
1908
+ data = &trak->stts_data_buf;
1909
+ data->temporary = 1;
1910
+ data->pos = atom_table;
1911
+ data->last = atom_end;
1912
+
1913
+ trak->out[NGX_HTTP_MP4_STTS_ATOM].buf = atom;
1914
+ trak->out[NGX_HTTP_MP4_STTS_DATA].buf = data;
1915
+
1916
+ ngx_mp4_atom_next(mp4, atom_data_size);
1917
+
1918
+ return NGX_OK;
1919
+ }
1920
+
1921
+
1922
+ static ngx_int_t
1923
+ ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4,
1924
+ ngx_http_mp4_trak_t *trak)
1925
+ {
1926
+ size_t atom_size;
1927
+ uint32_t entries, count, duration;
1928
+ uint64_t start_time;
1929
+ ngx_buf_t *atom, *data;
1930
+ ngx_uint_t start_sample;
1931
+ ngx_mp4_stts_atom_t *stts_atom;
1932
+ ngx_mp4_stts_entry_t *entry, *end;
1933
+
1934
+ /*
1935
+ * mdia.minf.stbl.stts updating requires trak->timescale
1936
+ * from mdia.mdhd atom which may reside after mdia.minf
1937
+ */
1938
+
1939
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
1940
+ "mp4 stts atom update");
1941
+
1942
+ data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf;
1943
+
1944
+ if (data == NULL) {
1945
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
1946
+ "no mp4 stts atoms were found in \"%s\"",
1947
+ mp4->file.name.data);
1948
+ return NGX_ERROR;
1949
+ }
1950
+
1951
+ entries = trak->time_to_sample_entries;
1952
+ start_time = (uint64_t) mp4->start * trak->timescale / 1000;
1953
+
1954
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
1955
+ "time-to-sample start_time:%uL", start_time);
1956
+
1957
+ start_sample = 0;
1958
+ entry = (ngx_mp4_stts_entry_t *) data->pos;
1959
+ end = (ngx_mp4_stts_entry_t *) data->last;
1960
+
1961
+ while (entry < end) {
1962
+ count = ngx_mp4_get_32value(entry->count);
1963
+ duration = ngx_mp4_get_32value(entry->duration);
1964
+
1965
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
1966
+ "count:%uD, duration:%uD", count, duration);
1967
+
1968
+ if (start_time < (uint64_t) count * duration) {
1969
+ start_sample += (ngx_uint_t) (start_time / duration);
1970
+ count -= (uint32_t) (start_time / duration);
1971
+ ngx_mp4_set_32value(entry->count, count);
1972
+ goto found;
1973
+ }
1974
+
1975
+ start_sample += count;
1976
+ start_time -= count * duration;
1977
+ entries--;
1978
+ entry++;
1979
+ }
1980
+
1981
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
1982
+ "start time is out mp4 stts samples in \"%s\"",
1983
+ mp4->file.name.data);
1984
+
1985
+ return NGX_ERROR;
1986
+
1987
+ found:
1988
+
1989
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
1990
+ "start_sample:%ui, new count:%uD", start_sample, count);
1991
+
1992
+ trak->start_sample = start_sample;
1993
+
1994
+ data->pos = (u_char *) entry;
1995
+ atom_size = sizeof(ngx_mp4_stts_atom_t) + (data->last - data->pos);
1996
+ trak->size += atom_size;
1997
+
1998
+ atom = trak->out[NGX_HTTP_MP4_STTS_ATOM].buf;
1999
+ stts_atom = (ngx_mp4_stts_atom_t *) atom->pos;
2000
+ ngx_mp4_set_32value(stts_atom->size, atom_size);
2001
+ ngx_mp4_set_32value(stts_atom->entries, entries);
2002
+
2003
+ return NGX_OK;
2004
+ }
2005
+
2006
+
2007
+ typedef struct {
2008
+ u_char size[4];
2009
+ u_char name[4];
2010
+ u_char version[1];
2011
+ u_char flags[3];
2012
+ u_char entries[4];
2013
+ } ngx_http_mp4_stss_atom_t;
2014
+
2015
+
2016
+ static ngx_int_t
2017
+ ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
2018
+ {
2019
+ u_char *atom_header, *atom_table, *atom_end;
2020
+ uint32_t entries;
2021
+ ngx_buf_t *atom, *data;
2022
+ ngx_http_mp4_trak_t *trak;
2023
+ ngx_http_mp4_stss_atom_t *stss_atom;
2024
+
2025
+ /* sync samples atom */
2026
+
2027
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stss atom");
2028
+
2029
+ atom_header = ngx_mp4_atom_header(mp4);
2030
+ stss_atom = (ngx_http_mp4_stss_atom_t *) atom_header;
2031
+ ngx_mp4_set_atom_name(stss_atom, 's', 't', 's', 's');
2032
+
2033
+ if (ngx_mp4_atom_data_size(ngx_http_mp4_stss_atom_t) > atom_data_size) {
2034
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2035
+ "\"%s\" mp4 stss atom too small", mp4->file.name.data);
2036
+ return NGX_ERROR;
2037
+ }
2038
+
2039
+ entries = ngx_mp4_get_32value(stss_atom->entries);
2040
+
2041
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2042
+ "sync sample entries:%uD", entries);
2043
+
2044
+ trak = ngx_mp4_last_trak(mp4);
2045
+ trak->sync_samples_entries = entries;
2046
+
2047
+ atom_table = atom_header + sizeof(ngx_http_mp4_stss_atom_t);
2048
+
2049
+ atom = &trak->stss_atom_buf;
2050
+ atom->temporary = 1;
2051
+ atom->pos = atom_header;
2052
+ atom->last = atom_table;
2053
+
2054
+ if (ngx_mp4_atom_data_size(ngx_http_mp4_stss_atom_t)
2055
+ + entries * sizeof(uint32_t) > atom_data_size)
2056
+ {
2057
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2058
+ "\"%s\" mp4 stss atom too small", mp4->file.name.data);
2059
+ return NGX_ERROR;
2060
+ }
2061
+
2062
+ atom_end = atom_table + entries * sizeof(uint32_t);
2063
+
2064
+ data = &trak->stss_data_buf;
2065
+ data->temporary = 1;
2066
+ data->pos = atom_table;
2067
+ data->last = atom_end;
2068
+
2069
+ trak->out[NGX_HTTP_MP4_STSS_ATOM].buf = atom;
2070
+ trak->out[NGX_HTTP_MP4_STSS_DATA].buf = data;
2071
+
2072
+ ngx_mp4_atom_next(mp4, atom_data_size);
2073
+
2074
+ return NGX_OK;
2075
+ }
2076
+
2077
+
2078
+ static ngx_int_t
2079
+ ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4,
2080
+ ngx_http_mp4_trak_t *trak)
2081
+ {
2082
+ size_t atom_size;
2083
+ uint32_t entries, sample, start_sample, *entry, *end;
2084
+ ngx_buf_t *atom, *data;
2085
+ ngx_http_mp4_stss_atom_t *stss_atom;
2086
+
2087
+ /*
2088
+ * mdia.minf.stbl.stss updating requires trak->start_sample
2089
+ * from mdia.minf.stbl.stts which depends on value from mdia.mdhd
2090
+ * atom which may reside after mdia.minf
2091
+ */
2092
+
2093
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2094
+ "mp4 stss atom update");
2095
+
2096
+ data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf;
2097
+
2098
+ if (data == NULL) {
2099
+ return NGX_OK;
2100
+ }
2101
+
2102
+ /* sync samples starts from 1 */
2103
+ start_sample = trak->start_sample + 1;
2104
+ entries = trak->sync_samples_entries;
2105
+
2106
+ entry = (uint32_t *) data->pos;
2107
+ end = (uint32_t *) data->last;
2108
+
2109
+ while (entry < end) {
2110
+ sample = ngx_mp4_get_32value(entry);
2111
+
2112
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2113
+ "start:%uD, sync:%uD", start_sample, sample);
2114
+
2115
+ if (sample >= start_sample) {
2116
+ goto found;
2117
+ }
2118
+
2119
+ entries--;
2120
+ entry++;
2121
+ }
2122
+
2123
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2124
+ "start sample is out of mp4 stss atom in \"%s\"",
2125
+ mp4->file.name.data);
2126
+
2127
+ return NGX_ERROR;
2128
+
2129
+ found:
2130
+
2131
+ data->pos = (u_char *) entry;
2132
+
2133
+ start_sample = trak->start_sample;
2134
+
2135
+ while (entry < end) {
2136
+ sample = ngx_mp4_get_32value(entry);
2137
+ sample -= start_sample;
2138
+ ngx_mp4_set_32value(entry, sample);
2139
+ entry++;
2140
+ }
2141
+
2142
+ atom_size = sizeof(ngx_http_mp4_stss_atom_t) + (data->last - data->pos);
2143
+ trak->size += atom_size;
2144
+
2145
+ atom = trak->out[NGX_HTTP_MP4_STSS_ATOM].buf;
2146
+ stss_atom = (ngx_http_mp4_stss_atom_t *) atom->pos;
2147
+
2148
+ ngx_mp4_set_32value(stss_atom->size, atom_size);
2149
+ ngx_mp4_set_32value(stss_atom->entries, entries);
2150
+
2151
+ return NGX_OK;
2152
+ }
2153
+
2154
+
2155
+ typedef struct {
2156
+ u_char size[4];
2157
+ u_char name[4];
2158
+ u_char version[1];
2159
+ u_char flags[3];
2160
+ u_char entries[4];
2161
+ } ngx_mp4_ctts_atom_t;
2162
+
2163
+ typedef struct {
2164
+ u_char count[4];
2165
+ u_char offset[4];
2166
+ } ngx_mp4_ctts_entry_t;
2167
+
2168
+
2169
+ static ngx_int_t
2170
+ ngx_http_mp4_read_ctts_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
2171
+ {
2172
+ u_char *atom_header, *atom_table, *atom_end;
2173
+ uint32_t entries;
2174
+ ngx_buf_t *atom, *data;
2175
+ ngx_mp4_ctts_atom_t *ctts_atom;
2176
+ ngx_http_mp4_trak_t *trak;
2177
+
2178
+ /* composition offsets atom */
2179
+
2180
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 ctts atom");
2181
+
2182
+ atom_header = ngx_mp4_atom_header(mp4);
2183
+ ctts_atom = (ngx_mp4_ctts_atom_t *) atom_header;
2184
+ ngx_mp4_set_atom_name(ctts_atom, 'c', 't', 't', 's');
2185
+
2186
+ if (ngx_mp4_atom_data_size(ngx_mp4_ctts_atom_t) > atom_data_size) {
2187
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2188
+ "\"%s\" mp4 ctts atom too small", mp4->file.name.data);
2189
+ return NGX_ERROR;
2190
+ }
2191
+
2192
+ entries = ngx_mp4_get_32value(ctts_atom->entries);
2193
+
2194
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2195
+ "composition offset entries:%uD", entries);
2196
+
2197
+ trak = ngx_mp4_last_trak(mp4);
2198
+ trak->composition_offset_entries = entries;
2199
+
2200
+ atom_table = atom_header + sizeof(ngx_mp4_ctts_atom_t);
2201
+
2202
+ atom = &trak->ctts_atom_buf;
2203
+ atom->temporary = 1;
2204
+ atom->pos = atom_header;
2205
+ atom->last = atom_table;
2206
+
2207
+ if (ngx_mp4_atom_data_size(ngx_mp4_ctts_atom_t)
2208
+ + entries * sizeof(ngx_mp4_ctts_entry_t) > atom_data_size)
2209
+ {
2210
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2211
+ "\"%s\" mp4 ctts atom too small", mp4->file.name.data);
2212
+ return NGX_ERROR;
2213
+ }
2214
+
2215
+ atom_end = atom_table + entries * sizeof(ngx_mp4_ctts_entry_t);
2216
+
2217
+ data = &trak->ctts_data_buf;
2218
+ data->temporary = 1;
2219
+ data->pos = atom_table;
2220
+ data->last = atom_end;
2221
+
2222
+ trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = atom;
2223
+ trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = data;
2224
+
2225
+ ngx_mp4_atom_next(mp4, atom_data_size);
2226
+
2227
+ return NGX_OK;
2228
+ }
2229
+
2230
+
2231
+ static void
2232
+ ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4,
2233
+ ngx_http_mp4_trak_t *trak)
2234
+ {
2235
+ size_t atom_size;
2236
+ uint32_t entries, count, start_sample;
2237
+ ngx_buf_t *atom, *data;
2238
+ ngx_mp4_ctts_atom_t *ctts_atom;
2239
+ ngx_mp4_ctts_entry_t *entry, *end;
2240
+
2241
+ /*
2242
+ * mdia.minf.stbl.ctts updating requires trak->start_sample
2243
+ * from mdia.minf.stbl.stts which depends on value from mdia.mdhd
2244
+ * atom which may reside after mdia.minf
2245
+ */
2246
+
2247
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2248
+ "mp4 ctts atom update");
2249
+
2250
+ data = trak->out[NGX_HTTP_MP4_CTTS_DATA].buf;
2251
+
2252
+ if (data == NULL) {
2253
+ return;
2254
+ }
2255
+
2256
+ /* sync samples starts from 1 */
2257
+ start_sample = trak->start_sample + 1;
2258
+ entries = trak->composition_offset_entries;
2259
+ entry = (ngx_mp4_ctts_entry_t *) data->pos;
2260
+ end = (ngx_mp4_ctts_entry_t *) data->last;
2261
+
2262
+ while (entry < end) {
2263
+ count = ngx_mp4_get_32value(entry->count);
2264
+
2265
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2266
+ "start:%uD, count:%uD, offset:%uD",
2267
+ start_sample, count, ngx_mp4_get_32value(entry->offset));
2268
+
2269
+ if (start_sample <= count) {
2270
+ count -= (start_sample - 1);
2271
+ ngx_mp4_set_32value(entry->count, count);
2272
+ goto found;
2273
+ }
2274
+
2275
+ start_sample -= count;
2276
+ entries--;
2277
+ entry++;
2278
+ }
2279
+
2280
+ trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = NULL;
2281
+ trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = NULL;
2282
+
2283
+ return;
2284
+
2285
+ found:
2286
+
2287
+ data->pos = (u_char *) entry;
2288
+ atom_size = sizeof(ngx_mp4_ctts_atom_t) + (data->last - data->pos);
2289
+ trak->size += atom_size;
2290
+
2291
+ atom = trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf;
2292
+ ctts_atom = (ngx_mp4_ctts_atom_t *) atom->pos;
2293
+
2294
+ ngx_mp4_set_32value(ctts_atom->size, atom_size);
2295
+ ngx_mp4_set_32value(ctts_atom->entries, entries);
2296
+
2297
+ return;
2298
+ }
2299
+
2300
+
2301
+ typedef struct {
2302
+ u_char size[4];
2303
+ u_char name[4];
2304
+ u_char version[1];
2305
+ u_char flags[3];
2306
+ u_char entries[4];
2307
+ } ngx_mp4_stsc_atom_t;
2308
+
2309
+
2310
+ static ngx_int_t
2311
+ ngx_http_mp4_read_stsc_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
2312
+ {
2313
+ u_char *atom_header, *atom_table, *atom_end;
2314
+ uint32_t entries;
2315
+ ngx_buf_t *atom, *data;
2316
+ ngx_mp4_stsc_atom_t *stsc_atom;
2317
+ ngx_http_mp4_trak_t *trak;
2318
+
2319
+ /* sample-to-chunk atom */
2320
+
2321
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stsc atom");
2322
+
2323
+ atom_header = ngx_mp4_atom_header(mp4);
2324
+ stsc_atom = (ngx_mp4_stsc_atom_t *) atom_header;
2325
+ ngx_mp4_set_atom_name(stsc_atom, 's', 't', 's', 'c');
2326
+
2327
+ if (ngx_mp4_atom_data_size(ngx_mp4_stsc_atom_t) > atom_data_size) {
2328
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2329
+ "\"%s\" mp4 stsc atom too small", mp4->file.name.data);
2330
+ return NGX_ERROR;
2331
+ }
2332
+
2333
+ entries = ngx_mp4_get_32value(stsc_atom->entries);
2334
+
2335
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2336
+ "sample-to-chunk entries:%uD", entries);
2337
+
2338
+ if (ngx_mp4_atom_data_size(ngx_mp4_stsc_atom_t)
2339
+ + entries * sizeof(ngx_mp4_stsc_entry_t) > atom_data_size)
2340
+ {
2341
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2342
+ "\"%s\" mp4 stsc atom too small", mp4->file.name.data);
2343
+ return NGX_ERROR;
2344
+ }
2345
+
2346
+ atom_table = atom_header + sizeof(ngx_mp4_stsc_atom_t);
2347
+ atom_end = atom_table + entries * sizeof(ngx_mp4_stsc_entry_t);
2348
+
2349
+ trak = ngx_mp4_last_trak(mp4);
2350
+ trak->sample_to_chunk_entries = entries;
2351
+
2352
+ atom = &trak->stsc_atom_buf;
2353
+ atom->temporary = 1;
2354
+ atom->pos = atom_header;
2355
+ atom->last = atom_table;
2356
+
2357
+ data = &trak->stsc_data_buf;
2358
+ data->temporary = 1;
2359
+ data->pos = atom_table;
2360
+ data->last = atom_end;
2361
+
2362
+ trak->out[NGX_HTTP_MP4_STSC_ATOM].buf = atom;
2363
+ trak->out[NGX_HTTP_MP4_STSC_DATA].buf = data;
2364
+
2365
+ ngx_mp4_atom_next(mp4, atom_data_size);
2366
+
2367
+ return NGX_OK;
2368
+ }
2369
+
2370
+
2371
+ static ngx_int_t
2372
+ ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4,
2373
+ ngx_http_mp4_trak_t *trak)
2374
+ {
2375
+ size_t atom_size;
2376
+ uint32_t start_sample, entries, chunk, samples, id,
2377
+ next_chunk, n;
2378
+ ngx_buf_t *atom, *data, *buf;
2379
+ ngx_mp4_stsc_atom_t *stsc_atom;
2380
+ ngx_mp4_stsc_entry_t *entry, *first, *end;
2381
+
2382
+ /*
2383
+ * mdia.minf.stbl.stsc updating requires trak->start_sample
2384
+ * from mdia.minf.stbl.stts which depends on value from mdia.mdhd
2385
+ * atom which may reside after mdia.minf
2386
+ */
2387
+
2388
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2389
+ "mp4 stsc atom update");
2390
+
2391
+ data = trak->out[NGX_HTTP_MP4_STSC_DATA].buf;
2392
+
2393
+ if (data == NULL) {
2394
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2395
+ "no mp4 stsc atoms were found in \"%s\"",
2396
+ mp4->file.name.data);
2397
+ return NGX_ERROR;
2398
+ }
2399
+
2400
+ if (trak->sample_to_chunk_entries == 0) {
2401
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2402
+ "zero number of entries in stsc atom in \"%s\"",
2403
+ mp4->file.name.data);
2404
+ return NGX_ERROR;
2405
+ }
2406
+
2407
+ start_sample = (uint32_t) trak->start_sample;
2408
+ entries = trak->sample_to_chunk_entries - 1;
2409
+
2410
+ entry = (ngx_mp4_stsc_entry_t *) data->pos;
2411
+ end = (ngx_mp4_stsc_entry_t *) data->last;
2412
+
2413
+ chunk = ngx_mp4_get_32value(entry->chunk);
2414
+ samples = ngx_mp4_get_32value(entry->samples);
2415
+ id = ngx_mp4_get_32value(entry->id);
2416
+ entry++;
2417
+
2418
+ while (entry < end) {
2419
+
2420
+ next_chunk = ngx_mp4_get_32value(entry->chunk);
2421
+
2422
+ ngx_log_debug5(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2423
+ "start_sample:%uD, chunk:%uD, chunks:%uD, "
2424
+ "samples:%uD, id:%uD",
2425
+ start_sample, chunk, next_chunk - chunk, samples, id);
2426
+
2427
+ n = (next_chunk - chunk) * samples;
2428
+
2429
+ if (start_sample <= n) {
2430
+ goto found;
2431
+ }
2432
+
2433
+ start_sample -= n;
2434
+
2435
+ chunk = next_chunk;
2436
+ samples = ngx_mp4_get_32value(entry->samples);
2437
+ id = ngx_mp4_get_32value(entry->id);
2438
+ entries--;
2439
+ entry++;
2440
+ }
2441
+
2442
+ next_chunk = trak->chunks;
2443
+
2444
+ ngx_log_debug4(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2445
+ "start_sample:%uD, chunk:%uD, chunks:%uD, samples:%uD",
2446
+ start_sample, chunk, next_chunk - chunk, samples);
2447
+
2448
+ n = (next_chunk - chunk) * samples;
2449
+
2450
+ if (start_sample > n) {
2451
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2452
+ "start time is out mp4 stsc chunks in \"%s\"",
2453
+ mp4->file.name.data);
2454
+ return NGX_ERROR;
2455
+ }
2456
+
2457
+ found:
2458
+
2459
+ entries++;
2460
+ entry--;
2461
+
2462
+ if (samples == 0) {
2463
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2464
+ "zero number of samples in \"%s\"",
2465
+ mp4->file.name.data);
2466
+ return NGX_ERROR;
2467
+ }
2468
+
2469
+ trak->start_chunk = chunk - 1;
2470
+
2471
+ trak->start_chunk += start_sample / samples;
2472
+ trak->chunk_samples = start_sample % samples;
2473
+
2474
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2475
+ "start chunk:%ui, samples:%uD",
2476
+ trak->start_chunk, trak->chunk_samples);
2477
+
2478
+ data->pos = (u_char *) entry;
2479
+ atom_size = sizeof(ngx_mp4_stsc_atom_t) + (data->last - data->pos);
2480
+
2481
+ ngx_mp4_set_32value(entry->chunk, 1);
2482
+
2483
+ if (trak->chunk_samples) {
2484
+
2485
+ first = &trak->stsc_chunk_entry;
2486
+ ngx_mp4_set_32value(first->chunk, 1);
2487
+ ngx_mp4_set_32value(first->samples, samples - trak->chunk_samples);
2488
+ ngx_mp4_set_32value(first->id, id);
2489
+
2490
+ buf = &trak->stsc_chunk_buf;
2491
+ buf->temporary = 1;
2492
+ buf->pos = (u_char *) first;
2493
+ buf->last = (u_char *) first + sizeof(ngx_mp4_stsc_entry_t);
2494
+
2495
+ trak->out[NGX_HTTP_MP4_STSC_CHUNK].buf = buf;
2496
+
2497
+ ngx_mp4_set_32value(entry->chunk, 2);
2498
+
2499
+ atom_size += sizeof(ngx_mp4_stsc_entry_t);
2500
+ }
2501
+
2502
+ while (++entry < end) {
2503
+ chunk = ngx_mp4_get_32value(entry->chunk);
2504
+ chunk -= trak->start_chunk;
2505
+ ngx_mp4_set_32value(entry->chunk, chunk);
2506
+ }
2507
+
2508
+ trak->size += atom_size;
2509
+
2510
+ atom = trak->out[NGX_HTTP_MP4_STSC_ATOM].buf;
2511
+ stsc_atom = (ngx_mp4_stsc_atom_t *) atom->pos;
2512
+
2513
+ ngx_mp4_set_32value(stsc_atom->size, atom_size);
2514
+ ngx_mp4_set_32value(stsc_atom->entries, entries);
2515
+
2516
+ return NGX_OK;
2517
+ }
2518
+
2519
+
2520
+ typedef struct {
2521
+ u_char size[4];
2522
+ u_char name[4];
2523
+ u_char version[1];
2524
+ u_char flags[3];
2525
+ u_char uniform_size[4];
2526
+ u_char entries[4];
2527
+ } ngx_mp4_stsz_atom_t;
2528
+
2529
+
2530
+ static ngx_int_t
2531
+ ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
2532
+ {
2533
+ u_char *atom_header, *atom_table, *atom_end;
2534
+ size_t atom_size;
2535
+ uint32_t entries, size;
2536
+ ngx_buf_t *atom, *data;
2537
+ ngx_mp4_stsz_atom_t *stsz_atom;
2538
+ ngx_http_mp4_trak_t *trak;
2539
+
2540
+ /* sample sizes atom */
2541
+
2542
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stsz atom");
2543
+
2544
+ atom_header = ngx_mp4_atom_header(mp4);
2545
+ stsz_atom = (ngx_mp4_stsz_atom_t *) atom_header;
2546
+ ngx_mp4_set_atom_name(stsz_atom, 's', 't', 's', 'z');
2547
+
2548
+ if (ngx_mp4_atom_data_size(ngx_mp4_stsz_atom_t) > atom_data_size) {
2549
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2550
+ "\"%s\" mp4 stsz atom too small", mp4->file.name.data);
2551
+ return NGX_ERROR;
2552
+ }
2553
+
2554
+ size = ngx_mp4_get_32value(stsz_atom->uniform_size);
2555
+ entries = ngx_mp4_get_32value(stsz_atom->entries);
2556
+
2557
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2558
+ "sample uniform size:%uD, entries:%uD", size, entries);
2559
+
2560
+ trak = ngx_mp4_last_trak(mp4);
2561
+ trak->sample_sizes_entries = entries;
2562
+
2563
+ atom_table = atom_header + sizeof(ngx_mp4_stsz_atom_t);
2564
+
2565
+ atom = &trak->stsz_atom_buf;
2566
+ atom->temporary = 1;
2567
+ atom->pos = atom_header;
2568
+ atom->last = atom_table;
2569
+
2570
+ trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf = atom;
2571
+
2572
+ if (size == 0) {
2573
+ if (ngx_mp4_atom_data_size(ngx_mp4_stsz_atom_t)
2574
+ + entries * sizeof(uint32_t) > atom_data_size)
2575
+ {
2576
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2577
+ "\"%s\" mp4 stsz atom too small",
2578
+ mp4->file.name.data);
2579
+ return NGX_ERROR;
2580
+ }
2581
+
2582
+ atom_end = atom_table + entries * sizeof(uint32_t);
2583
+
2584
+ data = &trak->stsz_data_buf;
2585
+ data->temporary = 1;
2586
+ data->pos = atom_table;
2587
+ data->last = atom_end;
2588
+
2589
+ trak->out[NGX_HTTP_MP4_STSZ_DATA].buf = data;
2590
+
2591
+ } else {
2592
+ /* if size != 0 then all samples are the same size */
2593
+ /* TODO : chunk samples */
2594
+ atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size;
2595
+ ngx_mp4_set_32value(atom_header, atom_size);
2596
+ trak->size += atom_size;
2597
+ }
2598
+
2599
+ ngx_mp4_atom_next(mp4, atom_data_size);
2600
+
2601
+ return NGX_OK;
2602
+ }
2603
+
2604
+
2605
+ static ngx_int_t
2606
+ ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4,
2607
+ ngx_http_mp4_trak_t *trak)
2608
+ {
2609
+ size_t atom_size;
2610
+ uint32_t *pos, *end;
2611
+ ngx_buf_t *atom, *data;
2612
+ ngx_mp4_stsz_atom_t *stsz_atom;
2613
+
2614
+ /*
2615
+ * mdia.minf.stbl.stsz updating requires trak->start_sample
2616
+ * from mdia.minf.stbl.stts which depends on value from mdia.mdhd
2617
+ * atom which may reside after mdia.minf
2618
+ */
2619
+
2620
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2621
+ "mp4 stsz atom update");
2622
+
2623
+ data = trak->out[NGX_HTTP_MP4_STSZ_DATA].buf;
2624
+
2625
+ if (data) {
2626
+ if (trak->start_sample > trak->sample_sizes_entries) {
2627
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2628
+ "start time is out mp4 stsz samples in \"%s\"",
2629
+ mp4->file.name.data);
2630
+ return NGX_ERROR;
2631
+ }
2632
+
2633
+ data->pos += trak->start_sample * sizeof(uint32_t);
2634
+ end = (uint32_t *) data->pos;
2635
+
2636
+ for (pos = end - trak->chunk_samples; pos < end; pos++) {
2637
+ trak->chunk_samples_size += ngx_mp4_get_32value(pos);
2638
+ }
2639
+
2640
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2641
+ "chunk samples sizes:%uL", trak->chunk_samples_size);
2642
+
2643
+ atom_size = sizeof(ngx_mp4_stsz_atom_t) + (data->last - data->pos);
2644
+ trak->size += atom_size;
2645
+
2646
+ atom = trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf;
2647
+ stsz_atom = (ngx_mp4_stsz_atom_t *) atom->pos;
2648
+
2649
+ ngx_mp4_set_32value(stsz_atom->size, atom_size);
2650
+ ngx_mp4_set_32value(stsz_atom->entries,
2651
+ trak->sample_sizes_entries - trak->start_sample);
2652
+ }
2653
+
2654
+ return NGX_OK;
2655
+ }
2656
+
2657
+
2658
+ typedef struct {
2659
+ u_char size[4];
2660
+ u_char name[4];
2661
+ u_char version[1];
2662
+ u_char flags[3];
2663
+ u_char entries[4];
2664
+ } ngx_mp4_stco_atom_t;
2665
+
2666
+
2667
+ static ngx_int_t
2668
+ ngx_http_mp4_read_stco_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
2669
+ {
2670
+ u_char *atom_header, *atom_table, *atom_end;
2671
+ uint32_t entries;
2672
+ ngx_buf_t *atom, *data;
2673
+ ngx_mp4_stco_atom_t *stco_atom;
2674
+ ngx_http_mp4_trak_t *trak;
2675
+
2676
+ /* chunk offsets atom */
2677
+
2678
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stco atom");
2679
+
2680
+ atom_header = ngx_mp4_atom_header(mp4);
2681
+ stco_atom = (ngx_mp4_stco_atom_t *) atom_header;
2682
+ ngx_mp4_set_atom_name(stco_atom, 's', 't', 'c', 'o');
2683
+
2684
+ if (ngx_mp4_atom_data_size(ngx_mp4_stco_atom_t) > atom_data_size) {
2685
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2686
+ "\"%s\" mp4 stco atom too small", mp4->file.name.data);
2687
+ return NGX_ERROR;
2688
+ }
2689
+
2690
+ entries = ngx_mp4_get_32value(stco_atom->entries);
2691
+
2692
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries);
2693
+
2694
+ if (ngx_mp4_atom_data_size(ngx_mp4_stco_atom_t)
2695
+ + entries * sizeof(uint32_t) > atom_data_size)
2696
+ {
2697
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2698
+ "\"%s\" mp4 stco atom too small", mp4->file.name.data);
2699
+ return NGX_ERROR;
2700
+ }
2701
+
2702
+ atom_table = atom_header + sizeof(ngx_mp4_stco_atom_t);
2703
+ atom_end = atom_table + entries * sizeof(uint32_t);
2704
+
2705
+ trak = ngx_mp4_last_trak(mp4);
2706
+ trak->chunks = entries;
2707
+
2708
+ atom = &trak->stco_atom_buf;
2709
+ atom->temporary = 1;
2710
+ atom->pos = atom_header;
2711
+ atom->last = atom_table;
2712
+
2713
+ data = &trak->stco_data_buf;
2714
+ data->temporary = 1;
2715
+ data->pos = atom_table;
2716
+ data->last = atom_end;
2717
+
2718
+ trak->out[NGX_HTTP_MP4_STCO_ATOM].buf = atom;
2719
+ trak->out[NGX_HTTP_MP4_STCO_DATA].buf = data;
2720
+
2721
+ ngx_mp4_atom_next(mp4, atom_data_size);
2722
+
2723
+ return NGX_OK;
2724
+ }
2725
+
2726
+
2727
+ static ngx_int_t
2728
+ ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4,
2729
+ ngx_http_mp4_trak_t *trak)
2730
+ {
2731
+ size_t atom_size;
2732
+ ngx_buf_t *atom, *data;
2733
+ ngx_mp4_stco_atom_t *stco_atom;
2734
+
2735
+ /*
2736
+ * mdia.minf.stbl.stco updating requires trak->start_chunk
2737
+ * from mdia.minf.stbl.stsc which depends on value from mdia.mdhd
2738
+ * atom which may reside after mdia.minf
2739
+ */
2740
+
2741
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2742
+ "mp4 stco atom update");
2743
+
2744
+ data = trak->out[NGX_HTTP_MP4_STCO_DATA].buf;
2745
+
2746
+ if (data == NULL) {
2747
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2748
+ "no mp4 stco atoms were found in \"%s\"",
2749
+ mp4->file.name.data);
2750
+ return NGX_ERROR;
2751
+ }
2752
+
2753
+ if (trak->start_chunk > trak->chunks) {
2754
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2755
+ "start time is out mp4 stco chunks in \"%s\"",
2756
+ mp4->file.name.data);
2757
+ return NGX_ERROR;
2758
+ }
2759
+
2760
+ data->pos += trak->start_chunk * sizeof(uint32_t);
2761
+ atom_size = sizeof(ngx_mp4_stco_atom_t) + (data->last - data->pos);
2762
+ trak->size += atom_size;
2763
+
2764
+ trak->start_offset = ngx_mp4_get_32value(data->pos);
2765
+ trak->start_offset += trak->chunk_samples_size;
2766
+ ngx_mp4_set_32value(data->pos, trak->start_offset);
2767
+
2768
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2769
+ "start chunk offset:%uD", trak->start_offset);
2770
+
2771
+ atom = trak->out[NGX_HTTP_MP4_STCO_ATOM].buf;
2772
+ stco_atom = (ngx_mp4_stco_atom_t *) atom->pos;
2773
+
2774
+ ngx_mp4_set_32value(stco_atom->size, atom_size);
2775
+ ngx_mp4_set_32value(stco_atom->entries, trak->chunks - trak->start_chunk);
2776
+
2777
+ return NGX_OK;
2778
+ }
2779
+
2780
+
2781
+ static void
2782
+ ngx_http_mp4_adjust_stco_atom(ngx_http_mp4_file_t *mp4,
2783
+ ngx_http_mp4_trak_t *trak, int32_t adjustment)
2784
+ {
2785
+ uint32_t offset, *entry, *end;
2786
+ ngx_buf_t *data;
2787
+
2788
+ /*
2789
+ * moov.trak.mdia.minf.stbl.stco adjustment requires
2790
+ * minimal start offset of all traks and new moov atom size
2791
+ */
2792
+
2793
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2794
+ "mp4 stco atom adjustment");
2795
+
2796
+ data = trak->out[NGX_HTTP_MP4_STCO_DATA].buf;
2797
+ entry = (uint32_t *) data->pos;
2798
+ end = (uint32_t *) data->last;
2799
+
2800
+ while (entry < end) {
2801
+ offset = ngx_mp4_get_32value(entry);
2802
+ offset += adjustment;
2803
+ ngx_mp4_set_32value(entry, offset);
2804
+ entry++;
2805
+ }
2806
+ }
2807
+
2808
+
2809
+ typedef struct {
2810
+ u_char size[4];
2811
+ u_char name[4];
2812
+ u_char version[1];
2813
+ u_char flags[3];
2814
+ u_char entries[4];
2815
+ } ngx_mp4_co64_atom_t;
2816
+
2817
+
2818
+ static ngx_int_t
2819
+ ngx_http_mp4_read_co64_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
2820
+ {
2821
+ u_char *atom_header, *atom_table, *atom_end;
2822
+ uint32_t entries;
2823
+ ngx_buf_t *atom, *data;
2824
+ ngx_mp4_co64_atom_t *co64_atom;
2825
+ ngx_http_mp4_trak_t *trak;
2826
+
2827
+ /* chunk offsets atom */
2828
+
2829
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 co64 atom");
2830
+
2831
+ atom_header = ngx_mp4_atom_header(mp4);
2832
+ co64_atom = (ngx_mp4_co64_atom_t *) atom_header;
2833
+ ngx_mp4_set_atom_name(co64_atom, 'c', 'o', '6', '4');
2834
+
2835
+ if (ngx_mp4_atom_data_size(ngx_mp4_co64_atom_t) > atom_data_size) {
2836
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2837
+ "\"%s\" mp4 co64 atom too small", mp4->file.name.data);
2838
+ return NGX_ERROR;
2839
+ }
2840
+
2841
+ entries = ngx_mp4_get_32value(co64_atom->entries);
2842
+
2843
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries);
2844
+
2845
+ if (ngx_mp4_atom_data_size(ngx_mp4_co64_atom_t)
2846
+ + entries * sizeof(uint64_t) > atom_data_size)
2847
+ {
2848
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2849
+ "\"%s\" mp4 co64 atom too small", mp4->file.name.data);
2850
+ return NGX_ERROR;
2851
+ }
2852
+
2853
+ atom_table = atom_header + sizeof(ngx_mp4_co64_atom_t);
2854
+ atom_end = atom_table + entries * sizeof(uint64_t);
2855
+
2856
+ trak = ngx_mp4_last_trak(mp4);
2857
+ trak->chunks = entries;
2858
+
2859
+ atom = &trak->co64_atom_buf;
2860
+ atom->temporary = 1;
2861
+ atom->pos = atom_header;
2862
+ atom->last = atom_table;
2863
+
2864
+ data = &trak->co64_data_buf;
2865
+ data->temporary = 1;
2866
+ data->pos = atom_table;
2867
+ data->last = atom_end;
2868
+
2869
+ trak->out[NGX_HTTP_MP4_CO64_ATOM].buf = atom;
2870
+ trak->out[NGX_HTTP_MP4_CO64_DATA].buf = data;
2871
+
2872
+ ngx_mp4_atom_next(mp4, atom_data_size);
2873
+
2874
+ return NGX_OK;
2875
+ }
2876
+
2877
+
2878
+ static ngx_int_t
2879
+ ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4,
2880
+ ngx_http_mp4_trak_t *trak)
2881
+ {
2882
+ size_t atom_size;
2883
+ ngx_buf_t *atom, *data;
2884
+ ngx_mp4_co64_atom_t *co64_atom;
2885
+
2886
+ /*
2887
+ * mdia.minf.stbl.co64 updating requires trak->start_chunk
2888
+ * from mdia.minf.stbl.stsc which depends on value from mdia.mdhd
2889
+ * atom which may reside after mdia.minf
2890
+ */
2891
+
2892
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2893
+ "mp4 co64 atom update");
2894
+
2895
+ data = trak->out[NGX_HTTP_MP4_CO64_DATA].buf;
2896
+
2897
+ if (data == NULL) {
2898
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2899
+ "no mp4 co64 atoms were found in \"%s\"",
2900
+ mp4->file.name.data);
2901
+ return NGX_ERROR;
2902
+ }
2903
+
2904
+ if (trak->start_chunk > trak->chunks) {
2905
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
2906
+ "start time is out mp4 co64 chunks in \"%s\"",
2907
+ mp4->file.name.data);
2908
+ return NGX_ERROR;
2909
+ }
2910
+
2911
+ data->pos += trak->start_chunk * sizeof(uint64_t);
2912
+ atom_size = sizeof(ngx_mp4_co64_atom_t) + (data->last - data->pos);
2913
+ trak->size += atom_size;
2914
+
2915
+ trak->start_offset = ngx_mp4_get_64value(data->pos);
2916
+ trak->start_offset += trak->chunk_samples_size;
2917
+ ngx_mp4_set_64value(data->pos, trak->start_offset);
2918
+
2919
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2920
+ "start chunk offset:%uL", trak->start_offset);
2921
+
2922
+ atom = trak->out[NGX_HTTP_MP4_CO64_ATOM].buf;
2923
+ co64_atom = (ngx_mp4_co64_atom_t *) atom->pos;
2924
+
2925
+ ngx_mp4_set_32value(co64_atom->size, atom_size);
2926
+ ngx_mp4_set_32value(co64_atom->entries, trak->chunks - trak->start_chunk);
2927
+
2928
+ return NGX_OK;
2929
+ }
2930
+
2931
+
2932
+ static void
2933
+ ngx_http_mp4_adjust_co64_atom(ngx_http_mp4_file_t *mp4,
2934
+ ngx_http_mp4_trak_t *trak, off_t adjustment)
2935
+ {
2936
+ uint64_t offset, *entry, *end;
2937
+ ngx_buf_t *data;
2938
+
2939
+ /*
2940
+ * moov.trak.mdia.minf.stbl.co64 adjustment requires
2941
+ * minimal start offset of all traks and new moov atom size
2942
+ */
2943
+
2944
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
2945
+ "mp4 co64 atom adjustment");
2946
+
2947
+ data = trak->out[NGX_HTTP_MP4_CO64_DATA].buf;
2948
+ entry = (uint64_t *) data->pos;
2949
+ end = (uint64_t *) data->last;
2950
+
2951
+ while (entry < end) {
2952
+ offset = ngx_mp4_get_64value(entry);
2953
+ offset += adjustment;
2954
+ ngx_mp4_set_64value(entry, offset);
2955
+ entry++;
2956
+ }
2957
+ }
2958
+
2959
+
2960
+ static char *
2961
+ ngx_http_mp4(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2962
+ {
2963
+ ngx_http_core_loc_conf_t *clcf;
2964
+
2965
+ clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
2966
+ clcf->handler = ngx_http_mp4_handler;
2967
+
2968
+ return NGX_CONF_OK;
2969
+ }
2970
+
2971
+
2972
+ static void *
2973
+ ngx_http_mp4_create_conf(ngx_conf_t *cf)
2974
+ {
2975
+ ngx_http_mp4_conf_t *conf;
2976
+
2977
+ conf = ngx_palloc(cf->pool, sizeof(ngx_http_mp4_conf_t));
2978
+ if (conf == NULL) {
2979
+ return NULL;
2980
+ }
2981
+
2982
+ conf->buffer_size = NGX_CONF_UNSET_SIZE;
2983
+ conf->max_buffer_size = NGX_CONF_UNSET_SIZE;
2984
+
2985
+ return conf;
2986
+ }
2987
+
2988
+
2989
+ static char *
2990
+ ngx_http_mp4_merge_conf(ngx_conf_t *cf, void *parent, void *child)
2991
+ {
2992
+ ngx_http_mp4_conf_t *prev = parent;
2993
+ ngx_http_mp4_conf_t *conf = child;
2994
+
2995
+ ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 512 * 1024);
2996
+ ngx_conf_merge_size_value(conf->max_buffer_size, prev->max_buffer_size,
2997
+ 10 * 1024 * 1024);
2998
+
2999
+ return NGX_CONF_OK;
3000
+ }