Mercurial > hg > nginx-vendor-current
comparison src/http/modules/ngx_http_mp4_module.c @ 640:eb208e0cf44d NGINX_1_1_4
nginx 1.1.4
*) Feature: the ngx_http_upstream_keepalive module.
*) Feature: the "proxy_http_version" directive.
*) Feature: the "fastcgi_keep_conn" directive.
*) Feature: the "worker_aio_requests" directive.
*) Bugfix: if nginx was built --with-file-aio it could not be run on
Linux kernel which did not support AIO.
*) Bugfix: in Linux AIO error processing.
Thanks to Hagai Avrahami.
*) Bugfix: reduced memory consumption for long-lived requests.
*) Bugfix: the module ngx_http_mp4_module did not support 64-bit MP4
"co64" atom.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Tue, 20 Sep 2011 00:00:00 +0400 |
parents | f5a8cf31a203 |
children | d3cf6c6b0043 |
comparison
equal
deleted
inserted
replaced
639:b516b4e38bc9 | 640:eb208e0cf44d |
---|---|
30 #define NGX_HTTP_MP4_STSC_DATA 19 | 30 #define NGX_HTTP_MP4_STSC_DATA 19 |
31 #define NGX_HTTP_MP4_STSZ_ATOM 20 | 31 #define NGX_HTTP_MP4_STSZ_ATOM 20 |
32 #define NGX_HTTP_MP4_STSZ_DATA 21 | 32 #define NGX_HTTP_MP4_STSZ_DATA 21 |
33 #define NGX_HTTP_MP4_STCO_ATOM 22 | 33 #define NGX_HTTP_MP4_STCO_ATOM 22 |
34 #define NGX_HTTP_MP4_STCO_DATA 23 | 34 #define NGX_HTTP_MP4_STCO_DATA 23 |
35 | 35 #define NGX_HTTP_MP4_CO64_ATOM 24 |
36 #define NGX_HTTP_MP4_LAST_ATOM NGX_HTTP_MP4_STCO_DATA | 36 #define NGX_HTTP_MP4_CO64_DATA 25 |
37 | |
38 #define NGX_HTTP_MP4_LAST_ATOM NGX_HTTP_MP4_CO64_DATA | |
37 | 39 |
38 | 40 |
39 typedef struct { | 41 typedef struct { |
40 size_t buffer_size; | 42 size_t buffer_size; |
41 size_t max_buffer_size; | 43 size_t max_buffer_size; |
59 uint32_t chunks; | 61 uint32_t chunks; |
60 | 62 |
61 ngx_uint_t start_sample; | 63 ngx_uint_t start_sample; |
62 ngx_uint_t start_chunk; | 64 ngx_uint_t start_chunk; |
63 ngx_uint_t chunk_samples; | 65 ngx_uint_t chunk_samples; |
64 ngx_uint_t chunk_samples_size; | 66 uint64_t chunk_samples_size; |
65 off_t start_offset; | 67 off_t start_offset; |
66 | 68 |
67 size_t tkhd_size; | 69 size_t tkhd_size; |
68 size_t mdhd_size; | 70 size_t mdhd_size; |
69 size_t hdlr_size; | 71 size_t hdlr_size; |
94 ngx_buf_t stsc_atom_buf; | 96 ngx_buf_t stsc_atom_buf; |
95 ngx_buf_t stsc_chunk_buf; | 97 ngx_buf_t stsc_chunk_buf; |
96 ngx_buf_t stsc_data_buf; | 98 ngx_buf_t stsc_data_buf; |
97 ngx_buf_t stsz_atom_buf; | 99 ngx_buf_t stsz_atom_buf; |
98 ngx_buf_t stsz_data_buf; | 100 ngx_buf_t stsz_data_buf; |
99 ngx_buf_t tsco_atom_buf; | 101 ngx_buf_t stco_atom_buf; |
100 ngx_buf_t tsco_data_buf; | 102 ngx_buf_t stco_data_buf; |
103 ngx_buf_t co64_atom_buf; | |
104 ngx_buf_t co64_data_buf; | |
101 | 105 |
102 ngx_mp4_stsc_entry_t stsc_chunk_entry; | 106 ngx_mp4_stsc_entry_t stsc_chunk_entry; |
103 } ngx_http_mp4_trak_t; | 107 } ngx_http_mp4_trak_t; |
104 | 108 |
105 | 109 |
266 uint64_t atom_data_size); | 270 uint64_t atom_data_size); |
267 static ngx_int_t ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4, | 271 static ngx_int_t ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4, |
268 ngx_http_mp4_trak_t *trak); | 272 ngx_http_mp4_trak_t *trak); |
269 static void ngx_http_mp4_adjust_stco_atom(ngx_http_mp4_file_t *mp4, | 273 static void ngx_http_mp4_adjust_stco_atom(ngx_http_mp4_file_t *mp4, |
270 ngx_http_mp4_trak_t *trak, int32_t adjustment); | 274 ngx_http_mp4_trak_t *trak, int32_t adjustment); |
275 static ngx_int_t ngx_http_mp4_read_co64_atom(ngx_http_mp4_file_t *mp4, | |
276 uint64_t atom_data_size); | |
277 static ngx_int_t ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4, | |
278 ngx_http_mp4_trak_t *trak); | |
279 static void ngx_http_mp4_adjust_co64_atom(ngx_http_mp4_file_t *mp4, | |
280 ngx_http_mp4_trak_t *trak, off_t adjustment); | |
271 static char *ngx_http_mp4(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); | 281 static char *ngx_http_mp4(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); |
272 static void *ngx_http_mp4_create_conf(ngx_conf_t *cf); | 282 static void *ngx_http_mp4_create_conf(ngx_conf_t *cf); |
273 static char *ngx_http_mp4_merge_conf(ngx_conf_t *cf, void *parent, void *child); | 283 static char *ngx_http_mp4_merge_conf(ngx_conf_t *cf, void *parent, void *child); |
274 | 284 |
275 static ngx_command_t ngx_http_mp4_commands[] = { | 285 static ngx_command_t ngx_http_mp4_commands[] = { |
371 { "stss", ngx_http_mp4_read_stss_atom }, | 381 { "stss", ngx_http_mp4_read_stss_atom }, |
372 { "ctts", ngx_http_mp4_read_ctts_atom }, | 382 { "ctts", ngx_http_mp4_read_ctts_atom }, |
373 { "stsc", ngx_http_mp4_read_stsc_atom }, | 383 { "stsc", ngx_http_mp4_read_stsc_atom }, |
374 { "stsz", ngx_http_mp4_read_stsz_atom }, | 384 { "stsz", ngx_http_mp4_read_stsz_atom }, |
375 { "stco", ngx_http_mp4_read_stco_atom }, | 385 { "stco", ngx_http_mp4_read_stco_atom }, |
386 { "co64", ngx_http_mp4_read_co64_atom }, | |
376 { NULL, NULL } | 387 { NULL, NULL } |
377 }; | 388 }; |
378 | 389 |
379 | 390 |
380 static ngx_int_t | 391 static ngx_int_t |
674 return NGX_ERROR; | 685 return NGX_ERROR; |
675 } | 686 } |
676 | 687 |
677 ngx_http_mp4_update_stsz_atom(mp4, &trak[i]); | 688 ngx_http_mp4_update_stsz_atom(mp4, &trak[i]); |
678 | 689 |
679 if (ngx_http_mp4_update_stco_atom(mp4, &trak[i]) != NGX_OK) { | 690 if (trak[i].out[NGX_HTTP_MP4_CO64_DATA].buf) { |
680 return NGX_ERROR; | 691 if (ngx_http_mp4_update_co64_atom(mp4, &trak[i]) != NGX_OK) { |
692 return NGX_ERROR; | |
693 } | |
694 | |
695 } else { | |
696 if (ngx_http_mp4_update_stco_atom(mp4, &trak[i]) != NGX_OK) { | |
697 return NGX_ERROR; | |
698 } | |
681 } | 699 } |
682 | 700 |
683 ngx_http_mp4_update_stbl_atom(mp4, &trak[i]); | 701 ngx_http_mp4_update_stbl_atom(mp4, &trak[i]); |
684 ngx_http_mp4_update_minf_atom(mp4, &trak[i]); | 702 ngx_http_mp4_update_minf_atom(mp4, &trak[i]); |
685 trak[i].size += trak[i].mdhd_size; | 703 trak[i].size += trak[i].mdhd_size; |
719 | 737 |
720 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | 738 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
721 "mp4 adjustment:%D", adjustment); | 739 "mp4 adjustment:%D", adjustment); |
722 | 740 |
723 for (i = 0; i < mp4->trak.nelts; i++) { | 741 for (i = 0; i < mp4->trak.nelts; i++) { |
724 ngx_http_mp4_adjust_stco_atom(mp4, &trak[i], (int32_t) adjustment); | 742 if (trak[i].out[NGX_HTTP_MP4_CO64_DATA].buf) { |
743 ngx_http_mp4_adjust_co64_atom(mp4, &trak[i], adjustment); | |
744 } else { | |
745 ngx_http_mp4_adjust_stco_atom(mp4, &trak[i], (int32_t) adjustment); | |
746 } | |
725 } | 747 } |
726 | 748 |
727 return NGX_OK; | 749 return NGX_OK; |
728 } | 750 } |
729 | 751 |
1700 static ngx_int_t | 1722 static ngx_int_t |
1701 ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | 1723 ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) |
1702 { | 1724 { |
1703 u_char *atom_header, *atom_table; | 1725 u_char *atom_header, *atom_table; |
1704 size_t atom_size; | 1726 size_t atom_size; |
1705 uint32_t entries; | |
1706 ngx_buf_t *atom; | 1727 ngx_buf_t *atom; |
1707 ngx_mp4_stsd_atom_t *stsd_atom; | 1728 ngx_mp4_stsd_atom_t *stsd_atom; |
1708 ngx_http_mp4_trak_t *trak; | 1729 ngx_http_mp4_trak_t *trak; |
1709 | 1730 |
1710 /* sample description atom */ | 1731 /* sample description atom */ |
1716 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | 1737 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; |
1717 atom_table = atom_header + atom_size; | 1738 atom_table = atom_header + atom_size; |
1718 ngx_mp4_set_32value(stsd_atom->size, atom_size); | 1739 ngx_mp4_set_32value(stsd_atom->size, atom_size); |
1719 ngx_mp4_set_atom_name(stsd_atom, 's', 't', 's', 'd'); | 1740 ngx_mp4_set_atom_name(stsd_atom, 's', 't', 's', 'd'); |
1720 | 1741 |
1721 entries = ngx_mp4_get_32value(stsd_atom->entries); | |
1722 | |
1723 if ((uint64_t) (sizeof(ngx_mp4_stsd_atom_t) - sizeof(ngx_mp4_atom_header_t)) | 1742 if ((uint64_t) (sizeof(ngx_mp4_stsd_atom_t) - sizeof(ngx_mp4_atom_header_t)) |
1724 > atom_data_size) { | 1743 > atom_data_size) |
1744 { | |
1725 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | 1745 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
1726 "\"%s\" mp4 stsd atom too large", | 1746 "\"%s\" mp4 stsd atom too large", |
1727 mp4->file.name.data); | 1747 mp4->file.name.data); |
1728 return NGX_ERROR; | 1748 return NGX_ERROR; |
1729 } | 1749 } |
2495 for (pos = end - trak->chunk_samples; pos < end; pos++) { | 2515 for (pos = end - trak->chunk_samples; pos < end; pos++) { |
2496 trak->chunk_samples_size += ngx_mp4_get_32value(pos); | 2516 trak->chunk_samples_size += ngx_mp4_get_32value(pos); |
2497 } | 2517 } |
2498 | 2518 |
2499 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | 2519 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
2500 "chunk samples sizes:%uD", trak->chunk_samples_size); | 2520 "chunk samples sizes:%uL", trak->chunk_samples_size); |
2501 | 2521 |
2502 atom_size = sizeof(ngx_mp4_stsz_atom_t) + (data->last - data->pos); | 2522 atom_size = sizeof(ngx_mp4_stsz_atom_t) + (data->last - data->pos); |
2503 trak->size += atom_size; | 2523 trak->size += atom_size; |
2504 | 2524 |
2505 atom = trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf; | 2525 atom = trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf; |
2552 } | 2572 } |
2553 | 2573 |
2554 trak = ngx_mp4_last_trak(mp4); | 2574 trak = ngx_mp4_last_trak(mp4); |
2555 trak->chunks = entries; | 2575 trak->chunks = entries; |
2556 | 2576 |
2557 atom = &trak->tsco_atom_buf; | 2577 atom = &trak->stco_atom_buf; |
2558 atom->temporary = 1; | 2578 atom->temporary = 1; |
2559 atom->pos = atom_header; | 2579 atom->pos = atom_header; |
2560 atom->last = atom_table; | 2580 atom->last = atom_table; |
2561 | 2581 |
2562 data = &trak->tsco_data_buf; | 2582 data = &trak->stco_data_buf; |
2563 data->temporary = 1; | 2583 data->temporary = 1; |
2564 data->pos = atom_table; | 2584 data->pos = atom_table; |
2565 data->last = atom_end; | 2585 data->last = atom_end; |
2566 | 2586 |
2567 trak->out[NGX_HTTP_MP4_STCO_ATOM].buf = atom; | 2587 trak->out[NGX_HTTP_MP4_STCO_ATOM].buf = atom; |
2646 entry++; | 2666 entry++; |
2647 } | 2667 } |
2648 } | 2668 } |
2649 | 2669 |
2650 | 2670 |
2671 typedef struct { | |
2672 u_char size[4]; | |
2673 u_char name[4]; | |
2674 u_char version[1]; | |
2675 u_char flags[3]; | |
2676 u_char entries[4]; | |
2677 } ngx_mp4_co64_atom_t; | |
2678 | |
2679 | |
2680 static ngx_int_t | |
2681 ngx_http_mp4_read_co64_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2682 { | |
2683 u_char *atom_header, *atom_table, *atom_end; | |
2684 uint32_t entries; | |
2685 ngx_buf_t *atom, *data; | |
2686 ngx_mp4_co64_atom_t *co64_atom; | |
2687 ngx_http_mp4_trak_t *trak; | |
2688 | |
2689 /* chunk offsets atom */ | |
2690 | |
2691 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 co64 atom"); | |
2692 | |
2693 atom_header = ngx_mp4_atom_header(mp4); | |
2694 co64_atom = (ngx_mp4_co64_atom_t *) atom_header; | |
2695 ngx_mp4_set_atom_name(co64_atom, 'c', 'o', '6', '4'); | |
2696 | |
2697 entries = ngx_mp4_get_32value(co64_atom->entries); | |
2698 | |
2699 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries); | |
2700 | |
2701 atom_table = atom_header + sizeof(ngx_mp4_co64_atom_t); | |
2702 atom_end = atom_table + entries * sizeof(uint64_t); | |
2703 | |
2704 if ((uint64_t) (atom_end - co64_atom->version) > atom_data_size) { | |
2705 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2706 "\"%s\" mp4 co64 atom too large", mp4->file.name.data); | |
2707 return NGX_ERROR; | |
2708 } | |
2709 | |
2710 trak = ngx_mp4_last_trak(mp4); | |
2711 trak->chunks = entries; | |
2712 | |
2713 atom = &trak->co64_atom_buf; | |
2714 atom->temporary = 1; | |
2715 atom->pos = atom_header; | |
2716 atom->last = atom_table; | |
2717 | |
2718 data = &trak->co64_data_buf; | |
2719 data->temporary = 1; | |
2720 data->pos = atom_table; | |
2721 data->last = atom_end; | |
2722 | |
2723 trak->out[NGX_HTTP_MP4_CO64_ATOM].buf = atom; | |
2724 trak->out[NGX_HTTP_MP4_CO64_DATA].buf = data; | |
2725 | |
2726 ngx_mp4_atom_next(mp4, atom_data_size); | |
2727 | |
2728 return NGX_OK; | |
2729 } | |
2730 | |
2731 | |
2732 static ngx_int_t | |
2733 ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4, | |
2734 ngx_http_mp4_trak_t *trak) | |
2735 { | |
2736 size_t atom_size; | |
2737 ngx_buf_t *atom, *data; | |
2738 ngx_mp4_co64_atom_t *co64_atom; | |
2739 | |
2740 /* | |
2741 * mdia.minf.stbl.co64 updating requires trak->start_chunk | |
2742 * from mdia.minf.stbl.stsc which depends on value from mdia.mdhd | |
2743 * atom which may reside after mdia.minf | |
2744 */ | |
2745 | |
2746 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2747 "mp4 co64 atom update"); | |
2748 | |
2749 data = trak->out[NGX_HTTP_MP4_CO64_DATA].buf; | |
2750 | |
2751 if (data == NULL) { | |
2752 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2753 "no mp4 co64 atoms were found in \"%s\"", | |
2754 mp4->file.name.data); | |
2755 return NGX_ERROR; | |
2756 } | |
2757 | |
2758 data->pos += trak->start_chunk * sizeof(uint64_t); | |
2759 atom_size = sizeof(ngx_mp4_co64_atom_t) + (data->last - data->pos); | |
2760 trak->size += atom_size; | |
2761 | |
2762 trak->start_offset = ngx_mp4_get_64value(data->pos); | |
2763 trak->start_offset += trak->chunk_samples_size; | |
2764 ngx_mp4_set_64value(data->pos, trak->start_offset); | |
2765 | |
2766 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2767 "start chunk offset:%uL", trak->start_offset); | |
2768 | |
2769 atom = trak->out[NGX_HTTP_MP4_CO64_ATOM].buf; | |
2770 co64_atom = (ngx_mp4_co64_atom_t *) atom->pos; | |
2771 | |
2772 ngx_mp4_set_32value(co64_atom->size, atom_size); | |
2773 ngx_mp4_set_32value(co64_atom->entries, trak->chunks - trak->start_chunk); | |
2774 | |
2775 return NGX_OK; | |
2776 } | |
2777 | |
2778 | |
2779 static void | |
2780 ngx_http_mp4_adjust_co64_atom(ngx_http_mp4_file_t *mp4, | |
2781 ngx_http_mp4_trak_t *trak, off_t adjustment) | |
2782 { | |
2783 uint64_t offset, *entry, *end; | |
2784 ngx_buf_t *data; | |
2785 | |
2786 /* | |
2787 * moov.trak.mdia.minf.stbl.co64 adjustment requires | |
2788 * minimal start offset of all traks and new moov atom size | |
2789 */ | |
2790 | |
2791 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2792 "mp4 co64 atom adjustment"); | |
2793 | |
2794 data = trak->out[NGX_HTTP_MP4_CO64_DATA].buf; | |
2795 entry = (uint64_t *) data->pos; | |
2796 end = (uint64_t *) data->last; | |
2797 | |
2798 while (entry < end) { | |
2799 offset = ngx_mp4_get_64value(entry); | |
2800 offset += adjustment; | |
2801 ngx_mp4_set_64value(entry, offset); | |
2802 entry++; | |
2803 } | |
2804 } | |
2805 | |
2806 | |
2651 static char * | 2807 static char * |
2652 ngx_http_mp4(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | 2808 ngx_http_mp4(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
2653 { | 2809 { |
2654 ngx_http_core_loc_conf_t *clcf; | 2810 ngx_http_core_loc_conf_t *clcf; |
2655 | 2811 |