Mercurial > hg > nginx
comparison src/http/modules/ngx_http_mp4_module.c @ 4112:bc0ca958c270
MP4 co64 atom support added.
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Thu, 15 Sep 2011 13:23:03 +0000 |
parents | 7705911c9d10 |
children | d9636bf3f159 |
comparison
equal
deleted
inserted
replaced
4111:088ee72d2e57 | 4112:bc0ca958c270 |
---|---|
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; |
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 stco_atom_buf; | 101 ngx_buf_t stco_atom_buf; |
100 ngx_buf_t stco_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 |
2493 for (pos = end - trak->chunk_samples; pos < end; pos++) { | 2515 for (pos = end - trak->chunk_samples; pos < end; pos++) { |
2494 trak->chunk_samples_size += ngx_mp4_get_32value(pos); | 2516 trak->chunk_samples_size += ngx_mp4_get_32value(pos); |
2495 } | 2517 } |
2496 | 2518 |
2497 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | 2519 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
2498 "chunk samples sizes:%uD", trak->chunk_samples_size); | 2520 "chunk samples sizes:%uL", trak->chunk_samples_size); |
2499 | 2521 |
2500 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); |
2501 trak->size += atom_size; | 2523 trak->size += atom_size; |
2502 | 2524 |
2503 atom = trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf; | 2525 atom = trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf; |
2644 entry++; | 2666 entry++; |
2645 } | 2667 } |
2646 } | 2668 } |
2647 | 2669 |
2648 | 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 | |
2649 static char * | 2807 static char * |
2650 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) |
2651 { | 2809 { |
2652 ngx_http_core_loc_conf_t *clcf; | 2810 ngx_http_core_loc_conf_t *clcf; |
2653 | 2811 |