Mercurial > hg > nginx
comparison src/http/modules/ngx_http_mp4_module.c @ 5620:0a567878254b
Mp4: added "end" argument support.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Thu, 20 Mar 2014 16:05:19 +0400 |
parents | 517b5b599e3f |
children | 345e4fd4bb64 |
comparison
equal
deleted
inserted
replaced
5619:517b5b599e3f | 5620:0a567878254b |
---|---|
25 #define NGX_HTTP_MP4_STSS_ATOM 13 | 25 #define NGX_HTTP_MP4_STSS_ATOM 13 |
26 #define NGX_HTTP_MP4_STSS_DATA 14 | 26 #define NGX_HTTP_MP4_STSS_DATA 14 |
27 #define NGX_HTTP_MP4_CTTS_ATOM 15 | 27 #define NGX_HTTP_MP4_CTTS_ATOM 15 |
28 #define NGX_HTTP_MP4_CTTS_DATA 16 | 28 #define NGX_HTTP_MP4_CTTS_DATA 16 |
29 #define NGX_HTTP_MP4_STSC_ATOM 17 | 29 #define NGX_HTTP_MP4_STSC_ATOM 17 |
30 #define NGX_HTTP_MP4_STSC_CHUNK 18 | 30 #define NGX_HTTP_MP4_STSC_START 18 |
31 #define NGX_HTTP_MP4_STSC_DATA 19 | 31 #define NGX_HTTP_MP4_STSC_DATA 19 |
32 #define NGX_HTTP_MP4_STSZ_ATOM 20 | 32 #define NGX_HTTP_MP4_STSC_END 20 |
33 #define NGX_HTTP_MP4_STSZ_DATA 21 | 33 #define NGX_HTTP_MP4_STSZ_ATOM 21 |
34 #define NGX_HTTP_MP4_STCO_ATOM 22 | 34 #define NGX_HTTP_MP4_STSZ_DATA 22 |
35 #define NGX_HTTP_MP4_STCO_DATA 23 | 35 #define NGX_HTTP_MP4_STCO_ATOM 23 |
36 #define NGX_HTTP_MP4_CO64_ATOM 24 | 36 #define NGX_HTTP_MP4_STCO_DATA 24 |
37 #define NGX_HTTP_MP4_CO64_DATA 25 | 37 #define NGX_HTTP_MP4_CO64_ATOM 25 |
38 #define NGX_HTTP_MP4_CO64_DATA 26 | |
38 | 39 |
39 #define NGX_HTTP_MP4_LAST_ATOM NGX_HTTP_MP4_CO64_DATA | 40 #define NGX_HTTP_MP4_LAST_ATOM NGX_HTTP_MP4_CO64_DATA |
40 | 41 |
41 | 42 |
42 typedef struct { | 43 typedef struct { |
60 uint32_t composition_offset_entries; | 61 uint32_t composition_offset_entries; |
61 uint32_t sample_sizes_entries; | 62 uint32_t sample_sizes_entries; |
62 uint32_t chunks; | 63 uint32_t chunks; |
63 | 64 |
64 ngx_uint_t start_sample; | 65 ngx_uint_t start_sample; |
66 ngx_uint_t end_sample; | |
65 ngx_uint_t start_chunk; | 67 ngx_uint_t start_chunk; |
66 ngx_uint_t chunk_samples; | 68 ngx_uint_t end_chunk; |
67 uint64_t chunk_samples_size; | 69 ngx_uint_t start_chunk_samples; |
70 ngx_uint_t end_chunk_samples; | |
71 uint64_t start_chunk_samples_size; | |
72 uint64_t end_chunk_samples_size; | |
68 off_t start_offset; | 73 off_t start_offset; |
74 off_t end_offset; | |
69 | 75 |
70 size_t tkhd_size; | 76 size_t tkhd_size; |
71 size_t mdhd_size; | 77 size_t mdhd_size; |
72 size_t hdlr_size; | 78 size_t hdlr_size; |
73 size_t vmhd_size; | 79 size_t vmhd_size; |
93 ngx_buf_t stss_atom_buf; | 99 ngx_buf_t stss_atom_buf; |
94 ngx_buf_t stss_data_buf; | 100 ngx_buf_t stss_data_buf; |
95 ngx_buf_t ctts_atom_buf; | 101 ngx_buf_t ctts_atom_buf; |
96 ngx_buf_t ctts_data_buf; | 102 ngx_buf_t ctts_data_buf; |
97 ngx_buf_t stsc_atom_buf; | 103 ngx_buf_t stsc_atom_buf; |
98 ngx_buf_t stsc_chunk_buf; | 104 ngx_buf_t stsc_start_chunk_buf; |
105 ngx_buf_t stsc_end_chunk_buf; | |
99 ngx_buf_t stsc_data_buf; | 106 ngx_buf_t stsc_data_buf; |
100 ngx_buf_t stsz_atom_buf; | 107 ngx_buf_t stsz_atom_buf; |
101 ngx_buf_t stsz_data_buf; | 108 ngx_buf_t stsz_data_buf; |
102 ngx_buf_t stco_atom_buf; | 109 ngx_buf_t stco_atom_buf; |
103 ngx_buf_t stco_data_buf; | 110 ngx_buf_t stco_data_buf; |
104 ngx_buf_t co64_atom_buf; | 111 ngx_buf_t co64_atom_buf; |
105 ngx_buf_t co64_data_buf; | 112 ngx_buf_t co64_data_buf; |
106 | 113 |
107 ngx_mp4_stsc_entry_t stsc_chunk_entry; | 114 ngx_mp4_stsc_entry_t stsc_start_chunk_entry; |
115 ngx_mp4_stsc_entry_t stsc_end_chunk_entry; | |
108 } ngx_http_mp4_trak_t; | 116 } ngx_http_mp4_trak_t; |
109 | 117 |
110 | 118 |
111 typedef struct { | 119 typedef struct { |
112 ngx_file_t file; | 120 ngx_file_t file; |
119 | 127 |
120 off_t offset; | 128 off_t offset; |
121 off_t end; | 129 off_t end; |
122 off_t content_length; | 130 off_t content_length; |
123 ngx_uint_t start; | 131 ngx_uint_t start; |
132 ngx_uint_t length; | |
124 uint32_t timescale; | 133 uint32_t timescale; |
125 ngx_http_request_t *request; | 134 ngx_http_request_t *request; |
126 ngx_array_t trak; | 135 ngx_array_t trak; |
127 ngx_http_mp4_trak_t traks[2]; | 136 ngx_http_mp4_trak_t traks[2]; |
128 | 137 |
217 static ngx_int_t ngx_http_mp4_read_moov_atom(ngx_http_mp4_file_t *mp4, | 226 static ngx_int_t ngx_http_mp4_read_moov_atom(ngx_http_mp4_file_t *mp4, |
218 uint64_t atom_data_size); | 227 uint64_t atom_data_size); |
219 static ngx_int_t ngx_http_mp4_read_mdat_atom(ngx_http_mp4_file_t *mp4, | 228 static ngx_int_t ngx_http_mp4_read_mdat_atom(ngx_http_mp4_file_t *mp4, |
220 uint64_t atom_data_size); | 229 uint64_t atom_data_size); |
221 static size_t ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, | 230 static size_t ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, |
222 off_t start_offset); | 231 off_t start_offset, off_t end_offset); |
223 static ngx_int_t ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4, | 232 static ngx_int_t ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4, |
224 uint64_t atom_data_size); | 233 uint64_t atom_data_size); |
225 static ngx_int_t ngx_http_mp4_read_trak_atom(ngx_http_mp4_file_t *mp4, | 234 static ngx_int_t ngx_http_mp4_read_trak_atom(ngx_http_mp4_file_t *mp4, |
226 uint64_t atom_data_size); | 235 uint64_t atom_data_size); |
227 static void ngx_http_mp4_update_trak_atom(ngx_http_mp4_file_t *mp4, | 236 static void ngx_http_mp4_update_trak_atom(ngx_http_mp4_file_t *mp4, |
257 static ngx_int_t ngx_http_mp4_read_stts_atom(ngx_http_mp4_file_t *mp4, | 266 static ngx_int_t ngx_http_mp4_read_stts_atom(ngx_http_mp4_file_t *mp4, |
258 uint64_t atom_data_size); | 267 uint64_t atom_data_size); |
259 static ngx_int_t ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, | 268 static ngx_int_t ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, |
260 ngx_http_mp4_trak_t *trak); | 269 ngx_http_mp4_trak_t *trak); |
261 static ngx_int_t ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, | 270 static ngx_int_t ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, |
262 ngx_http_mp4_trak_t *trak); | 271 ngx_http_mp4_trak_t *trak, ngx_uint_t start); |
263 static ngx_int_t ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4, | 272 static ngx_int_t ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4, |
264 uint64_t atom_data_size); | 273 uint64_t atom_data_size); |
265 static ngx_int_t ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4, | 274 static ngx_int_t ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4, |
266 ngx_http_mp4_trak_t *trak); | 275 ngx_http_mp4_trak_t *trak); |
267 static void ngx_http_mp4_crop_stss_data(ngx_http_mp4_file_t *mp4, | 276 static void ngx_http_mp4_crop_stss_data(ngx_http_mp4_file_t *mp4, |
268 ngx_http_mp4_trak_t *trak); | 277 ngx_http_mp4_trak_t *trak, ngx_uint_t start); |
269 static ngx_int_t ngx_http_mp4_read_ctts_atom(ngx_http_mp4_file_t *mp4, | 278 static ngx_int_t ngx_http_mp4_read_ctts_atom(ngx_http_mp4_file_t *mp4, |
270 uint64_t atom_data_size); | 279 uint64_t atom_data_size); |
271 static void ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4, | 280 static void ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4, |
272 ngx_http_mp4_trak_t *trak); | 281 ngx_http_mp4_trak_t *trak); |
273 static void ngx_http_mp4_crop_ctts_data(ngx_http_mp4_file_t *mp4, | 282 static void ngx_http_mp4_crop_ctts_data(ngx_http_mp4_file_t *mp4, |
274 ngx_http_mp4_trak_t *trak); | 283 ngx_http_mp4_trak_t *trak, ngx_uint_t start); |
275 static ngx_int_t ngx_http_mp4_read_stsc_atom(ngx_http_mp4_file_t *mp4, | 284 static ngx_int_t ngx_http_mp4_read_stsc_atom(ngx_http_mp4_file_t *mp4, |
276 uint64_t atom_data_size); | 285 uint64_t atom_data_size); |
277 static ngx_int_t ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4, | 286 static ngx_int_t ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4, |
278 ngx_http_mp4_trak_t *trak); | 287 ngx_http_mp4_trak_t *trak); |
279 static ngx_int_t ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4, | 288 static ngx_int_t ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4, |
280 ngx_http_mp4_trak_t *trak); | 289 ngx_http_mp4_trak_t *trak, ngx_uint_t start); |
281 static ngx_int_t ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *mp4, | 290 static ngx_int_t ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *mp4, |
282 uint64_t atom_data_size); | 291 uint64_t atom_data_size); |
283 static ngx_int_t ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4, | 292 static ngx_int_t ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4, |
284 ngx_http_mp4_trak_t *trak); | 293 ngx_http_mp4_trak_t *trak); |
285 static ngx_int_t ngx_http_mp4_read_stco_atom(ngx_http_mp4_file_t *mp4, | 294 static ngx_int_t ngx_http_mp4_read_stco_atom(ngx_http_mp4_file_t *mp4, |
409 static ngx_int_t | 418 static ngx_int_t |
410 ngx_http_mp4_handler(ngx_http_request_t *r) | 419 ngx_http_mp4_handler(ngx_http_request_t *r) |
411 { | 420 { |
412 u_char *last; | 421 u_char *last; |
413 size_t root; | 422 size_t root; |
414 ngx_int_t rc, start; | 423 ngx_int_t rc, start, end; |
415 ngx_uint_t level; | 424 ngx_uint_t level, length; |
416 ngx_str_t path, value; | 425 ngx_str_t path, value; |
417 ngx_log_t *log; | 426 ngx_log_t *log; |
418 ngx_buf_t *b; | 427 ngx_buf_t *b; |
419 ngx_chain_t out; | 428 ngx_chain_t out; |
420 ngx_http_mp4_file_t *mp4; | 429 ngx_http_mp4_file_t *mp4; |
515 | 524 |
516 r->root_tested = !r->error_page; | 525 r->root_tested = !r->error_page; |
517 r->allow_ranges = 1; | 526 r->allow_ranges = 1; |
518 | 527 |
519 start = -1; | 528 start = -1; |
529 length = 0; | |
520 r->headers_out.content_length_n = of.size; | 530 r->headers_out.content_length_n = of.size; |
521 mp4 = NULL; | 531 mp4 = NULL; |
522 b = NULL; | 532 b = NULL; |
523 | 533 |
524 if (r->args.len) { | 534 if (r->args.len) { |
536 | 546 |
537 if (ngx_errno != 0) { | 547 if (ngx_errno != 0) { |
538 start = -1; | 548 start = -1; |
539 } | 549 } |
540 } | 550 } |
551 | |
552 if (ngx_http_arg(r, (u_char *) "end", 3, &value) == NGX_OK) { | |
553 | |
554 ngx_set_errno(0); | |
555 end = (int) (strtod((char *) value.data, NULL) * 1000); | |
556 | |
557 if (ngx_errno != 0) { | |
558 end = -1; | |
559 } | |
560 | |
561 if (end > 0) { | |
562 if (start < 0) { | |
563 start = 0; | |
564 } | |
565 | |
566 if (end > start) { | |
567 length = end - start; | |
568 } | |
569 } | |
570 } | |
541 } | 571 } |
542 | 572 |
543 if (start >= 0) { | 573 if (start >= 0) { |
544 r->allow_ranges = 0; | 574 r->allow_ranges = 0; |
545 | 575 |
551 mp4->file.fd = of.fd; | 581 mp4->file.fd = of.fd; |
552 mp4->file.name = path; | 582 mp4->file.name = path; |
553 mp4->file.log = r->connection->log; | 583 mp4->file.log = r->connection->log; |
554 mp4->end = of.size; | 584 mp4->end = of.size; |
555 mp4->start = (ngx_uint_t) start; | 585 mp4->start = (ngx_uint_t) start; |
586 mp4->length = length; | |
556 mp4->request = r; | 587 mp4->request = r; |
557 | 588 |
558 switch (ngx_http_mp4_process(mp4)) { | 589 switch (ngx_http_mp4_process(mp4)) { |
559 | 590 |
560 case NGX_DECLINED: | 591 case NGX_DECLINED: |
656 | 687 |
657 | 688 |
658 static ngx_int_t | 689 static ngx_int_t |
659 ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) | 690 ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) |
660 { | 691 { |
661 off_t start_offset, adjustment; | 692 off_t start_offset, end_offset, adjustment; |
662 ngx_int_t rc; | 693 ngx_int_t rc; |
663 ngx_uint_t i, j; | 694 ngx_uint_t i, j; |
664 ngx_chain_t **prev; | 695 ngx_chain_t **prev; |
665 ngx_http_mp4_trak_t *trak; | 696 ngx_http_mp4_trak_t *trak; |
666 ngx_http_mp4_conf_t *conf; | 697 ngx_http_mp4_conf_t *conf; |
667 | 698 |
668 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | 699 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
669 "mp4 start:%ui", mp4->start); | 700 "mp4 start:%ui, length:%ui", mp4->start, mp4->length); |
670 | 701 |
671 conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module); | 702 conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module); |
672 | 703 |
673 mp4->buffer_size = conf->buffer_size; | 704 mp4->buffer_size = conf->buffer_size; |
674 | 705 |
706 *prev = &mp4->mvhd_atom; | 737 *prev = &mp4->mvhd_atom; |
707 prev = &mp4->mvhd_atom.next; | 738 prev = &mp4->mvhd_atom.next; |
708 } | 739 } |
709 | 740 |
710 start_offset = mp4->end; | 741 start_offset = mp4->end; |
742 end_offset = 0; | |
711 trak = mp4->trak.elts; | 743 trak = mp4->trak.elts; |
712 | 744 |
713 for (i = 0; i < mp4->trak.nelts; i++) { | 745 for (i = 0; i < mp4->trak.nelts; i++) { |
714 | 746 |
715 if (ngx_http_mp4_update_stts_atom(mp4, &trak[i]) != NGX_OK) { | 747 if (ngx_http_mp4_update_stts_atom(mp4, &trak[i]) != NGX_OK) { |
753 | 785 |
754 if (start_offset > trak[i].start_offset) { | 786 if (start_offset > trak[i].start_offset) { |
755 start_offset = trak[i].start_offset; | 787 start_offset = trak[i].start_offset; |
756 } | 788 } |
757 | 789 |
790 if (end_offset < trak[i].end_offset) { | |
791 end_offset = trak[i].end_offset; | |
792 } | |
793 | |
758 *prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM]; | 794 *prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM]; |
759 prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM].next; | 795 prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM].next; |
760 | 796 |
761 for (j = 0; j < NGX_HTTP_MP4_LAST_ATOM + 1; j++) { | 797 for (j = 0; j < NGX_HTTP_MP4_LAST_ATOM + 1; j++) { |
762 if (trak[i].out[j].buf) { | 798 if (trak[i].out[j].buf) { |
764 prev = &trak[i].out[j].next; | 800 prev = &trak[i].out[j].next; |
765 } | 801 } |
766 } | 802 } |
767 } | 803 } |
768 | 804 |
805 if (end_offset < start_offset) { | |
806 end_offset = start_offset; | |
807 } | |
808 | |
769 mp4->moov_size += 8; | 809 mp4->moov_size += 8; |
770 | 810 |
771 ngx_mp4_set_32value(mp4->moov_atom_header, mp4->moov_size); | 811 ngx_mp4_set_32value(mp4->moov_atom_header, mp4->moov_size); |
772 ngx_mp4_set_atom_name(mp4->moov_atom_header, 'm', 'o', 'o', 'v'); | 812 ngx_mp4_set_atom_name(mp4->moov_atom_header, 'm', 'o', 'o', 'v'); |
773 mp4->content_length += mp4->moov_size; | 813 mp4->content_length += mp4->moov_size; |
780 mp4->file.name.data); | 820 mp4->file.name.data); |
781 return NGX_ERROR; | 821 return NGX_ERROR; |
782 } | 822 } |
783 | 823 |
784 adjustment = mp4->ftyp_size + mp4->moov_size | 824 adjustment = mp4->ftyp_size + mp4->moov_size |
785 + ngx_http_mp4_update_mdat_atom(mp4, start_offset) | 825 + ngx_http_mp4_update_mdat_atom(mp4, start_offset, end_offset) |
786 - start_offset; | 826 - start_offset; |
787 | 827 |
788 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | 828 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
789 "mp4 adjustment:%O", adjustment); | 829 "mp4 adjustment:%O", adjustment); |
790 | 830 |
1024 | 1064 |
1025 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 moov atom"); | 1065 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 moov atom"); |
1026 | 1066 |
1027 no_mdat = (mp4->mdat_atom.buf == NULL); | 1067 no_mdat = (mp4->mdat_atom.buf == NULL); |
1028 | 1068 |
1029 if (no_mdat && mp4->start == 0) { | 1069 if (no_mdat && mp4->start == 0 && mp4->length == 0) { |
1030 /* | 1070 /* |
1031 * send original file if moov atom resides before | 1071 * send original file if moov atom resides before |
1032 * mdat atom and client requests integral file | 1072 * mdat atom and client requests integral file |
1033 */ | 1073 */ |
1034 return NGX_DECLINED; | 1074 return NGX_DECLINED; |
1123 return NGX_OK; | 1163 return NGX_OK; |
1124 } | 1164 } |
1125 | 1165 |
1126 | 1166 |
1127 static size_t | 1167 static size_t |
1128 ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset) | 1168 ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset, |
1169 off_t end_offset) | |
1129 { | 1170 { |
1130 off_t atom_data_size; | 1171 off_t atom_data_size; |
1131 u_char *atom_header; | 1172 u_char *atom_header; |
1132 uint32_t atom_header_size; | 1173 uint32_t atom_header_size; |
1133 uint64_t atom_size; | 1174 uint64_t atom_size; |
1134 ngx_buf_t *atom; | 1175 ngx_buf_t *atom; |
1135 | 1176 |
1136 atom_data_size = mp4->mdat_data.buf->file_last - start_offset; | 1177 atom_data_size = end_offset - start_offset; |
1137 mp4->mdat_data.buf->file_pos = start_offset; | 1178 mp4->mdat_data.buf->file_pos = start_offset; |
1179 mp4->mdat_data.buf->file_last = end_offset; | |
1138 | 1180 |
1139 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | 1181 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
1140 "mdat new offset @%O:%O", start_offset, atom_data_size); | 1182 "mdat new offset @%O:%O", start_offset, atom_data_size); |
1141 | 1183 |
1142 atom_header = mp4->mdat_atom_header; | 1184 atom_header = mp4->mdat_atom_header; |
1214 ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | 1256 ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) |
1215 { | 1257 { |
1216 u_char *atom_header; | 1258 u_char *atom_header; |
1217 size_t atom_size; | 1259 size_t atom_size; |
1218 uint32_t timescale; | 1260 uint32_t timescale; |
1219 uint64_t duration, start_time; | 1261 uint64_t duration, start_time, length_time; |
1220 ngx_buf_t *atom; | 1262 ngx_buf_t *atom; |
1221 ngx_mp4_mvhd_atom_t *mvhd_atom; | 1263 ngx_mp4_mvhd_atom_t *mvhd_atom; |
1222 ngx_mp4_mvhd64_atom_t *mvhd64_atom; | 1264 ngx_mp4_mvhd64_atom_t *mvhd64_atom; |
1223 | 1265 |
1224 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 mvhd atom"); | 1266 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 mvhd atom"); |
1267 mp4->file.name.data); | 1309 mp4->file.name.data); |
1268 return NGX_ERROR; | 1310 return NGX_ERROR; |
1269 } | 1311 } |
1270 | 1312 |
1271 duration -= start_time; | 1313 duration -= start_time; |
1314 | |
1315 if (mp4->length) { | |
1316 length_time = (uint64_t) mp4->length * timescale / 1000; | |
1317 | |
1318 if (duration > length_time) { | |
1319 duration = length_time; | |
1320 } | |
1321 } | |
1272 | 1322 |
1273 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | 1323 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
1274 "mvhd new duration:%uL, time:%.3fs", | 1324 "mvhd new duration:%uL, time:%.3fs", |
1275 duration, (double) duration / timescale); | 1325 duration, (double) duration / timescale); |
1276 | 1326 |
1413 static ngx_int_t | 1463 static ngx_int_t |
1414 ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | 1464 ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) |
1415 { | 1465 { |
1416 u_char *atom_header; | 1466 u_char *atom_header; |
1417 size_t atom_size; | 1467 size_t atom_size; |
1418 uint64_t duration, start_time; | 1468 uint64_t duration, start_time, length_time; |
1419 ngx_buf_t *atom; | 1469 ngx_buf_t *atom; |
1420 ngx_http_mp4_trak_t *trak; | 1470 ngx_http_mp4_trak_t *trak; |
1421 ngx_mp4_tkhd_atom_t *tkhd_atom; | 1471 ngx_mp4_tkhd_atom_t *tkhd_atom; |
1422 ngx_mp4_tkhd64_atom_t *tkhd64_atom; | 1472 ngx_mp4_tkhd64_atom_t *tkhd64_atom; |
1423 | 1473 |
1462 "tkhd duration is less than start time"); | 1512 "tkhd duration is less than start time"); |
1463 return NGX_DECLINED; | 1513 return NGX_DECLINED; |
1464 } | 1514 } |
1465 | 1515 |
1466 duration -= start_time; | 1516 duration -= start_time; |
1517 | |
1518 if (mp4->length) { | |
1519 length_time = (uint64_t) mp4->length * mp4->timescale / 1000; | |
1520 | |
1521 if (duration > length_time) { | |
1522 duration = length_time; | |
1523 } | |
1524 } | |
1467 | 1525 |
1468 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | 1526 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
1469 "tkhd new duration:%uL, time:%.3fs", | 1527 "tkhd new duration:%uL, time:%.3fs", |
1470 duration, (double) duration / mp4->timescale); | 1528 duration, (double) duration / mp4->timescale); |
1471 | 1529 |
1564 ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | 1622 ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) |
1565 { | 1623 { |
1566 u_char *atom_header; | 1624 u_char *atom_header; |
1567 size_t atom_size; | 1625 size_t atom_size; |
1568 uint32_t timescale; | 1626 uint32_t timescale; |
1569 uint64_t duration, start_time; | 1627 uint64_t duration, start_time, length_time; |
1570 ngx_buf_t *atom; | 1628 ngx_buf_t *atom; |
1571 ngx_http_mp4_trak_t *trak; | 1629 ngx_http_mp4_trak_t *trak; |
1572 ngx_mp4_mdhd_atom_t *mdhd_atom; | 1630 ngx_mp4_mdhd_atom_t *mdhd_atom; |
1573 ngx_mp4_mdhd64_atom_t *mdhd64_atom; | 1631 ngx_mp4_mdhd64_atom_t *mdhd64_atom; |
1574 | 1632 |
1615 "mdhd duration is less than start time"); | 1673 "mdhd duration is less than start time"); |
1616 return NGX_DECLINED; | 1674 return NGX_DECLINED; |
1617 } | 1675 } |
1618 | 1676 |
1619 duration -= start_time; | 1677 duration -= start_time; |
1678 | |
1679 if (mp4->length) { | |
1680 length_time = (uint64_t) mp4->length * timescale / 1000; | |
1681 | |
1682 if (duration > length_time) { | |
1683 duration = length_time; | |
1684 } | |
1685 } | |
1620 | 1686 |
1621 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | 1687 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
1622 "mdhd new duration:%uL, time:%.3fs", | 1688 "mdhd new duration:%uL, time:%.3fs", |
1623 duration, (double) duration / timescale); | 1689 duration, (double) duration / timescale); |
1624 | 1690 |
2008 "no mp4 stts atoms were found in \"%s\"", | 2074 "no mp4 stts atoms were found in \"%s\"", |
2009 mp4->file.name.data); | 2075 mp4->file.name.data); |
2010 return NGX_ERROR; | 2076 return NGX_ERROR; |
2011 } | 2077 } |
2012 | 2078 |
2013 if (ngx_http_mp4_crop_stts_data(mp4, trak) != NGX_OK) { | 2079 if (ngx_http_mp4_crop_stts_data(mp4, trak, 1) != NGX_OK) { |
2080 return NGX_ERROR; | |
2081 } | |
2082 | |
2083 if (ngx_http_mp4_crop_stts_data(mp4, trak, 0) != NGX_OK) { | |
2014 return NGX_ERROR; | 2084 return NGX_ERROR; |
2015 } | 2085 } |
2016 | 2086 |
2017 atom_size = sizeof(ngx_mp4_stts_atom_t) + (data->last - data->pos); | 2087 atom_size = sizeof(ngx_mp4_stts_atom_t) + (data->last - data->pos); |
2018 trak->size += atom_size; | 2088 trak->size += atom_size; |
2026 } | 2096 } |
2027 | 2097 |
2028 | 2098 |
2029 static ngx_int_t | 2099 static ngx_int_t |
2030 ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, | 2100 ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, |
2031 ngx_http_mp4_trak_t *trak) | 2101 ngx_http_mp4_trak_t *trak, ngx_uint_t start) |
2032 { | 2102 { |
2033 uint32_t count, duration; | 2103 uint32_t count, duration, rest; |
2034 uint64_t start_time; | 2104 uint64_t start_time; |
2035 ngx_buf_t *data; | 2105 ngx_buf_t *data; |
2036 ngx_uint_t start_sample, entries; | 2106 ngx_uint_t start_sample, entries, start_sec; |
2037 ngx_mp4_stts_entry_t *entry, *end; | 2107 ngx_mp4_stts_entry_t *entry, *end; |
2038 | 2108 |
2109 if (start) { | |
2110 start_sec = mp4->start; | |
2111 | |
2112 } else if (mp4->length) { | |
2113 start_sec = mp4->length; | |
2114 | |
2115 } else { | |
2116 return NGX_OK; | |
2117 } | |
2118 | |
2039 data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf; | 2119 data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf; |
2040 | 2120 |
2041 start_time = (uint64_t) mp4->start * trak->timescale / 1000; | 2121 start_time = (uint64_t) start_sec * trak->timescale / 1000; |
2042 | 2122 |
2043 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | 2123 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
2044 "time-to-sample start_time:%uL", start_time); | 2124 "time-to-sample start_time:%uL", start_time); |
2045 | 2125 |
2046 entries = trak->time_to_sample_entries; | 2126 entries = trak->time_to_sample_entries; |
2055 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | 2135 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
2056 "count:%uD, duration:%uD", count, duration); | 2136 "count:%uD, duration:%uD", count, duration); |
2057 | 2137 |
2058 if (start_time < (uint64_t) count * duration) { | 2138 if (start_time < (uint64_t) count * duration) { |
2059 start_sample += (ngx_uint_t) (start_time / duration); | 2139 start_sample += (ngx_uint_t) (start_time / duration); |
2060 count -= (uint32_t) (start_time / duration); | 2140 rest = (uint32_t) (start_time / duration); |
2061 ngx_mp4_set_32value(entry->count, count); | |
2062 goto found; | 2141 goto found; |
2063 } | 2142 } |
2064 | 2143 |
2065 start_sample += count; | 2144 start_sample += count; |
2066 start_time -= count * duration; | 2145 start_time -= count * duration; |
2077 found: | 2156 found: |
2078 | 2157 |
2079 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | 2158 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
2080 "start_sample:%ui, new count:%uD", start_sample, count); | 2159 "start_sample:%ui, new count:%uD", start_sample, count); |
2081 | 2160 |
2082 trak->time_to_sample_entries = entries; | 2161 if (start) { |
2083 trak->start_sample = start_sample; | 2162 ngx_mp4_set_32value(entry->count, count - rest); |
2084 data->pos = (u_char *) entry; | 2163 data->pos = (u_char *) entry; |
2164 trak->time_to_sample_entries = entries; | |
2165 trak->start_sample = start_sample; | |
2166 | |
2167 } else { | |
2168 ngx_mp4_set_32value(entry->count, rest); | |
2169 data->last = (u_char *) (entry + 1); | |
2170 trak->time_to_sample_entries -= entries - 1; | |
2171 trak->end_sample = trak->start_sample + start_sample; | |
2172 } | |
2085 | 2173 |
2086 return NGX_OK; | 2174 return NGX_OK; |
2087 } | 2175 } |
2088 | 2176 |
2089 | 2177 |
2180 | 2268 |
2181 if (data == NULL) { | 2269 if (data == NULL) { |
2182 return NGX_OK; | 2270 return NGX_OK; |
2183 } | 2271 } |
2184 | 2272 |
2185 ngx_http_mp4_crop_stss_data(mp4, trak); | 2273 ngx_http_mp4_crop_stss_data(mp4, trak, 1); |
2274 ngx_http_mp4_crop_stss_data(mp4, trak, 0); | |
2186 | 2275 |
2187 entry = (uint32_t *) data->pos; | 2276 entry = (uint32_t *) data->pos; |
2188 end = (uint32_t *) data->last; | 2277 end = (uint32_t *) data->last; |
2189 | 2278 |
2190 start_sample = trak->start_sample; | 2279 start_sample = trak->start_sample; |
2209 } | 2298 } |
2210 | 2299 |
2211 | 2300 |
2212 static void | 2301 static void |
2213 ngx_http_mp4_crop_stss_data(ngx_http_mp4_file_t *mp4, | 2302 ngx_http_mp4_crop_stss_data(ngx_http_mp4_file_t *mp4, |
2214 ngx_http_mp4_trak_t *trak) | 2303 ngx_http_mp4_trak_t *trak, ngx_uint_t start) |
2215 { | 2304 { |
2216 uint32_t sample, start_sample, *entry, *end; | 2305 uint32_t sample, start_sample, *entry, *end; |
2217 ngx_buf_t *data; | 2306 ngx_buf_t *data; |
2218 ngx_uint_t entries; | 2307 ngx_uint_t entries; |
2219 | 2308 |
2309 /* sync samples starts from 1 */ | |
2310 | |
2311 if (start) { | |
2312 start_sample = trak->start_sample + 1; | |
2313 | |
2314 } else if (mp4->length) { | |
2315 start_sample = trak->end_sample + 1; | |
2316 | |
2317 } else { | |
2318 return; | |
2319 } | |
2320 | |
2220 data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf; | 2321 data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf; |
2221 | 2322 |
2222 /* sync samples starts from 1 */ | |
2223 start_sample = trak->start_sample + 1; | |
2224 entries = trak->sync_samples_entries; | 2323 entries = trak->sync_samples_entries; |
2225 | |
2226 entry = (uint32_t *) data->pos; | 2324 entry = (uint32_t *) data->pos; |
2227 end = (uint32_t *) data->last; | 2325 end = (uint32_t *) data->last; |
2228 | 2326 |
2229 while (entry < end) { | 2327 while (entry < end) { |
2230 sample = ngx_mp4_get_32value(entry); | 2328 sample = ngx_mp4_get_32value(entry); |
2243 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | 2341 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
2244 "start sample is out of mp4 stss atom"); | 2342 "start sample is out of mp4 stss atom"); |
2245 | 2343 |
2246 found: | 2344 found: |
2247 | 2345 |
2248 data->pos = (u_char *) entry; | 2346 if (start) { |
2249 trak->sync_samples_entries = entries; | 2347 data->pos = (u_char *) entry; |
2348 trak->sync_samples_entries = entries; | |
2349 | |
2350 } else { | |
2351 data->last = (u_char *) entry; | |
2352 trak->sync_samples_entries -= entries; | |
2353 } | |
2250 } | 2354 } |
2251 | 2355 |
2252 | 2356 |
2253 typedef struct { | 2357 typedef struct { |
2254 u_char size[4]; | 2358 u_char size[4]; |
2347 | 2451 |
2348 if (data == NULL) { | 2452 if (data == NULL) { |
2349 return; | 2453 return; |
2350 } | 2454 } |
2351 | 2455 |
2352 ngx_http_mp4_crop_ctts_data(mp4, trak); | 2456 ngx_http_mp4_crop_ctts_data(mp4, trak, 1); |
2457 ngx_http_mp4_crop_ctts_data(mp4, trak, 0); | |
2353 | 2458 |
2354 if (trak->composition_offset_entries == 0) { | 2459 if (trak->composition_offset_entries == 0) { |
2355 trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = NULL; | 2460 trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = NULL; |
2356 trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = NULL; | 2461 trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = NULL; |
2357 return; | 2462 return; |
2370 } | 2475 } |
2371 | 2476 |
2372 | 2477 |
2373 static void | 2478 static void |
2374 ngx_http_mp4_crop_ctts_data(ngx_http_mp4_file_t *mp4, | 2479 ngx_http_mp4_crop_ctts_data(ngx_http_mp4_file_t *mp4, |
2375 ngx_http_mp4_trak_t *trak) | 2480 ngx_http_mp4_trak_t *trak, ngx_uint_t start) |
2376 { | 2481 { |
2377 uint32_t count, start_sample; | 2482 uint32_t count, start_sample, rest; |
2378 ngx_buf_t *data; | 2483 ngx_buf_t *data; |
2379 ngx_uint_t entries; | 2484 ngx_uint_t entries; |
2380 ngx_mp4_ctts_entry_t *entry, *end; | 2485 ngx_mp4_ctts_entry_t *entry, *end; |
2381 | 2486 |
2487 /* sync samples starts from 1 */ | |
2488 | |
2489 if (start) { | |
2490 start_sample = trak->start_sample + 1; | |
2491 | |
2492 } else if (mp4->length) { | |
2493 start_sample = trak->end_sample - trak->start_sample + 1; | |
2494 | |
2495 } else { | |
2496 return; | |
2497 } | |
2498 | |
2382 data = trak->out[NGX_HTTP_MP4_CTTS_DATA].buf; | 2499 data = trak->out[NGX_HTTP_MP4_CTTS_DATA].buf; |
2383 | 2500 |
2384 /* sync samples starts from 1 */ | |
2385 start_sample = trak->start_sample + 1; | |
2386 entries = trak->composition_offset_entries; | 2501 entries = trak->composition_offset_entries; |
2387 entry = (ngx_mp4_ctts_entry_t *) data->pos; | 2502 entry = (ngx_mp4_ctts_entry_t *) data->pos; |
2388 end = (ngx_mp4_ctts_entry_t *) data->last; | 2503 end = (ngx_mp4_ctts_entry_t *) data->last; |
2389 | 2504 |
2390 while (entry < end) { | 2505 while (entry < end) { |
2393 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | 2508 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
2394 "start:%uD, count:%uD, offset:%uD", | 2509 "start:%uD, count:%uD, offset:%uD", |
2395 start_sample, count, ngx_mp4_get_32value(entry->offset)); | 2510 start_sample, count, ngx_mp4_get_32value(entry->offset)); |
2396 | 2511 |
2397 if (start_sample <= count) { | 2512 if (start_sample <= count) { |
2398 count -= (start_sample - 1); | 2513 rest = start_sample - 1; |
2399 ngx_mp4_set_32value(entry->count, count); | |
2400 goto found; | 2514 goto found; |
2401 } | 2515 } |
2402 | 2516 |
2403 start_sample -= count; | 2517 start_sample -= count; |
2404 entries--; | 2518 entries--; |
2405 entry++; | 2519 entry++; |
2406 } | 2520 } |
2407 | 2521 |
2408 data->pos = (u_char *) end; | 2522 if (start) { |
2409 trak->composition_offset_entries = 0; | 2523 data->pos = (u_char *) end; |
2524 trak->composition_offset_entries = 0; | |
2525 } | |
2410 | 2526 |
2411 return; | 2527 return; |
2412 | 2528 |
2413 found: | 2529 found: |
2414 | 2530 |
2415 data->pos = (u_char *) entry; | 2531 if (start) { |
2416 trak->composition_offset_entries = entries; | 2532 ngx_mp4_set_32value(entry->count, count - rest); |
2533 data->pos = (u_char *) entry; | |
2534 trak->composition_offset_entries = entries; | |
2535 | |
2536 } else { | |
2537 ngx_mp4_set_32value(entry->count, rest); | |
2538 data->last = (u_char *) (entry + 1); | |
2539 trak->composition_offset_entries -= entries - 1; | |
2540 } | |
2417 } | 2541 } |
2418 | 2542 |
2419 | 2543 |
2420 typedef struct { | 2544 typedef struct { |
2421 u_char size[4]; | 2545 u_char size[4]; |
2520 "zero number of entries in stsc atom in \"%s\"", | 2644 "zero number of entries in stsc atom in \"%s\"", |
2521 mp4->file.name.data); | 2645 mp4->file.name.data); |
2522 return NGX_ERROR; | 2646 return NGX_ERROR; |
2523 } | 2647 } |
2524 | 2648 |
2525 if (ngx_http_mp4_crop_stsc_data(mp4, trak) != NGX_OK) { | 2649 if (ngx_http_mp4_crop_stsc_data(mp4, trak, 1) != NGX_OK) { |
2650 return NGX_ERROR; | |
2651 } | |
2652 | |
2653 if (ngx_http_mp4_crop_stsc_data(mp4, trak, 0) != NGX_OK) { | |
2526 return NGX_ERROR; | 2654 return NGX_ERROR; |
2527 } | 2655 } |
2528 | 2656 |
2529 entry = (ngx_mp4_stsc_entry_t *) data->pos; | 2657 entry = (ngx_mp4_stsc_entry_t *) data->pos; |
2530 end = (ngx_mp4_stsc_entry_t *) data->last; | 2658 end = (ngx_mp4_stsc_entry_t *) data->last; |
2551 } | 2679 } |
2552 | 2680 |
2553 | 2681 |
2554 static ngx_int_t | 2682 static ngx_int_t |
2555 ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4, | 2683 ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4, |
2556 ngx_http_mp4_trak_t *trak) | 2684 ngx_http_mp4_trak_t *trak, ngx_uint_t start) |
2557 { | 2685 { |
2558 uint32_t start_sample, chunk, samples, id, next_chunk, n; | 2686 uint32_t start_sample, chunk, samples, id, next_chunk, n, |
2687 prev_samples; | |
2559 ngx_buf_t *data, *buf; | 2688 ngx_buf_t *data, *buf; |
2560 ngx_uint_t entries, target_chunk, chunk_samples; | 2689 ngx_uint_t entries, target_chunk, chunk_samples; |
2561 ngx_mp4_stsc_entry_t *entry, *end, *first; | 2690 ngx_mp4_stsc_entry_t *entry, *end, *first; |
2562 | 2691 |
2692 entries = trak->sample_to_chunk_entries - 1; | |
2693 | |
2694 if (start) { | |
2695 start_sample = (uint32_t) trak->start_sample; | |
2696 | |
2697 } else if (mp4->length) { | |
2698 start_sample = (uint32_t) (trak->end_sample - trak->start_sample); | |
2699 | |
2700 data = trak->out[NGX_HTTP_MP4_STSC_START].buf; | |
2701 | |
2702 if (data) { | |
2703 entry = (ngx_mp4_stsc_entry_t *) data->pos; | |
2704 samples = ngx_mp4_get_32value(entry->samples); | |
2705 entries--; | |
2706 | |
2707 if (samples > start_sample) { | |
2708 samples = start_sample; | |
2709 ngx_mp4_set_32value(entry->samples, samples); | |
2710 } | |
2711 | |
2712 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2713 "mp4 stsc using %uD start samples", samples); | |
2714 | |
2715 start_sample -= samples; | |
2716 } | |
2717 | |
2718 } else { | |
2719 return NGX_OK; | |
2720 } | |
2721 | |
2563 data = trak->out[NGX_HTTP_MP4_STSC_DATA].buf; | 2722 data = trak->out[NGX_HTTP_MP4_STSC_DATA].buf; |
2564 | |
2565 start_sample = (uint32_t) trak->start_sample; | |
2566 entries = trak->sample_to_chunk_entries - 1; | |
2567 | 2723 |
2568 entry = (ngx_mp4_stsc_entry_t *) data->pos; | 2724 entry = (ngx_mp4_stsc_entry_t *) data->pos; |
2569 end = (ngx_mp4_stsc_entry_t *) data->last; | 2725 end = (ngx_mp4_stsc_entry_t *) data->last; |
2570 | 2726 |
2571 chunk = ngx_mp4_get_32value(entry->chunk); | 2727 chunk = ngx_mp4_get_32value(entry->chunk); |
2572 samples = ngx_mp4_get_32value(entry->samples); | 2728 samples = ngx_mp4_get_32value(entry->samples); |
2573 id = ngx_mp4_get_32value(entry->id); | 2729 id = ngx_mp4_get_32value(entry->id); |
2730 prev_samples = 0; | |
2574 entry++; | 2731 entry++; |
2575 | 2732 |
2576 while (entry < end) { | 2733 while (entry < end) { |
2577 | 2734 |
2578 next_chunk = ngx_mp4_get_32value(entry->chunk); | 2735 next_chunk = ngx_mp4_get_32value(entry->chunk); |
2588 goto found; | 2745 goto found; |
2589 } | 2746 } |
2590 | 2747 |
2591 start_sample -= n; | 2748 start_sample -= n; |
2592 | 2749 |
2750 prev_samples = samples; | |
2593 chunk = next_chunk; | 2751 chunk = next_chunk; |
2594 samples = ngx_mp4_get_32value(entry->samples); | 2752 samples = ngx_mp4_get_32value(entry->samples); |
2595 id = ngx_mp4_get_32value(entry->id); | 2753 id = ngx_mp4_get_32value(entry->id); |
2596 entries--; | 2754 entries--; |
2597 entry++; | 2755 entry++; |
2630 | 2788 |
2631 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | 2789 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
2632 "start chunk:%ui, samples:%uD", | 2790 "start chunk:%ui, samples:%uD", |
2633 target_chunk, chunk_samples); | 2791 target_chunk, chunk_samples); |
2634 | 2792 |
2635 data->pos = (u_char *) entry; | 2793 if (start) { |
2636 | 2794 data->pos = (u_char *) entry; |
2637 trak->start_chunk = target_chunk; | 2795 |
2638 trak->chunk_samples = chunk_samples; | 2796 trak->sample_to_chunk_entries = entries; |
2639 | 2797 trak->start_chunk = target_chunk; |
2640 ngx_mp4_set_32value(entry->chunk, trak->start_chunk + 1); | 2798 trak->start_chunk_samples = chunk_samples; |
2641 | 2799 |
2642 samples -= chunk_samples; | 2800 ngx_mp4_set_32value(entry->chunk, trak->start_chunk + 1); |
2801 | |
2802 samples -= chunk_samples; | |
2803 | |
2804 } else { | |
2805 if (start_sample) { | |
2806 data->last = (u_char *) (entry + 1); | |
2807 trak->sample_to_chunk_entries -= entries - 1; | |
2808 trak->end_chunk_samples = samples; | |
2809 | |
2810 } else { | |
2811 data->last = (u_char *) entry; | |
2812 trak->sample_to_chunk_entries -= entries; | |
2813 trak->end_chunk_samples = prev_samples; | |
2814 } | |
2815 | |
2816 if (chunk_samples) { | |
2817 trak->end_chunk = target_chunk + 1; | |
2818 trak->end_chunk_samples = chunk_samples; | |
2819 | |
2820 } else { | |
2821 trak->end_chunk = target_chunk; | |
2822 } | |
2823 | |
2824 samples = chunk_samples; | |
2825 next_chunk = chunk + 1; | |
2826 } | |
2643 | 2827 |
2644 if (chunk_samples && next_chunk - target_chunk == 2) { | 2828 if (chunk_samples && next_chunk - target_chunk == 2) { |
2645 | 2829 |
2646 ngx_mp4_set_32value(entry->samples, samples); | 2830 ngx_mp4_set_32value(entry->samples, samples); |
2647 | 2831 |
2648 } else if (chunk_samples) { | 2832 } else if (chunk_samples && start) { |
2649 | 2833 |
2650 first = &trak->stsc_chunk_entry; | 2834 first = &trak->stsc_start_chunk_entry; |
2651 ngx_mp4_set_32value(first->chunk, 1); | 2835 ngx_mp4_set_32value(first->chunk, 1); |
2652 ngx_mp4_set_32value(first->samples, samples); | 2836 ngx_mp4_set_32value(first->samples, samples); |
2653 ngx_mp4_set_32value(first->id, id); | 2837 ngx_mp4_set_32value(first->id, id); |
2654 | 2838 |
2655 buf = &trak->stsc_chunk_buf; | 2839 buf = &trak->stsc_start_chunk_buf; |
2656 buf->temporary = 1; | 2840 buf->temporary = 1; |
2657 buf->pos = (u_char *) first; | 2841 buf->pos = (u_char *) first; |
2658 buf->last = (u_char *) first + sizeof(ngx_mp4_stsc_entry_t); | 2842 buf->last = (u_char *) first + sizeof(ngx_mp4_stsc_entry_t); |
2659 | 2843 |
2660 trak->out[NGX_HTTP_MP4_STSC_CHUNK].buf = buf; | 2844 trak->out[NGX_HTTP_MP4_STSC_START].buf = buf; |
2661 | 2845 |
2662 ngx_mp4_set_32value(entry->chunk, trak->start_chunk + 2); | 2846 ngx_mp4_set_32value(entry->chunk, trak->start_chunk + 2); |
2663 | 2847 |
2664 entries++; | 2848 trak->sample_to_chunk_entries++; |
2665 } | 2849 |
2666 | 2850 } else if (chunk_samples) { |
2667 trak->sample_to_chunk_entries = entries; | 2851 |
2852 first = &trak->stsc_end_chunk_entry; | |
2853 ngx_mp4_set_32value(first->chunk, trak->end_chunk - trak->start_chunk); | |
2854 ngx_mp4_set_32value(first->samples, samples); | |
2855 ngx_mp4_set_32value(first->id, id); | |
2856 | |
2857 buf = &trak->stsc_end_chunk_buf; | |
2858 buf->temporary = 1; | |
2859 buf->pos = (u_char *) first; | |
2860 buf->last = (u_char *) first + sizeof(ngx_mp4_stsc_entry_t); | |
2861 | |
2862 trak->out[NGX_HTTP_MP4_STSC_END].buf = buf; | |
2863 | |
2864 trak->sample_to_chunk_entries++; | |
2865 } | |
2668 | 2866 |
2669 return NGX_OK; | 2867 return NGX_OK; |
2670 } | 2868 } |
2671 | 2869 |
2672 | 2870 |
2758 static ngx_int_t | 2956 static ngx_int_t |
2759 ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4, | 2957 ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4, |
2760 ngx_http_mp4_trak_t *trak) | 2958 ngx_http_mp4_trak_t *trak) |
2761 { | 2959 { |
2762 size_t atom_size; | 2960 size_t atom_size; |
2763 uint32_t *pos, *end; | 2961 uint32_t *pos, *end, entries; |
2764 ngx_buf_t *atom, *data; | 2962 ngx_buf_t *atom, *data; |
2765 ngx_mp4_stsz_atom_t *stsz_atom; | 2963 ngx_mp4_stsz_atom_t *stsz_atom; |
2766 | 2964 |
2767 /* | 2965 /* |
2768 * mdia.minf.stbl.stsz updating requires trak->start_sample | 2966 * mdia.minf.stbl.stsz updating requires trak->start_sample |
2774 "mp4 stsz atom update"); | 2972 "mp4 stsz atom update"); |
2775 | 2973 |
2776 data = trak->out[NGX_HTTP_MP4_STSZ_DATA].buf; | 2974 data = trak->out[NGX_HTTP_MP4_STSZ_DATA].buf; |
2777 | 2975 |
2778 if (data) { | 2976 if (data) { |
2779 if (trak->start_sample > trak->sample_sizes_entries) { | 2977 entries = trak->sample_sizes_entries; |
2978 | |
2979 if (trak->start_sample > entries) { | |
2780 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | 2980 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
2781 "start time is out mp4 stsz samples in \"%s\"", | 2981 "start time is out mp4 stsz samples in \"%s\"", |
2782 mp4->file.name.data); | 2982 mp4->file.name.data); |
2783 return NGX_ERROR; | 2983 return NGX_ERROR; |
2784 } | 2984 } |
2785 | 2985 |
2986 entries -= trak->start_sample; | |
2786 data->pos += trak->start_sample * sizeof(uint32_t); | 2987 data->pos += trak->start_sample * sizeof(uint32_t); |
2787 end = (uint32_t *) data->pos; | 2988 end = (uint32_t *) data->pos; |
2788 | 2989 |
2789 for (pos = end - trak->chunk_samples; pos < end; pos++) { | 2990 for (pos = end - trak->start_chunk_samples; pos < end; pos++) { |
2790 trak->chunk_samples_size += ngx_mp4_get_32value(pos); | 2991 trak->start_chunk_samples_size += ngx_mp4_get_32value(pos); |
2791 } | 2992 } |
2792 | 2993 |
2793 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | 2994 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
2794 "chunk samples sizes:%uL", trak->chunk_samples_size); | 2995 "chunk samples sizes:%uL", |
2996 trak->start_chunk_samples_size); | |
2997 | |
2998 if (mp4->length) { | |
2999 if (trak->end_sample - trak->start_sample > entries) { | |
3000 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
3001 "end time is out mp4 stsz samples in \"%s\"", | |
3002 mp4->file.name.data); | |
3003 return NGX_ERROR; | |
3004 } | |
3005 | |
3006 entries = trak->end_sample - trak->start_sample; | |
3007 data->last = data->pos + entries * sizeof(uint32_t); | |
3008 end = (uint32_t *) data->last; | |
3009 | |
3010 for (pos = end - trak->end_chunk_samples; pos < end; pos++) { | |
3011 trak->end_chunk_samples_size += ngx_mp4_get_32value(pos); | |
3012 } | |
3013 | |
3014 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
3015 "mp4 stsz end_chunk_samples_size:%uL", | |
3016 trak->end_chunk_samples_size); | |
3017 } | |
2795 | 3018 |
2796 atom_size = sizeof(ngx_mp4_stsz_atom_t) + (data->last - data->pos); | 3019 atom_size = sizeof(ngx_mp4_stsz_atom_t) + (data->last - data->pos); |
2797 trak->size += atom_size; | 3020 trak->size += atom_size; |
2798 | 3021 |
2799 atom = trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf; | 3022 atom = trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf; |
2800 stsz_atom = (ngx_mp4_stsz_atom_t *) atom->pos; | 3023 stsz_atom = (ngx_mp4_stsz_atom_t *) atom->pos; |
2801 | 3024 |
2802 ngx_mp4_set_32value(stsz_atom->size, atom_size); | 3025 ngx_mp4_set_32value(stsz_atom->size, atom_size); |
2803 ngx_mp4_set_32value(stsz_atom->entries, | 3026 ngx_mp4_set_32value(stsz_atom->entries, entries); |
2804 trak->sample_sizes_entries - trak->start_sample); | |
2805 } | 3027 } |
2806 | 3028 |
2807 return NGX_OK; | 3029 return NGX_OK; |
2808 } | 3030 } |
2809 | 3031 |
2880 static ngx_int_t | 3102 static ngx_int_t |
2881 ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4, | 3103 ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4, |
2882 ngx_http_mp4_trak_t *trak) | 3104 ngx_http_mp4_trak_t *trak) |
2883 { | 3105 { |
2884 size_t atom_size; | 3106 size_t atom_size; |
3107 uint32_t entries; | |
2885 ngx_buf_t *atom, *data; | 3108 ngx_buf_t *atom, *data; |
2886 ngx_mp4_stco_atom_t *stco_atom; | 3109 ngx_mp4_stco_atom_t *stco_atom; |
2887 | 3110 |
2888 /* | 3111 /* |
2889 * mdia.minf.stbl.stco updating requires trak->start_chunk | 3112 * mdia.minf.stbl.stco updating requires trak->start_chunk |
2909 mp4->file.name.data); | 3132 mp4->file.name.data); |
2910 return NGX_ERROR; | 3133 return NGX_ERROR; |
2911 } | 3134 } |
2912 | 3135 |
2913 data->pos += trak->start_chunk * sizeof(uint32_t); | 3136 data->pos += trak->start_chunk * sizeof(uint32_t); |
3137 | |
3138 trak->start_offset = ngx_mp4_get_32value(data->pos); | |
3139 trak->start_offset += trak->start_chunk_samples_size; | |
3140 ngx_mp4_set_32value(data->pos, trak->start_offset); | |
3141 | |
3142 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
3143 "start chunk offset:%uD", trak->start_offset); | |
3144 | |
3145 if (mp4->length) { | |
3146 | |
3147 if (trak->end_chunk > trak->chunks) { | |
3148 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
3149 "end time is out mp4 stco chunks in \"%s\"", | |
3150 mp4->file.name.data); | |
3151 return NGX_ERROR; | |
3152 } | |
3153 | |
3154 entries = trak->end_chunk - trak->start_chunk; | |
3155 data->last = data->pos + entries * sizeof(uint32_t); | |
3156 | |
3157 if (entries) { | |
3158 trak->end_offset = | |
3159 ngx_mp4_get_32value(data->last - sizeof(uint32_t)); | |
3160 trak->end_offset += trak->end_chunk_samples_size; | |
3161 | |
3162 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
3163 "end chunk offset:%O", trak->end_offset); | |
3164 } | |
3165 | |
3166 } else { | |
3167 entries = trak->chunks - trak->start_chunk; | |
3168 trak->end_offset = mp4->mdat_data.buf->file_last; | |
3169 } | |
3170 | |
3171 if (entries == 0) { | |
3172 trak->start_offset = mp4->end; | |
3173 trak->end_offset = 0; | |
3174 } | |
3175 | |
2914 atom_size = sizeof(ngx_mp4_stco_atom_t) + (data->last - data->pos); | 3176 atom_size = sizeof(ngx_mp4_stco_atom_t) + (data->last - data->pos); |
2915 trak->size += atom_size; | 3177 trak->size += atom_size; |
2916 | 3178 |
2917 trak->start_offset = ngx_mp4_get_32value(data->pos); | |
2918 trak->start_offset += trak->chunk_samples_size; | |
2919 ngx_mp4_set_32value(data->pos, trak->start_offset); | |
2920 | |
2921 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2922 "start chunk offset:%uD", trak->start_offset); | |
2923 | |
2924 atom = trak->out[NGX_HTTP_MP4_STCO_ATOM].buf; | 3179 atom = trak->out[NGX_HTTP_MP4_STCO_ATOM].buf; |
2925 stco_atom = (ngx_mp4_stco_atom_t *) atom->pos; | 3180 stco_atom = (ngx_mp4_stco_atom_t *) atom->pos; |
2926 | 3181 |
2927 ngx_mp4_set_32value(stco_atom->size, atom_size); | 3182 ngx_mp4_set_32value(stco_atom->size, atom_size); |
2928 ngx_mp4_set_32value(stco_atom->entries, trak->chunks - trak->start_chunk); | 3183 ngx_mp4_set_32value(stco_atom->entries, entries); |
2929 | 3184 |
2930 return NGX_OK; | 3185 return NGX_OK; |
2931 } | 3186 } |
2932 | 3187 |
2933 | 3188 |
3031 static ngx_int_t | 3286 static ngx_int_t |
3032 ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4, | 3287 ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4, |
3033 ngx_http_mp4_trak_t *trak) | 3288 ngx_http_mp4_trak_t *trak) |
3034 { | 3289 { |
3035 size_t atom_size; | 3290 size_t atom_size; |
3291 uint64_t entries; | |
3036 ngx_buf_t *atom, *data; | 3292 ngx_buf_t *atom, *data; |
3037 ngx_mp4_co64_atom_t *co64_atom; | 3293 ngx_mp4_co64_atom_t *co64_atom; |
3038 | 3294 |
3039 /* | 3295 /* |
3040 * mdia.minf.stbl.co64 updating requires trak->start_chunk | 3296 * mdia.minf.stbl.co64 updating requires trak->start_chunk |
3060 mp4->file.name.data); | 3316 mp4->file.name.data); |
3061 return NGX_ERROR; | 3317 return NGX_ERROR; |
3062 } | 3318 } |
3063 | 3319 |
3064 data->pos += trak->start_chunk * sizeof(uint64_t); | 3320 data->pos += trak->start_chunk * sizeof(uint64_t); |
3321 | |
3322 trak->start_offset = ngx_mp4_get_64value(data->pos); | |
3323 trak->start_offset += trak->start_chunk_samples_size; | |
3324 ngx_mp4_set_64value(data->pos, trak->start_offset); | |
3325 | |
3326 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
3327 "start chunk offset:%uL", trak->start_offset); | |
3328 | |
3329 if (mp4->length) { | |
3330 | |
3331 if (trak->end_chunk > trak->chunks) { | |
3332 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
3333 "end time is out mp4 co64 chunks in \"%s\"", | |
3334 mp4->file.name.data); | |
3335 return NGX_ERROR; | |
3336 } | |
3337 | |
3338 entries = trak->end_chunk - trak->start_chunk; | |
3339 data->last = data->pos + entries * sizeof(uint64_t); | |
3340 | |
3341 if (entries) { | |
3342 trak->end_offset = | |
3343 ngx_mp4_get_64value(data->last - sizeof(uint64_t)); | |
3344 trak->end_offset += trak->end_chunk_samples_size; | |
3345 | |
3346 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
3347 "end chunk offset:%O", trak->end_offset); | |
3348 } | |
3349 | |
3350 } else { | |
3351 entries = trak->chunks - trak->start_chunk; | |
3352 trak->end_offset = mp4->mdat_data.buf->file_last; | |
3353 } | |
3354 | |
3355 if (entries == 0) { | |
3356 trak->start_offset = mp4->end; | |
3357 trak->end_offset = 0; | |
3358 } | |
3359 | |
3065 atom_size = sizeof(ngx_mp4_co64_atom_t) + (data->last - data->pos); | 3360 atom_size = sizeof(ngx_mp4_co64_atom_t) + (data->last - data->pos); |
3066 trak->size += atom_size; | 3361 trak->size += atom_size; |
3067 | 3362 |
3068 trak->start_offset = ngx_mp4_get_64value(data->pos); | |
3069 trak->start_offset += trak->chunk_samples_size; | |
3070 ngx_mp4_set_64value(data->pos, trak->start_offset); | |
3071 | |
3072 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
3073 "start chunk offset:%uL", trak->start_offset); | |
3074 | |
3075 atom = trak->out[NGX_HTTP_MP4_CO64_ATOM].buf; | 3363 atom = trak->out[NGX_HTTP_MP4_CO64_ATOM].buf; |
3076 co64_atom = (ngx_mp4_co64_atom_t *) atom->pos; | 3364 co64_atom = (ngx_mp4_co64_atom_t *) atom->pos; |
3077 | 3365 |
3078 ngx_mp4_set_32value(co64_atom->size, atom_size); | 3366 ngx_mp4_set_32value(co64_atom->size, atom_size); |
3079 ngx_mp4_set_32value(co64_atom->entries, trak->chunks - trak->start_chunk); | 3367 ngx_mp4_set_32value(co64_atom->entries, entries); |
3080 | 3368 |
3081 return NGX_OK; | 3369 return NGX_OK; |
3082 } | 3370 } |
3083 | 3371 |
3084 | 3372 |