]> git.pld-linux.org Git - packages/lighttpd.git/blob - lighttpd-mod_h264_streaming.patch
- patch against 1.4.18 and http://h264.code-shop.com/svn/h264 @20
[packages/lighttpd.git] / lighttpd-mod_h264_streaming.patch
1 diff -ur -x '*.m4' -x ltmain.sh -x install-sh -x depcomp -x Makefile.in -x compile -x 'config.*' -x configure -x missing -x mkinstalldirs -x autom4te.cache -Nur -x .svn lighttpd-1.4.18/src/Makefile.am lighttpd-mod_h264_streaming-1.4.18/src/Makefile.am
2 --- lighttpd-1.4.18/src/Makefile.am     2007-09-03 01:23:53.000000000 +0300
3 +++ lighttpd-mod_h264_streaming-1.4.18/src/Makefile.am  2007-10-23 23:42:37.736979478 +0300
4 @@ -77,6 +77,11 @@
5  mod_flv_streaming_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
6  mod_flv_streaming_la_LIBADD = $(common_libadd)
7  
8 +lib_LTLIBRARIES += mod_h264_streaming.la
9 +mod_h264_streaming_la_SOURCES = mod_h264_streaming.c moov.c
10 +mod_h264_streaming_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
11 +mod_h264_streaming_la_LIBADD = $(common_libadd)
12 +
13  lib_LTLIBRARIES += mod_evasive.la
14  mod_evasive_la_SOURCES = mod_evasive.c
15  mod_evasive_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
16 diff -ur -x '*.m4' -x ltmain.sh -x install-sh -x depcomp -x Makefile.in -x compile -x 'config.*' -x configure -x missing -x mkinstalldirs -x autom4te.cache -Nur -x .svn lighttpd-1.4.18/src/mod_h264_streaming.c lighttpd-mod_h264_streaming-1.4.18/src/mod_h264_streaming.c
17 --- lighttpd-1.4.18/src/mod_h264_streaming.c    1970-01-01 03:00:00.000000000 +0300
18 +++ lighttpd-mod_h264_streaming-1.4.18/src/mod_h264_streaming.c 2007-10-23 23:42:37.696978564 +0300
19 @@ -0,0 +1,467 @@
20 +/*******************************************************************************
21 + mod_h264_streaming.c
22 +
23 + mod_h264_streaming - A lighttpd plugin for pseudo-streaming Quicktime/MPEG4 files.
24 + http://h264.code-shop.com
25 +
26 + Copyright (C) 2007 CodeShop B.V.
27 +
28 + This program is free software: you can redistribute it and/or modify
29 + it under the terms of the GNU General Public License as published by
30 + the Free Software Foundation, either version 3 of the License, or
31 + (at your option) any later version.
32 +
33 + This program is distributed in the hope that it will be useful,
34 + but WITHOUT ANY WARRANTY; without even the implied warranty of
35 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36 + GNU General Public License for more details.
37 +
38 + You should have received a copy of the GNU General Public License
39 + along with this program.  If not, see <http://www.gnu.org/licenses/>.
40 +******************************************************************************/ 
41 +
42 +#include <ctype.h>
43 +#include <stdlib.h>
44 +#include <string.h>
45 +#include <stdio.h>
46 +
47 +#include "base.h"
48 +#include "log.h"
49 +#include "buffer.h"
50 +#include "response.h"
51 +#include "http_chunk.h"
52 +#include "stat_cache.h"
53 +
54 +#include "plugin.h"
55 +
56 +#ifdef HAVE_CONFIG_H
57 +#include "config.h"
58 +#endif
59 +
60 +/* plugin config for all request/connections */
61 +
62 +typedef struct {
63 +       array *extensions;
64 +} plugin_config;
65 +
66 +typedef struct {
67 +       PLUGIN_DATA;
68 +
69 +       buffer *query_str;
70 +       array *get_params;
71 +
72 +       plugin_config **config_storage;
73 +
74 +       plugin_config conf;
75 +} plugin_data;
76 +
77 +/* init the plugin data */
78 +INIT_FUNC(mod_h264_streaming_init) {
79 +       plugin_data *p;
80 +
81 +       p = calloc(1, sizeof(*p));
82 +
83 +       p->query_str = buffer_init();
84 +       p->get_params = array_init();
85 +
86 +       return p;
87 +}
88 +
89 +/* detroy the plugin data */
90 +FREE_FUNC(mod_h264_streaming_free) {
91 +       plugin_data *p = p_d;
92 +
93 +       UNUSED(srv);
94 +
95 +       if (!p) return HANDLER_GO_ON;
96 +
97 +       if (p->config_storage) {
98 +               size_t i;
99 +
100 +               for (i = 0; i < srv->config_context->used; i++) {
101 +                       plugin_config *s = p->config_storage[i];
102 +
103 +                       if (!s) continue;
104 +
105 +                       array_free(s->extensions);
106 +
107 +                       free(s);
108 +               }
109 +               free(p->config_storage);
110 +       }
111 +
112 +       buffer_free(p->query_str);
113 +       array_free(p->get_params);
114 +
115 +       free(p);
116 +
117 +       return HANDLER_GO_ON;
118 +}
119 +
120 +/* handle plugin config and check values */
121 +
122 +SETDEFAULTS_FUNC(mod_h264_streaming_set_defaults) {
123 +       plugin_data *p = p_d;
124 +       size_t i = 0;
125 +
126 +       config_values_t cv[] = {
127 +               { "h264-streaming.extensions",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
128 +               { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
129 +       };
130 +
131 +       if (!p) return HANDLER_ERROR;
132 +
133 +       p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
134 +
135 +       for (i = 0; i < srv->config_context->used; i++) {
136 +               plugin_config *s;
137 +
138 +               s = calloc(1, sizeof(plugin_config));
139 +               s->extensions     = array_init();
140 +
141 +               cv[0].destination = s->extensions;
142 +
143 +               p->config_storage[i] = s;
144 +
145 +               if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
146 +                       return HANDLER_ERROR;
147 +               }
148 +       }
149 +
150 +       return HANDLER_GO_ON;
151 +}
152 +
153 +#define PATCH(x) \
154 +       p->conf.x = s->x;
155 +static int mod_h264_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
156 +       size_t i, j;
157 +       plugin_config *s = p->config_storage[0];
158 +
159 +       PATCH(extensions);
160 +
161 +       /* skip the first, the global context */
162 +       for (i = 1; i < srv->config_context->used; i++) {
163 +               data_config *dc = (data_config *)srv->config_context->data[i];
164 +               s = p->config_storage[i];
165 +
166 +               /* condition didn't match */
167 +               if (!config_check_cond(srv, con, dc)) continue;
168 +
169 +               /* merge config */
170 +               for (j = 0; j < dc->value->used; j++) {
171 +                       data_unset *du = dc->value->data[j];
172 +
173 +                       if (buffer_is_equal_string(du->key, CONST_STR_LEN("h264-streaming.extensions"))) {
174 +                               PATCH(extensions);
175 +                       }
176 +               }
177 +       }
178 +
179 +       return 0;
180 +}
181 +#undef PATCH
182 +
183 +static int split_get_params(array *get_params, buffer *qrystr) {
184 +       size_t is_key = 1;
185 +       size_t i;
186 +       char *key = NULL, *val = NULL;
187 +
188 +       key = qrystr->ptr;
189 +
190 +       /* we need the \0 */
191 +       for (i = 0; i < qrystr->used; i++) {
192 +               switch(qrystr->ptr[i]) {
193 +               case '=':
194 +                       if (is_key) {
195 +                               val = qrystr->ptr + i + 1;
196 +
197 +                               qrystr->ptr[i] = '\0';
198 +
199 +                               is_key = 0;
200 +                       }
201 +
202 +                       break;
203 +               case '&':
204 +               case '\0': /* fin symbol */
205 +                       if (!is_key) {
206 +                               data_string *ds;
207 +                               /* we need at least a = since the last & */
208 +
209 +                               /* terminate the value */
210 +                               qrystr->ptr[i] = '\0';
211 +
212 +                               if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) {
213 +                                       ds = data_string_init();
214 +                               }
215 +                               buffer_copy_string_len(ds->key, key, strlen(key));
216 +                               buffer_copy_string_len(ds->value, val, strlen(val));
217 +
218 +                               array_insert_unique(get_params, (data_unset *)ds);
219 +                       }
220 +
221 +                       key = qrystr->ptr + i + 1;
222 +                       val = NULL;
223 +                       is_key = 1;
224 +                       break;
225 +               }
226 +       }
227 +
228 +       return 0;
229 +}
230 +
231 +extern unsigned int moov_seek(unsigned char* moov_data, unsigned int size,
232 +                               float start_time,
233 +                               unsigned int* mdat_start, unsigned int* mdat_size,
234 +                               unsigned int offset);
235 +
236 +void write_char(unsigned char* outbuffer, int value)
237 +{
238 +  outbuffer[0] = (unsigned char)(value);
239 +}
240 +
241 +void write_int32(unsigned char* outbuffer, long value)
242 +{
243 +  outbuffer[0] = (unsigned char)((value >> 24) & 0xff);
244 +  outbuffer[1] = (unsigned char)((value >> 16) & 0xff);
245 +  outbuffer[2] = (unsigned char)((value >> 8) & 0xff);
246 +  outbuffer[3] = (unsigned char)((value >> 0) & 0xff);
247 +}
248 +
249 +struct atom_t
250 +{
251 +  unsigned char type_[4];
252 +  unsigned int size_;
253 +  unsigned int start_;
254 +  unsigned int end_;
255 +};
256 +
257 +#define ATOM_PREAMBLE_SIZE 8
258 +
259 +unsigned int atom_header_size(unsigned char* atom_bytes)
260 +{
261 +  return (atom_bytes[0] << 24) +
262 +         (atom_bytes[1] << 16) +
263 +         (atom_bytes[2] << 8) +
264 +         (atom_bytes[3]);
265 +}
266 +
267 +int atom_read_header(FILE* infile, struct atom_t* atom)
268 +{
269 +  unsigned char atom_bytes[ATOM_PREAMBLE_SIZE];
270 +
271 +  atom->start_ = ftell(infile);
272 +
273 +  fread(atom_bytes, ATOM_PREAMBLE_SIZE, 1, infile);
274 +  memcpy(&atom->type_[0], &atom_bytes[4], 4);
275 +  atom->size_ = atom_header_size(atom_bytes);
276 +  atom->end_ = atom->start_ + atom->size_;
277 +
278 +  return 1;
279 +}
280 +
281 +void atom_write_header(unsigned char* outbuffer, struct atom_t* atom)
282 +{
283 +  int i;
284 +  write_int32(outbuffer, atom->size_);
285 +  for(i = 0; i != 4; ++i)
286 +    write_char(outbuffer + 4 + i, atom->type_[i]);
287 +}
288 +
289 +int atom_is(struct atom_t const* atom, const char* type)
290 +{
291 +  return (atom->type_[0] == type[0] &&
292 +          atom->type_[1] == type[1] &&
293 +          atom->type_[2] == type[2] &&
294 +          atom->type_[3] == type[3])
295 +         ;
296 +}
297 +
298 +void atom_skip(FILE* infile, struct atom_t const* atom)
299 +{
300 +  fseek(infile, atom->end_, SEEK_SET);
301 +}
302 +
303 +void atom_print(struct atom_t const* atom)
304 +{
305 +  printf("Atom(%c%c%c%c,%d)\n", atom->type_[0], atom->type_[1],
306 +          atom->type_[2], atom->type_[3], atom->size_);
307 +}
308 +
309 +
310 +URIHANDLER_FUNC(mod_h264_streaming_path_handler) {
311 +       plugin_data *p = p_d;
312 +       int s_len;
313 +       size_t k;
314 +
315 +       UNUSED(srv);
316 +
317 +       if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
318 +
319 +       mod_h264_streaming_patch_connection(srv, con, p);
320 +
321 +       s_len = con->physical.path->used - 1;
322 +
323 +       for (k = 0; k < p->conf.extensions->used; k++) {
324 +               data_string *ds = (data_string *)p->conf.extensions->data[k];
325 +               int ct_len = ds->value->used - 1;
326 +
327 +               if (ct_len > s_len) continue;
328 +               if (ds->value->used == 0) continue;
329 +
330 +               if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
331 +                       data_string *get_param;
332 +                       stat_cache_entry *sce = NULL;
333 +                       buffer *b;
334 +                       double start;
335 +                       char *err = NULL;
336 +                       /* if there is a start=[0-9]+ in the header use it as start,
337 +                        * otherwise send the full file */
338 +
339 +                       array_reset(p->get_params);
340 +                       buffer_copy_string_buffer(p->query_str, con->uri.query);
341 +                       split_get_params(p->get_params, p->query_str);
342 +
343 +                       if (NULL == (get_param = (data_string *)array_get_element(p->get_params, "start"))) {
344 +                               return HANDLER_GO_ON;
345 +                       }
346 +
347 +                       /* too short */
348 +//                     if (get_param->value->used < 2) return HANDLER_GO_ON;
349 +
350 +                       /* check if it is a number */
351 +//                     start = strtol(get_param->value->ptr, &err, 10);
352 +                       start = strtod(get_param->value->ptr, &err);
353 +                       if (*err != '\0') {
354 +                               return HANDLER_GO_ON;
355 +                       }
356 +
357 +//                     if (start <= 0) return HANDLER_GO_ON;
358 +                       if (start < 0) return HANDLER_GO_ON;
359 +
360 +                       /* check if start is > filesize */
361 +                       if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
362 +                               return HANDLER_GO_ON;
363 +                       }
364 +
365 +//                     if (start > sce->st.st_size) {
366 +//                             return HANDLER_GO_ON;
367 +//                     }
368 +
369 +                       /* we are safe now, let's build a h264 header */
370 +                       b = chunkqueue_get_append_buffer(con->write_queue);
371 +#if 0
372 +                       BUFFER_COPY_STRING_CONST(b, "FLV\x1\x1\0\0\0\x9\0\0\0\x9");
373 +                       http_chunk_append_file(srv, con, con->physical.path, start, sce->st.st_size - start);
374 +#else
375 +                       {
376 +                       FILE* infile;
377 +                       struct atom_t ftyp_atom;
378 +                       struct atom_t moov_atom;
379 +                       struct atom_t mdat_atom;
380 +                       unsigned char* moov_data = 0;
381 +                       unsigned char* ftyp_data = 0;
382 +
383 +                       infile = fopen(con->physical.path->ptr, "rb");
384 +                       if(!infile) {
385 +                               return HANDLER_GO_ON;
386 +                       }
387 +
388 +                       {
389 +                               unsigned int filesize = sce->st.st_size;
390 +
391 +                               struct atom_t leaf_atom;
392 +                               while(ftell(infile) < filesize)
393 +                               {
394 +                                       if(!atom_read_header(infile, &leaf_atom))
395 +                                               break;
396 +
397 +                                       atom_print(&leaf_atom);
398 +
399 +                                       if(atom_is(&leaf_atom, "ftyp"))
400 +                                       {
401 +                                               ftyp_atom = leaf_atom;
402 +                                               ftyp_data = malloc(ftyp_atom.size_);
403 +                                               fseek(infile, ftyp_atom.start_, SEEK_SET);
404 +                                               fread(ftyp_data, ftyp_atom.size_, 1, infile);
405 +                                       }
406 +                                       else
407 +                                       if(atom_is(&leaf_atom, "moov"))
408 +                                       {
409 +                                               moov_atom = leaf_atom;
410 +                                               moov_data = malloc(moov_atom.size_);
411 +                                               fseek(infile, moov_atom.start_, SEEK_SET);
412 +                                               fread(moov_data, moov_atom.size_, 1, infile);
413 +                                       }
414 +                                       else
415 +                                       if(atom_is(&leaf_atom, "mdat"))
416 +                                       {
417 +                                               mdat_atom = leaf_atom;
418 +                                       }
419 +                                       atom_skip(infile, &leaf_atom);
420 +                               }
421 +                       }
422 +                       fclose(infile);
423 +
424 +                       if(!moov_data)
425 +                               return HANDLER_GO_ON;
426 +
427 +                       {
428 +
429 +                       unsigned int mdat_start = (ftyp_data ? ftyp_atom.size_ : 0) + moov_atom.size_;
430 +                       if(!moov_seek(moov_data + ATOM_PREAMBLE_SIZE,
431 +                                       moov_atom.size_ - ATOM_PREAMBLE_SIZE,
432 +                                       start,
433 +                                       &mdat_atom.start_, &mdat_atom.size_,
434 +                                       mdat_start - mdat_atom.start_))
435 +                               return HANDLER_GO_ON;
436 +
437 +                       if(ftyp_data)
438 +                       {
439 +                               buffer_append_memory(b, ftyp_data, ftyp_atom.size_);
440 +                               free(ftyp_data);
441 +                       }
442 +
443 +                       buffer_append_memory(b, moov_data, moov_atom.size_);
444 +                       free(moov_data);
445 +
446 +                       {
447 +                       unsigned char mdat_bytes[ATOM_PREAMBLE_SIZE];
448 +//                     mdat_atom.size_ -= bytes_to_skip;
449 +                       atom_write_header(mdat_bytes, &mdat_atom);
450 +                       buffer_append_memory(b, mdat_bytes, ATOM_PREAMBLE_SIZE);
451 +                       b->used++; /* add virtual \0 */
452 +                       }
453 +
454 +                       http_chunk_append_file(srv, con, con->physical.path, mdat_atom.start_ + ATOM_PREAMBLE_SIZE,
455 +                                               mdat_atom.size_ - ATOM_PREAMBLE_SIZE);
456 +                       }
457 +                       }
458 +#endif
459 +                       response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/mp4"));
460 +
461 +                       con->file_finished = 1;
462 +
463 +                       return HANDLER_FINISHED;
464 +               }
465 +       }
466 +
467 +       /* not found */
468 +       return HANDLER_GO_ON;
469 +}
470 +
471 +/* this function is called at dlopen() time and inits the callbacks */
472 +
473 +int mod_h264_streaming_plugin_init(plugin *p) {
474 +       p->version     = LIGHTTPD_VERSION_ID;
475 +       p->name        = buffer_init_string("h264_streaming");
476 +
477 +       p->init        = mod_h264_streaming_init;
478 +       p->handle_physical = mod_h264_streaming_path_handler;
479 +       p->set_defaults  = mod_h264_streaming_set_defaults;
480 +       p->cleanup     = mod_h264_streaming_free;
481 +
482 +       p->data        = NULL;
483 +
484 +       return 0;
485 +}
486 +
487 diff -ur -x '*.m4' -x ltmain.sh -x install-sh -x depcomp -x Makefile.in -x compile -x 'config.*' -x configure -x missing -x mkinstalldirs -x autom4te.cache -Nur -x .svn lighttpd-1.4.18/src/moov.c lighttpd-mod_h264_streaming-1.4.18/src/moov.c
488 --- lighttpd-1.4.18/src/moov.c  1970-01-01 03:00:00.000000000 +0300
489 +++ lighttpd-mod_h264_streaming-1.4.18/src/moov.c       2007-10-23 23:42:37.776980392 +0300
490 @@ -0,0 +1,1188 @@
491 +/******************************************************************************
492 + moov.c
493 +
494 + moov - A library for splitting Quicktime/MPEG4 files.
495 + http://h264.code-shop.com
496 +
497 + Copyright (C) 2007 CodeShop B.V.
498 +
499 + This program is free software: you can redistribute it and/or modify
500 + it under the terms of the GNU General Public License as published by
501 + the Free Software Foundation, either version 3 of the License, or
502 + (at your option) any later version.
503 +
504 + This program is distributed in the hope that it will be useful,
505 + but WITHOUT ANY WARRANTY; without even the implied warranty of
506 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
507 + GNU General Public License for more details.
508 +
509 + You should have received a copy of the GNU General Public License
510 + along with this program.  If not, see <http://www.gnu.org/licenses/>.
511 +******************************************************************************/ 
512 +
513 +/* 
514 +  Uses code snippets from the libquicktime library:
515 +   http://libquicktime.sourceforge.net
516 +
517 +  The QuickTime File Format PDF from Apple:
518 +    http://developer.apple.com/techpubs/quicktime/qtdevdocs/PDF/QTFileFormat.pdf
519 +*/
520 +
521 +#include <stdlib.h>
522 +#include <stdio.h>
523 +#include <string.h>
524 +#include <limits.h>
525 +#include <inttypes.h>
526 +
527 +static int read_char(unsigned char const* buffer)
528 +{
529 +  return buffer[0];
530 +}
531 +
532 +static int read_int32(void const* buffer)
533 +{
534 +  unsigned char* p = (unsigned char*)buffer;
535 +  return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
536 +}
537 +
538 +static void write_int32(void* outbuffer, uint32_t value)
539 +{
540 +  unsigned char* p = (unsigned char*)outbuffer;
541 +  p[0] = (unsigned char)((value >> 24) & 0xff);
542 +  p[1] = (unsigned char)((value >> 16) & 0xff);
543 +  p[2] = (unsigned char)((value >> 8) & 0xff);
544 +  p[3] = (unsigned char)((value >> 0) & 0xff);
545 +}
546 +
547 +struct atom_t
548 +{
549 +  unsigned char type_[4];
550 +  unsigned int size_;
551 +  unsigned char* start_;
552 +  unsigned char* end_;
553 +};
554 +
555 +#define ATOM_PREAMBLE_SIZE 8
556 +
557 +static unsigned int atom_header_size(unsigned char* atom_bytes)
558 +{
559 +  return (atom_bytes[0] << 24) +
560 +         (atom_bytes[1] << 16) +
561 +         (atom_bytes[2] << 8) +
562 +         (atom_bytes[3]);
563 +}
564 +
565 +static unsigned char* atom_read_header(unsigned char* buffer, struct atom_t* atom)
566 +{
567 +  atom->start_ = buffer;
568 +  memcpy(&atom->type_[0], &buffer[4], 4);
569 +  atom->size_ = atom_header_size(buffer);
570 +  atom->end_ = atom->start_ + atom->size_;
571 +
572 +  return buffer + ATOM_PREAMBLE_SIZE;
573 +}
574 +
575 +static unsigned char* atom_skip(struct atom_t const* atom)
576 +{
577 +  return atom->end_;
578 +}
579 +
580 +static int atom_is(struct atom_t const* atom, const char* type)
581 +{
582 +  return (atom->type_[0] == type[0] &&
583 +          atom->type_[1] == type[1] &&
584 +          atom->type_[2] == type[2] &&
585 +          atom->type_[3] == type[3])
586 +         ;
587 +}
588 +
589 +static void atom_print(struct atom_t const* atom)
590 +{
591 +  printf("Atom(%c%c%c%c,%d)\n", atom->type_[0], atom->type_[1],
592 +          atom->type_[2], atom->type_[3], atom->size_);
593 +}
594 +
595 +#define MAX_TRACKS 8
596 +
597 +unsigned int stts_get_entries(unsigned char const* stts)
598 +{
599 +  return read_int32(stts + 4);
600 +}
601 +
602 +void stts_get_sample_count_and_duration(unsigned char const* stts,
603 +  unsigned int idx, unsigned int* sample_count, unsigned int* sample_duration)
604 +{
605 +  unsigned char const* table = stts + 8 + idx * 8;
606 +  *sample_count = read_int32(table);
607 +  *sample_duration = read_int32(table + 4);
608 +}
609 +
610 +struct stts_table_t
611 +{
612 +  uint32_t sample_count_;
613 +  uint32_t sample_duration_;
614 +};
615 +
616 +unsigned int ctts_get_entries(unsigned char const* ctts)
617 +{
618 +  return read_int32(ctts + 4);
619 +}
620 +
621 +void ctts_get_sample_count_and_offset(unsigned char const* ctts,
622 +  unsigned int idx, unsigned int* sample_count, unsigned int* sample_offset)
623 +{
624 +  unsigned char const* table = ctts + 8 + idx * 8;
625 +  *sample_count = read_int32(table);
626 +  *sample_offset = read_int32(table + 4);
627 +}
628 +
629 +unsigned int ctts_get_samples(unsigned char const* ctts)
630 +{
631 +  long samples = 0;
632 +  long entries = ctts_get_entries(ctts);
633 +  int i;
634 +  for(i = 0; i != entries; ++i)
635 +  {
636 +    unsigned int sample_count;
637 +    unsigned int sample_offset;
638 +    ctts_get_sample_count_and_offset(ctts, i, &sample_count, &sample_offset);
639 +    samples += sample_count;
640 +  }
641 +
642 +  return samples;
643 +}
644 +
645 +struct ctts_table_t
646 +{
647 +  uint32_t sample_count_;
648 +  uint32_t sample_offset_;
649 +};
650 +
651 +struct stsc_table_t
652 +{
653 +  uint32_t chunk_;
654 +  uint32_t samples_;
655 +  uint32_t id_;
656 +};
657 +
658 +unsigned int stsc_get_entries(unsigned char const* stsc)
659 +{
660 +  return read_int32(stsc + 4);
661 +}
662 +
663 +void stsc_get_table(unsigned char const* stsc, unsigned int i, struct stsc_table_t *stsc_table)
664 +{
665 +  struct stsc_table_t* table = (struct stsc_table_t*)(stsc + 8);
666 +  stsc_table->chunk_ = read_int32(&table[i].chunk_) - 1;
667 +  stsc_table->samples_ = read_int32(&table[i].samples_);
668 +  stsc_table->id_ = read_int32(&table[i].id_);
669 +}
670 +
671 +unsigned int stsc_get_chunk(unsigned char* stsc, unsigned int sample)
672 +{
673 +  unsigned int entries = read_int32(stsc + 4);
674 +  struct stsc_table_t* table = (struct stsc_table_t*)(stsc + 8);
675 +
676 +  if(entries == 0)
677 +  {
678 +    return 0;
679 +  }
680 +  else
681 +//  if(entries == 1)
682 +//  {
683 +//    unsigned int table_samples = read_int32(&table[0].samples_);
684 +//    unsigned int chunk = (sample + 1) / table_samples;
685 +//    return chunk - 1;
686 +//  }
687 +//  else
688 +  {
689 +    unsigned int total = 0;
690 +    unsigned int chunk1 = 1;
691 +    unsigned int chunk1samples = 0;
692 +    unsigned int chunk2entry = 0;
693 +    unsigned int chunk, chunk_sample;
694 +  
695 +    do
696 +    {
697 +      unsigned int range_samples;
698 +      unsigned int chunk2 = read_int32(&table[chunk2entry].chunk_);
699 +      chunk = chunk2 - chunk1;
700 +      range_samples = chunk * chunk1samples;
701 +
702 +      if(sample < total + range_samples)
703 +        break;
704 +
705 +      chunk1samples = read_int32(&table[chunk2entry].samples_);
706 +      chunk1 = chunk2;
707 +
708 +      if(chunk2entry < entries)
709 +      {
710 +        chunk2entry++;
711 +        total += range_samples;
712 +      }
713 +    } while(chunk2entry < entries);
714 +
715 +    if(chunk1samples)
716 +    {
717 +      unsigned int sample_in_chunk = (sample - total) % chunk1samples;
718 +      if(sample_in_chunk != 0)
719 +      {
720 +        printf("ERROR: sample must be chunk aligned: %d\n", sample_in_chunk);
721 +      }
722 +      chunk = (sample - total) / chunk1samples + chunk1;
723 +    }
724 +    else
725 +      chunk = 1;
726 +
727 +    chunk_sample = total + (chunk - chunk1) * chunk1samples;
728 +
729 +    return chunk;
730 +  }
731 +}
732 +
733 +unsigned int stsc_get_samples(unsigned char* stsc)
734 +{
735 +  unsigned int entries = read_int32(stsc + 4);
736 +  struct stsc_table_t* table = (struct stsc_table_t*)(stsc + 8);
737 +  unsigned int samples = 0;
738 +  unsigned int i;
739 +  for(i = 0; i != entries; ++i)
740 +  {
741 +    samples += read_int32(&table[i].samples_);
742 +  }
743 +  return samples;
744 +}
745 +
746 +unsigned int stco_get_entries(unsigned char const* stco)
747 +{
748 +  return read_int32(stco + 4);
749 +}
750 +
751 +unsigned int stco_get_offset(unsigned char const* stco, int idx)
752 +{
753 +  uint32_t const* table = (uint32_t const*)(stco + 8);
754 +  return read_int32(&table[idx]);
755 +}
756 +
757 +unsigned int stsz_get_sample_size(unsigned char const* stsz)
758 +{
759 +  return read_int32(stsz + 4);
760 +}
761 +
762 +unsigned int stsz_get_entries(unsigned char const* stsz)
763 +{
764 +  return read_int32(stsz + 8);
765 +}
766 +
767 +unsigned int stsz_get_size(unsigned char const* stsz, unsigned int idx)
768 +{
769 +  uint32_t const* table = (uint32_t const*)(stsz + 12);
770 +  return read_int32(&table[idx]);
771 +}
772 +
773 +unsigned int stts_get_duration(unsigned char const* stts)
774 +{
775 +  long duration = 0;
776 +  long entries = stts_get_entries(stts);
777 +  int i;
778 +  for(i = 0; i != entries; ++i)
779 +  {
780 +    unsigned int sample_count;
781 +    unsigned int sample_duration;
782 +    stts_get_sample_count_and_duration(stts, i,
783 +                                       &sample_count, &sample_duration);
784 +    duration += sample_duration * sample_count;
785 +  }
786 +
787 +  return duration;
788 +}
789 +
790 +unsigned int stts_get_samples(unsigned char const* stts)
791 +{
792 +  long samples = 0;
793 +  long entries = stts_get_entries(stts);
794 +  int i;
795 +  for(i = 0; i != entries; ++i)
796 +  {
797 +    unsigned int sample_count;
798 +    unsigned int sample_duration;
799 +    stts_get_sample_count_and_duration(stts, i,
800 +                                       &sample_count, &sample_duration);
801 +    samples += sample_count;
802 +  }
803 +
804 +  return samples;
805 +}
806 +
807 +unsigned int stts_get_sample(unsigned char const* stts, unsigned int time)
808 +{
809 +  unsigned int stts_index = 0;
810 +  unsigned int stts_count;
811 +
812 +  unsigned int ret = 0;
813 +  unsigned int time_count = 0;
814 +
815 +  unsigned int entries = stts_get_entries(stts);
816 +  for(; stts_index != entries; ++stts_index)
817 +  {
818 +    unsigned int sample_count;
819 +    unsigned int sample_duration;
820 +    stts_get_sample_count_and_duration(stts, stts_index,
821 +                                       &sample_count, &sample_duration);
822 +    if(time_count + sample_duration * sample_count >= time)
823 +    {
824 +      stts_count = (time - time_count) / sample_duration;
825 +      time_count += stts_count * sample_duration;
826 +      ret += stts_count;
827 +      break;
828 +    }
829 +    else
830 +    {
831 +      time_count += sample_duration * sample_count;
832 +      ret += sample_count;
833 +//      stts_index++;
834 +    }
835 +//    if(stts_index >= table_.size())
836 +//      break;
837 +  }
838 +//  *time = time_count;
839 +  return ret;
840 +}
841 +
842 +unsigned int stts_get_time(unsigned char const* stts, unsigned int sample)
843 +{
844 +  unsigned int ret = 0;
845 +  unsigned int stts_index = 0;
846 +  unsigned int sample_count = 0;
847 +  
848 +  for(;;)
849 +  {
850 +    unsigned int table_sample_count;
851 +    unsigned int table_sample_duration;
852 +    stts_get_sample_count_and_duration(stts, stts_index,
853 +                                       &table_sample_count, &table_sample_duration);
854 +
855 +    if(sample_count + table_sample_count > sample)
856 +    {
857 +      unsigned int stts_count = (sample - sample_count);
858 +      ret += stts_count * table_sample_duration;
859 +      break;
860 +    }
861 +    else
862 +    {
863 +      sample_count += table_sample_count;
864 +      ret += table_sample_count * table_sample_duration;
865 +      stts_index++;
866 +    }
867 +  }
868 +  return ret;
869 +}
870 +
871 +
872 +struct stbl_t
873 +{
874 +  unsigned char* start_;
875 +//stsd stsd_;               // sample description
876 +  unsigned char* stts_;     // decoding time-to-sample
877 +  unsigned char* stss_;     // sync sample
878 +  unsigned char* stsc_;     // sample-to-chunk
879 +  unsigned char* stsz_;     // sample size
880 +  unsigned char* stco_;     // chunk offset
881 +  unsigned char* ctts_;     // composition time-to-sample
882 +};
883 +
884 +void stbl_parse(struct stbl_t* stbl, unsigned char* buffer, unsigned int size)
885 +{
886 +  struct atom_t leaf_atom;
887 +  unsigned char* buffer_start = buffer;
888 +  stbl->stss_ = 0;
889 +  stbl->ctts_ = 0;
890 +
891 +  stbl->start_ = buffer;
892 +  
893 +  while(buffer < buffer_start + size)
894 +  {
895 +    buffer = atom_read_header(buffer, &leaf_atom);
896 +
897 +    atom_print(&leaf_atom);
898 +
899 +    if(atom_is(&leaf_atom, "stts"))
900 +    {
901 +      stbl->stts_ = buffer;
902 +    }
903 +    else
904 +    if(atom_is(&leaf_atom, "stss"))
905 +    {
906 +      stbl->stss_ = buffer;
907 +    }
908 +    else
909 +    if(atom_is(&leaf_atom, "stsc"))
910 +    {
911 +      stbl->stsc_ = buffer;
912 +    }
913 +    else
914 +    if(atom_is(&leaf_atom, "stsz"))
915 +    {
916 +      stbl->stsz_ = buffer;
917 +    }
918 +    else
919 +    if(atom_is(&leaf_atom, "stco"))
920 +    {
921 +      stbl->stco_ = buffer;
922 +    }
923 +    else
924 +    if(atom_is(&leaf_atom, "co64"))
925 +    {
926 +      perror("TODO: co64");
927 +    }
928 +    else
929 +    if(atom_is(&leaf_atom, "ctts"))
930 +    {
931 +      stbl->ctts_ = buffer;
932 +    }
933 +
934 +    buffer = atom_skip(&leaf_atom);
935 +  }
936 +}
937 +
938 +struct minf_t
939 +{
940 +  unsigned char* start_;
941 +  struct stbl_t stbl_;
942 +};
943 +
944 +void minf_parse(struct minf_t* minf, unsigned char* buffer, unsigned int size)
945 +{
946 +  struct atom_t leaf_atom;
947 +  unsigned char* buffer_start = buffer;
948 +
949 +  minf->start_ = buffer;
950 +  
951 +  while(buffer < buffer_start + size)
952 +  {
953 +    buffer = atom_read_header(buffer, &leaf_atom);
954 +
955 +    atom_print(&leaf_atom);
956 +
957 +    if(atom_is(&leaf_atom, "stbl"))
958 +    {
959 +      stbl_parse(&minf->stbl_, buffer, leaf_atom.size_ - ATOM_PREAMBLE_SIZE);
960 +    }
961 +
962 +    buffer = atom_skip(&leaf_atom);
963 +  }
964 +}
965 +
966 +struct mdia_t
967 +{
968 +  unsigned char* start_;
969 +  unsigned char* mdhd_;
970 +  struct minf_t minf_;
971 +//  hdlr hdlr_;
972 +};
973 +
974 +void mdia_parse(struct mdia_t* mdia, unsigned char* buffer, unsigned int size)
975 +{
976 +  struct atom_t leaf_atom;
977 +  unsigned char* buffer_start = buffer;
978 +
979 +  mdia->start_ = buffer;
980 +  
981 +  while(buffer < buffer_start + size)
982 +  {
983 +    buffer = atom_read_header(buffer, &leaf_atom);
984 +
985 +    atom_print(&leaf_atom);
986 +
987 +    if(atom_is(&leaf_atom, "mdhd"))
988 +    {
989 +      mdia->mdhd_ = buffer;
990 +    }
991 +    else
992 +    if(atom_is(&leaf_atom, "minf"))
993 +    {
994 +      minf_parse(&mdia->minf_, buffer, leaf_atom.size_ - ATOM_PREAMBLE_SIZE);
995 +    }
996 +
997 +    buffer = atom_skip(&leaf_atom);
998 +  }
999 +}
1000 +
1001 +struct chunks_t
1002 +{
1003 +  unsigned int sample_;   // number of the first sample in the chunk
1004 +  unsigned int size_;     // number of samples in the chunk
1005 +  int id_;                // for multiple codecs mode - not used
1006 +  unsigned int pos_;      // start byte position of chunk
1007 +};
1008 +
1009 +struct samples_t
1010 +{
1011 +  unsigned int pts_;      // decoding/presentation time
1012 +  unsigned int size_;     // size in bytes
1013 +  unsigned int pos_;      // byte offset
1014 +  unsigned int cto_;      // composition time offset
1015 +};
1016 +
1017 +struct trak_t
1018 +{
1019 +  unsigned char* start_;
1020 +  unsigned char* tkhd_;
1021 +  struct mdia_t mdia_;
1022 +
1023 +  /* temporary indices */
1024 +  unsigned int chunks_size_;
1025 +  struct chunks_t* chunks_;
1026 +
1027 +  unsigned int samples_size_;
1028 +  struct samples_t* samples_;
1029 +};
1030 +
1031 +void trak_init(struct trak_t* trak)
1032 +{
1033 +  trak->chunks_ = 0;
1034 +  trak->samples_ = 0;
1035 +}
1036 +
1037 +void trak_exit(struct trak_t* trak)
1038 +{
1039 +  if(trak->chunks_)
1040 +      free(trak->chunks_);
1041 +  if(trak->samples_)
1042 +    free(trak->samples_);
1043 +}
1044 +
1045 +void trak_parse(struct trak_t* trak, unsigned char* buffer, unsigned int size)
1046 +{
1047 +  struct atom_t leaf_atom;
1048 +  unsigned char* buffer_start = buffer;
1049 +
1050 +  trak->start_ = buffer;
1051 +  
1052 +  while(buffer < buffer_start + size)
1053 +  {
1054 +    buffer = atom_read_header(buffer, &leaf_atom);
1055 +
1056 +    atom_print(&leaf_atom);
1057 +
1058 +    if(atom_is(&leaf_atom, "tkhd"))
1059 +    {
1060 +      trak->tkhd_ = buffer;
1061 +    }
1062 +    else
1063 +    if(atom_is(&leaf_atom, "mdia"))
1064 +    {
1065 +      mdia_parse(&trak->mdia_, buffer, leaf_atom.size_ - ATOM_PREAMBLE_SIZE);
1066 +    }
1067 +
1068 +    buffer = atom_skip(&leaf_atom);
1069 +  }
1070 +}
1071 +
1072 +struct moov_t
1073 +{
1074 +  unsigned char* start_;
1075 +  unsigned int tracks_;
1076 +  unsigned char* mvhd_;
1077 +  struct trak_t traks_[MAX_TRACKS];
1078 +};
1079 +
1080 +void moov_init(struct moov_t* moov)
1081 +{
1082 +  moov->tracks_ = 0;
1083 +}
1084 +
1085 +void moov_exit(struct moov_t* moov)
1086 +{
1087 +  unsigned int i;
1088 +  for(i = 0; i != moov->tracks_; ++i)
1089 +  {
1090 +    trak_exit(&moov->traks_[i]);
1091 +  }
1092 +}
1093 +
1094 +void trak_build_index(struct trak_t* trak)
1095 +{
1096 +  void const* stco = trak->mdia_.minf_.stbl_.stco_;
1097 +
1098 +  trak->chunks_size_ = stco_get_entries(stco);
1099 +  trak->chunks_ = malloc(trak->chunks_size_ * sizeof(struct chunks_t));
1100 +
1101 +  {
1102 +    unsigned int i;
1103 +    for(i = 0; i != trak->chunks_size_; ++i)
1104 +    {
1105 +      trak->chunks_[i].pos_ = stco_get_offset(stco, i);
1106 +    }
1107 +  }
1108 +
1109 +  // process chunkmap:
1110 +  {
1111 +    void const* stsc = trak->mdia_.minf_.stbl_.stsc_;
1112 +    unsigned int last = trak->chunks_size_;
1113 +    unsigned int i = stsc_get_entries(stsc);
1114 +    while(i > 0)
1115 +    {
1116 +      struct stsc_table_t stsc_table;
1117 +      unsigned int j;
1118 +
1119 +      --i;
1120 +
1121 +      stsc_get_table(stsc, i, &stsc_table);
1122 +      for(j = stsc_table.chunk_; j < last; j++)
1123 +      {
1124 +        trak->chunks_[j].id_ = stsc_table.id_;
1125 +        trak->chunks_[j].size_ = stsc_table.samples_;
1126 +      }
1127 +      last = stsc_table.chunk_;
1128 +    }
1129 +  }
1130 +
1131 +  // calc pts of chunks:
1132 +  {
1133 +    void const* stsz = trak->mdia_.minf_.stbl_.stsz_;
1134 +    unsigned int sample_size = stsz_get_sample_size(stsz);
1135 +    unsigned int s = 0;
1136 +    {
1137 +      unsigned int j;
1138 +      for(j = 0; j < trak->chunks_size_; j++)
1139 +      {
1140 +        trak->chunks_[j].sample_ = s;
1141 +        s += trak->chunks_[j].size_;
1142 +      }
1143 +    }
1144 +
1145 +    if(sample_size == 0)
1146 +    {
1147 +      trak->samples_size_ = stsz_get_entries(stsz);
1148 +    }
1149 +    else
1150 +    {
1151 +      trak->samples_size_ = s;
1152 +    }
1153 +
1154 +    trak->samples_ = malloc(trak->samples_size_ * sizeof(struct samples_t));
1155 +
1156 +    if(sample_size == 0)
1157 +    {
1158 +      unsigned int i;
1159 +      for(i = 0; i != trak->samples_size_ ; ++i)
1160 +        trak->samples_[i].size_ = stsz_get_size(stsz, i);
1161 +    }
1162 +    else
1163 +    {
1164 +      unsigned int i;
1165 +      for(i = 0; i != trak->samples_size_ ; ++i)
1166 +        trak->samples_[i].size_ = sample_size;
1167 +    }
1168 +  }
1169 +
1170 +//  i = 0;
1171 +//  for (j = 0; j < trak->durmap_size; j++)
1172 +//    i += trak->durmap[j].num;
1173 +//  if (i != s) {
1174 +//    mp_msg(MSGT_DEMUX, MSGL_WARN,
1175 +//           "MOV: durmap and chunkmap sample count differ (%i vs %i)\n", i, s);
1176 +//    if (i > s) s = i;
1177 +//  }
1178 +
1179 +  // calc pts:
1180 +  {
1181 +    void const* stts = trak->mdia_.minf_.stbl_.stts_;
1182 +    unsigned int s = 0;
1183 +    unsigned int entries = stts_get_entries(stts);
1184 +    unsigned int j;
1185 +    for(j = 0; j < entries; j++)
1186 +    {
1187 +      unsigned int i;
1188 +      unsigned int pts = 0;
1189 +      unsigned int sample_count;
1190 +      unsigned int sample_duration;
1191 +      stts_get_sample_count_and_duration(stts, j,
1192 +                                         &sample_count, &sample_duration);
1193 +      for(i = 0; i < sample_count; i++)
1194 +      {
1195 +        trak->samples_[s].pts_ = pts;
1196 +        ++s;
1197 +        pts += sample_duration;
1198 +      }
1199 +    }
1200 +  }
1201 +
1202 +  // calc composition times:
1203 +  {
1204 +    void const* ctts = trak->mdia_.minf_.stbl_.ctts_;
1205 +    if(ctts)
1206 +    {
1207 +      unsigned int s = 0;
1208 +      unsigned int entries = ctts_get_entries(ctts);
1209 +      unsigned int j;
1210 +      for(j = 0; j < entries; j++)
1211 +      {
1212 +        unsigned int i;
1213 +        unsigned int sample_count;
1214 +        unsigned int sample_offset;
1215 +        ctts_get_sample_count_and_offset(ctts, j, &sample_count, &sample_offset);
1216 +        for(i = 0; i < sample_count; i++)
1217 +        {
1218 +          trak->samples_[s].cto_ = sample_offset;
1219 +          ++s;
1220 +        }
1221 +      }
1222 +    }
1223 +  }
1224 +
1225 +  // calc sample offsets
1226 +  {
1227 +    unsigned int s = 0;
1228 +    unsigned int j;
1229 +    for(j = 0; j < trak->chunks_size_; j++)
1230 +    {
1231 +      unsigned int pos = trak->chunks_[j].pos_;
1232 +      unsigned int i;
1233 +      for(i = 0; i < trak->chunks_[j].size_; i++)
1234 +      {
1235 +        trak->samples_[s].pos_ = pos;
1236 +        pos += trak->samples_[s].size_;
1237 +        ++s;
1238 +      }
1239 +    }
1240 +  }
1241 +}
1242 +
1243 +void trak_write_index(struct trak_t* trak, unsigned int start, unsigned int end)
1244 +{
1245 +  // write samples [start,end>
1246 +
1247 +  // stts = [entries * [sample_count, sample_duration]
1248 +  {
1249 +    unsigned char* stts = trak->mdia_.minf_.stbl_.stts_;
1250 +    unsigned int entries = 0;
1251 +    struct stts_table_t* table = (struct stts_table_t*)(stts + 8);
1252 +    unsigned int s;
1253 +    for(s = start; s != end; ++s)
1254 +    {
1255 +      unsigned int sample_count = 1;
1256 +      unsigned int sample_duration =
1257 +        trak->samples_[s + 1].pts_ - trak->samples_[s].pts_;
1258 +      while(s != end - 1)
1259 +      {
1260 +        if((trak->samples_[s + 1].pts_ - trak->samples_[s].pts_) != sample_duration)
1261 +          break;
1262 +        ++sample_count;
1263 +        ++s;
1264 +      }
1265 +      // write entry
1266 +      write_int32(&table[entries].sample_count_, sample_count);
1267 +      write_int32(&table[entries].sample_duration_, sample_duration);
1268 +      ++entries;
1269 +    }
1270 +    write_int32(stts + 4, entries);
1271 +    if(stts_get_samples(stts) != end - start)
1272 +    {
1273 +      printf("ERROR: stts_get_samples=%d, should be %d\n",
1274 +             stts_get_samples(stts), end - start);
1275 +    }
1276 +  }
1277 +
1278 +  // ctts = [entries * [sample_count, sample_offset]
1279 +  {
1280 +    unsigned char* ctts = trak->mdia_.minf_.stbl_.ctts_;
1281 +    if(ctts)
1282 +    {
1283 +      unsigned int entries = 0;
1284 +      struct ctts_table_t* table = (struct ctts_table_t*)(ctts + 8);
1285 +      unsigned int s;
1286 +      for(s = start; s != end; ++s)
1287 +      {
1288 +        unsigned int sample_count = 1;
1289 +        unsigned int sample_offset = trak->samples_[s].cto_;
1290 +        while(s != end - 1)
1291 +        {
1292 +          if(trak->samples_[s + 1].cto_ != sample_offset)
1293 +            break;
1294 +          ++sample_count;
1295 +          ++s;
1296 +        }
1297 +        // write entry
1298 +        write_int32(&table[entries].sample_count_, sample_count);
1299 +        write_int32(&table[entries].sample_offset_, sample_offset);
1300 +        ++entries;
1301 +      }
1302 +      write_int32(ctts + 4, entries);
1303 +      if(ctts_get_samples(ctts) != end - start)
1304 +      {
1305 +        printf("ERROR: ctts_get_samples=%d, should be %d\n",
1306 +               ctts_get_samples(ctts), end - start);
1307 +      }
1308 +    }
1309 +  }
1310 +
1311 +  // process chunkmap:
1312 +  {
1313 +    unsigned char* stsc = trak->mdia_.minf_.stbl_.stsc_;
1314 +    struct stsc_table_t* stsc_table = (struct stsc_table_t*)(stsc + 8);
1315 +    unsigned int i;
1316 +    for(i = 0; i != trak->chunks_size_; ++i)
1317 +    {
1318 +      if(trak->chunks_[i].sample_ + trak->chunks_[i].size_ > start)
1319 +        break;
1320 +    }
1321 +
1322 +    {
1323 +      unsigned int stsc_entries = 0;
1324 +      unsigned int chunk_start = i;
1325 +      unsigned int samples =
1326 +        trak->chunks_[i].sample_ + trak->chunks_[i].size_ - start;
1327 +      unsigned int id = trak->chunks_[i].id_;
1328 +
1329 +      // write entry [chunk,samples,id]
1330 +      write_int32(&stsc_table[stsc_entries].chunk_, 1);
1331 +      write_int32(&stsc_table[stsc_entries].samples_, samples);
1332 +      write_int32(&stsc_table[stsc_entries].id_, id);
1333 +      ++stsc_entries;
1334 +      if(i != trak->chunks_size_)
1335 +      {
1336 +        for(i += 1; i != trak->chunks_size_; ++i)
1337 +        {
1338 +          if(trak->chunks_[i].size_ != samples)
1339 +          {
1340 +            samples = trak->chunks_[i].size_;
1341 +            id = trak->chunks_[i].id_;
1342 +            write_int32(&stsc_table[stsc_entries].chunk_, i - chunk_start + 1);
1343 +            write_int32(&stsc_table[stsc_entries].samples_, samples);
1344 +            write_int32(&stsc_table[stsc_entries].id_, id);
1345 +            ++stsc_entries;
1346 +          }
1347 +        }
1348 +      }
1349 +      write_int32(stsc + 4, stsc_entries);
1350 +      {
1351 +        unsigned char* stco = trak->mdia_.minf_.stbl_.stco_;
1352 +//        stco_erase(stco, chunk_start);
1353 +        unsigned int entries = read_int32(stco + 4);
1354 +        uint32_t* stco_table = (uint32_t*)(stco + 8);
1355 +        memmove(stco_table, &stco_table[chunk_start],
1356 +                (entries - chunk_start) * sizeof(uint32_t));
1357 +        write_int32(stco + 4, entries - chunk_start);
1358 +
1359 +        // patch first chunk with correct sample offset
1360 +//        uint32_t* stco_table = (uint32_t*)(stco + 8);
1361 +        write_int32(stco_table, trak->samples_[start].pos_);
1362 +      }
1363 +    }
1364 +  }
1365 +
1366 +  // process sync samples:
1367 +  if(trak->mdia_.minf_.stbl_.stss_)
1368 +  {
1369 +    unsigned char* stss = trak->mdia_.minf_.stbl_.stss_;
1370 +    unsigned int entries = read_int32(stss + 4);
1371 +    uint32_t* table = (uint32_t*)(stss + 8);
1372 +    unsigned int stss_start;
1373 +    unsigned int i;
1374 +    for(i = 0; i != entries; ++i)
1375 +    {
1376 +      if(read_int32(&table[i]) >= start + 1)
1377 +        break;
1378 +    }
1379 +    stss_start = i;
1380 +    for(; i != entries; ++i)
1381 +    {
1382 +      unsigned int sync_sample = read_int32(&table[i]);
1383 +      if(sync_sample >= end + 1)
1384 +        break;
1385 +      write_int32(&table[i - stss_start], sync_sample - start);
1386 +
1387 +    }
1388 +//    memmove(table, table + stss_start, (i - stss_start) * sizeof(uint32_t));
1389 +    write_int32(stss + 4, i - stss_start);
1390 +  }
1391 +
1392 +  // process sample sizes
1393 +  {
1394 +    unsigned char* stsz = trak->mdia_.minf_.stbl_.stsz_;
1395 +    if(stsz_get_sample_size(stsz) == 0)
1396 +    {
1397 +      uint32_t* table = (uint32_t*)(stsz + 12);
1398 +      memmove(table, &table[start], (end - start) * sizeof(uint32_t));
1399 +      write_int32(stsz + 8, end - start);
1400 +    }
1401 +  }
1402 +}
1403 +
1404 +int moov_parse(struct moov_t* moov, unsigned char* buffer, unsigned int size)
1405 +{
1406 +  struct atom_t leaf_atom;
1407 +  unsigned char* buffer_start = buffer;
1408 +
1409 +  moov->start_ = buffer;
1410 +  
1411 +  while(buffer < buffer_start + size)
1412 +  {
1413 +    buffer = atom_read_header(buffer, &leaf_atom);
1414 +
1415 +    atom_print(&leaf_atom);
1416 +
1417 +    if(atom_is(&leaf_atom, "cmov"))
1418 +    {
1419 +      return 0;
1420 +    }
1421 +    else
1422 +    if(atom_is(&leaf_atom, "mvhd"))
1423 +    {
1424 +      moov->mvhd_ = buffer;
1425 +    }
1426 +    else
1427 +    if(atom_is(&leaf_atom, "trak"))
1428 +    {
1429 +      if(moov->tracks_ == MAX_TRACKS)
1430 +        return 0;
1431 +      else
1432 +      {
1433 +        struct trak_t* trak = &moov->traks_[moov->tracks_];
1434 +        trak_init(trak);
1435 +        trak_parse(trak, buffer, leaf_atom.size_ - ATOM_PREAMBLE_SIZE);
1436 +        ++moov->tracks_;
1437 +      }
1438 +    }
1439 +    buffer = atom_skip(&leaf_atom);
1440 +  }
1441 +
1442 +  // build the indexing tables
1443 +  {
1444 +    unsigned int i;
1445 +    for(i = 0; i != moov->tracks_; ++i)
1446 +    {
1447 +      trak_build_index(&moov->traks_[i]);
1448 +    }
1449 +  }
1450 +
1451 +  return 1;
1452 +}
1453 +
1454 +void stco_shift_offsets(unsigned char* stco, int offset)
1455 +{
1456 +  unsigned int entries = read_int32(stco + 4);
1457 +  unsigned int* table = (unsigned int*)(stco + 8);
1458 +  unsigned int i;
1459 +  for(i = 0; i != entries; ++i)
1460 +    write_int32(&table[i], (read_int32(&table[i]) + offset));
1461 +}
1462 +
1463 +void trak_shift_offsets(struct trak_t* trak, int offset)
1464 +{
1465 +  unsigned char* stco = trak->mdia_.minf_.stbl_.stco_;
1466 +  stco_shift_offsets(stco, offset);
1467 +}
1468 +
1469 +void moov_shift_offsets(struct moov_t* moov, int offset)
1470 +{
1471 +  unsigned int i;
1472 +  for(i = 0; i != moov->tracks_; ++i)
1473 +  {
1474 +    trak_shift_offsets(&moov->traks_[i], offset);
1475 +  }
1476 +}
1477 +
1478 +long mvhd_get_time_scale(unsigned char* mvhd)
1479 +{
1480 +  int version = read_char(mvhd);
1481 +  unsigned char* p = mvhd + (version == 0 ? 12 : 20);
1482 +  return read_int32(p);
1483 +}
1484 +
1485 +void mvhd_set_duration(unsigned char* mvhd, long duration)
1486 +{
1487 +  int version = read_char(mvhd);
1488 +  if(version == 0)
1489 +  {
1490 +    write_int32(mvhd + 16, duration);
1491 +  }
1492 +  else
1493 +  {
1494 +    perror("mvhd_set_duration");
1495 +//    write_int64(mvhd + 24, duration);
1496 +  }
1497 +}
1498 +
1499 +long mdhd_get_time_scale(unsigned char* mdhd)
1500 +{
1501 +  return read_int32(mdhd + 12);
1502 +}
1503 +
1504 +void mdhd_set_duration(unsigned char* mdhd, unsigned int duration)
1505 +{
1506 +  write_int32(mdhd + 16, duration);
1507 +}
1508 +
1509 +void tkhd_set_duration(unsigned char* tkhd, unsigned int duration)
1510 +{
1511 +  int version = read_char(tkhd);
1512 +  if(version == 0)
1513 +  {
1514 +    write_int32(tkhd + 20, duration);
1515 +  }
1516 +  else
1517 +  {
1518 +    perror("tkhd_set_duration");
1519 +//    write_int64(tkhd + 28, duration);
1520 +  }
1521 +}
1522 +
1523 +unsigned int stss_get_entries(unsigned char const* stss)
1524 +{
1525 +  return read_int32(stss + 4);
1526 +}
1527 +
1528 +unsigned int stss_get_sample(unsigned char const* stss, unsigned int idx)
1529 +{
1530 +  unsigned char const* p = stss + 8 + idx * 4;
1531 +  return read_int32(p);
1532 +}
1533 +
1534 +unsigned int stss_get_nearest_keyframe(unsigned char const* stss, unsigned int sample)
1535 +{
1536 +  // scan the sync samples to find the key frame that precedes the sample number
1537 +  unsigned int i;
1538 +  unsigned int entries = stss_get_entries(stss);
1539 +  unsigned int table_sample = 0;
1540 +  for(i = 0; i != entries; ++i)
1541 +  {
1542 +    table_sample = stss_get_sample(stss, i);
1543 +    if(table_sample >= sample)
1544 +      break;
1545 +  }
1546 +  if(table_sample == sample)
1547 +    return table_sample;
1548 +  else
1549 +    return stss_get_sample(stss, i - 1);
1550 +}
1551 +
1552 +unsigned int stbl_get_nearest_keyframe(struct stbl_t const* stbl, unsigned int sample)
1553 +{
1554 +  // If the sync atom is not present, all samples are implicit sync samples.
1555 +  if(!stbl->stss_)
1556 +    return sample;
1557 +
1558 +  return stss_get_nearest_keyframe(stbl->stss_, sample);
1559 +}
1560 +
1561 +unsigned int moov_seek(unsigned char* moov_data, unsigned int size,
1562 +                       float start_time,
1563 +                       unsigned int* mdat_start,
1564 +                       unsigned int* mdat_size,
1565 +                       unsigned int offset)
1566 +{
1567 +  struct moov_t* moov = malloc(sizeof(struct moov_t));
1568 +  moov_init(moov);
1569 +  if(!moov_parse(moov, moov_data, size))
1570 +  {
1571 +    moov_exit(moov);
1572 +    free(moov);
1573 +    return 0;
1574 +  }
1575 +
1576 +  {
1577 +    long moov_time_scale = mvhd_get_time_scale(moov->mvhd_);
1578 +    unsigned int start = (unsigned int)(start_time * moov_time_scale);
1579 +//  unsigned int end = (unsigned int)(end_time * moov_time_scale);
1580 +    unsigned int bytes_to_skip = UINT_MAX;
1581 +    unsigned int i;
1582 +
1583 +    // for every trak, convert seconds to sample (time-to-sample).
1584 +    // adjust sample to keyframe
1585 +    unsigned int trak_sample_start[MAX_TRACKS];
1586 +//  unsigned int trak_sample_end[MAX_TRACKS];
1587 +
1588 +    unsigned int moov_duration = 0;
1589 +
1590 +    // clayton.mp4 has a third track with one sample that lasts the whole clip.
1591 +    // Assuming the first two tracks are the audio and video track, we patch
1592 +    // the remaining tracks to 'free' atoms.
1593 +    if(moov->tracks_ > 2)
1594 +    {
1595 +      for(i = 2; i != moov->tracks_; ++i)
1596 +      {
1597 +        // patch 'trak' to 'free'
1598 +        unsigned char* p = moov->traks_[i].start_ - 4;
1599 +        p[0] = 'f';
1600 +        p[1] = 'r';
1601 +        p[2] = 'e';
1602 +        p[3] = 'e';
1603 +      }
1604 +      moov->tracks_ = 2;
1605 +    }
1606 +
1607 +    for(i = 0; i != moov->tracks_; ++i)
1608 +    {
1609 +      struct trak_t* trak = &moov->traks_[i];
1610 +      struct stbl_t* stbl = &trak->mdia_.minf_.stbl_;
1611 +      long trak_time_scale = mdhd_get_time_scale(trak->mdia_.mdhd_);
1612 +      float moov_to_trak_time = (float)trak_time_scale / (float)moov_time_scale;
1613 +      float trak_to_moov_time = (float)moov_time_scale / (float)trak_time_scale;
1614 +
1615 +      start = stts_get_sample(stbl->stts_, (unsigned int)(start * moov_to_trak_time));
1616 +      start = stbl_get_nearest_keyframe(stbl, start + 1) - 1;
1617 +      trak_sample_start[i] = start;
1618 +      start = (unsigned int)(stts_get_time(stbl->stts_, start) * trak_to_moov_time);
1619 +    }
1620 +
1621 +    printf("start=%u\n", start);
1622 +
1623 +    for(i = 0; i != moov->tracks_; ++i)
1624 +    {
1625 +      struct trak_t* trak = &moov->traks_[i];
1626 +      struct stbl_t* stbl = &trak->mdia_.minf_.stbl_;
1627 +
1628 +      unsigned int start_sample = trak_sample_start[i];
1629 +      unsigned int end_sample = trak->samples_size_;
1630 +
1631 +      trak_write_index(trak, start_sample, end_sample);
1632 +
1633 +      {
1634 +        unsigned skip =
1635 +          trak->samples_[start_sample].pos_ - trak->samples_[0].pos_;
1636 +        if(skip < bytes_to_skip)
1637 +          bytes_to_skip = skip;
1638 +        printf("Trak can skip %u bytes\n", skip);
1639 +      }
1640 +
1641 +      {
1642 +        // fixup trak (duration)
1643 +        unsigned int trak_duration = stts_get_duration(stbl->stts_);
1644 +        long trak_time_scale = mdhd_get_time_scale(trak->mdia_.mdhd_);
1645 +        float trak_to_moov_time = (float)moov_time_scale / (float)trak_time_scale;
1646 +        unsigned int duration = (long)((float)trak_duration * trak_to_moov_time);
1647 +        mdhd_set_duration(trak->mdia_.mdhd_, trak_duration);
1648 +        tkhd_set_duration(trak->tkhd_, duration);
1649 +        printf("trak: new_duration=%d\n", duration);
1650 +
1651 +        if(duration > moov_duration)
1652 +          moov_duration = duration;
1653 +      }
1654 +
1655 +      printf("stco.size=%d, ", read_int32(stbl->stco_ + 4));
1656 +      printf("stts.size=%d samples=%d\n", read_int32(stbl->stts_ + 4), stts_get_samples(stbl->stts_));
1657 +      printf("stsz.size=%d\n", read_int32(stbl->stsz_ + 8));
1658 +      printf("stsc.samples=%d\n", stsc_get_samples(stbl->stsc_));
1659 +    }
1660 +    mvhd_set_duration(moov->mvhd_, moov_duration);
1661 +
1662 +    offset -= bytes_to_skip;
1663 +
1664 +    printf("shifting offsets by %d\n", offset);
1665 +    moov_shift_offsets(moov, offset);
1666 +
1667 +    *mdat_start += bytes_to_skip;
1668 +    *mdat_size -= bytes_to_skip;
1669 +  }
1670 +
1671 +  moov_exit(moov);
1672 +  free(moov);
1673 +
1674 +  return 1;
1675 +}
1676 +
1677 +// End Of File
1678 +
This page took 0.239605 seconds and 4 git commands to generate.