]> git.pld-linux.org Git - packages/lighttpd.git/blob - lighttpd-mod_h264_streaming.patch
up to 1.4.38
[packages/lighttpd.git] / lighttpd-mod_h264_streaming.patch
1 --- lighttpd-1.4.18/src/Makefile.am     2007-09-03 01:23:53.000000000 +0300
2 +++ lighttpd-mod_h264_streaming-1.4.18/src/Makefile.am  2007-10-23 23:42:37.736979478 +0300
3 @@ -77,6 +77,11 @@
4  mod_flv_streaming_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
5  mod_flv_streaming_la_LIBADD = $(common_libadd)
6  
7 +lib_LTLIBRARIES += mod_h264_streaming.la
8 +mod_h264_streaming_la_SOURCES = mod_h264_streaming.c moov.c
9 +mod_h264_streaming_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
10 +mod_h264_streaming_la_LIBADD = $(common_libadd)
11 +
12  lib_LTLIBRARIES += mod_evasive.la
13  mod_evasive_la_SOURCES = mod_evasive.c
14  mod_evasive_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
15 --- /dev/null   2008-11-04 20:33:38.146691408 +0200
16 +++ lighttpd-1.4.18/src/mod_h264_streaming.c    2009-01-26 20:59:51.385271731 +0200
17 @@ -0,0 +1,337 @@
18 +/*******************************************************************************
19 + mod_h264_streaming.c
20 +
21 + mod_h264_streaming - A lighttpd plugin for pseudo-streaming Quicktime/MPEG4 files.
22 + http://h264.code-shop.com
23 +
24 + Copyright (C) 2007-2009 CodeShop B.V.
25 +******************************************************************************/ 
26 +
27 +#include <ctype.h>
28 +#include <stdlib.h>
29 +#include <string.h>
30 +#include <stdio.h>
31 +
32 +#include "base.h"
33 +#include "log.h"
34 +#include "buffer.h"
35 +#include "response.h"
36 +#include "http_chunk.h"
37 +#include "stat_cache.h"
38 +
39 +#include "plugin.h"
40 +
41 +#ifdef HAVE_CONFIG_H
42 +#include "config.h"
43 +#endif
44 +
45 +#include "moov.h"
46 +
47 +/* plugin config for all request/connections */
48 +
49 +typedef struct {
50 +  array *extensions;
51 +} plugin_config;
52 +
53 +typedef struct {
54 +  PLUGIN_DATA;
55 +
56 +  buffer *query_str;
57 +  array *get_params;
58 +
59 +  plugin_config **config_storage;
60 +
61 +  plugin_config conf;
62 +} plugin_data;
63 +
64 +/* init the plugin data */
65 +INIT_FUNC(mod_h264_streaming_init) {
66 +  plugin_data *p;
67 +
68 +  p = calloc(1, sizeof(*p));
69 +
70 +  p->query_str = buffer_init();
71 +  p->get_params = array_init();
72 +
73 +  return p;
74 +}
75 +
76 +/* detroy the plugin data */
77 +FREE_FUNC(mod_h264_streaming_free) {
78 +  plugin_data *p = p_d;
79 +
80 +  UNUSED(srv);
81 +
82 +  if (!p) return HANDLER_GO_ON;
83 +
84 +  if (p->config_storage) {
85 +    size_t i;
86 +
87 +    for (i = 0; i < srv->config_context->used; i++) {
88 +      plugin_config *s = p->config_storage[i];
89 +
90 +      if (!s) continue;
91 +
92 +      array_free(s->extensions);
93 +
94 +      free(s);
95 +    }
96 +    free(p->config_storage);
97 +  }
98 +
99 +  buffer_free(p->query_str);
100 +  array_free(p->get_params);
101 +
102 +  free(p);
103 +
104 +  return HANDLER_GO_ON;
105 +}
106 +
107 +/* handle plugin config and check values */
108 +
109 +SETDEFAULTS_FUNC(mod_h264_streaming_set_defaults) {
110 +  plugin_data *p = p_d;
111 +  size_t i = 0;
112 +
113 +  config_values_t cv[] = {
114 +    { "h264-streaming.extensions",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
115 +    { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
116 +  };
117 +
118 +  if (!p) return HANDLER_ERROR;
119 +
120 +  p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
121 +
122 +  for (i = 0; i < srv->config_context->used; i++) {
123 +    plugin_config *s;
124 +
125 +    s = calloc(1, sizeof(plugin_config));
126 +    s->extensions     = array_init();
127 +
128 +    cv[0].destination = s->extensions;
129 +
130 +    p->config_storage[i] = s;
131 +
132 +    if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
133 +      return HANDLER_ERROR;
134 +    }
135 +  }
136 +
137 +  return HANDLER_GO_ON;
138 +}
139 +
140 +#define PATCH(x) \
141 +  p->conf.x = s->x;
142 +static int mod_h264_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
143 +  size_t i, j;
144 +  plugin_config *s = p->config_storage[0];
145 +
146 +  PATCH(extensions);
147 +
148 +  /* skip the first, the global context */
149 +  for (i = 1; i < srv->config_context->used; i++) {
150 +    data_config *dc = (data_config *)srv->config_context->data[i];
151 +    s = p->config_storage[i];
152 +
153 +    /* condition didn't match */
154 +    if (!config_check_cond(srv, con, dc)) continue;
155 +
156 +    /* merge config */
157 +    for (j = 0; j < dc->value->used; j++) {
158 +      data_unset *du = dc->value->data[j];
159 +
160 +      if (buffer_is_equal_string(du->key, CONST_STR_LEN("h264-streaming.extensions"))) {
161 +        PATCH(extensions);
162 +      }
163 +    }
164 +  }
165 +
166 +  return 0;
167 +}
168 +#undef PATCH
169 +
170 +static int split_get_params(array *get_params, buffer *qrystr) {
171 +  size_t is_key = 1;
172 +  size_t i;
173 +  char *key = NULL, *val = NULL;
174 +
175 +  key = qrystr->ptr;
176 +
177 +  /* we need the \0 */
178 +  for (i = 0; i < qrystr->used; i++) {
179 +    switch(qrystr->ptr[i]) {
180 +    case '=':
181 +      if (is_key) {
182 +        val = qrystr->ptr + i + 1;
183 +
184 +        qrystr->ptr[i] = '\0';
185 +
186 +        is_key = 0;
187 +      }
188 +
189 +      break;
190 +    case '&':
191 +    case '\0': /* fin symbol */
192 +      if (!is_key) {
193 +        data_string *ds;
194 +        /* we need at least a = since the last & */
195 +
196 +        /* terminate the value */
197 +        qrystr->ptr[i] = '\0';
198 +
199 +        if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) {
200 +          ds = data_string_init();
201 +        }
202 +        buffer_copy_string_len(ds->key, key, strlen(key));
203 +        buffer_copy_string_len(ds->value, val, strlen(val));
204 +
205 +        array_insert_unique(get_params, (data_unset *)ds);
206 +      }
207 +
208 +      key = qrystr->ptr + i + 1;
209 +      val = NULL;
210 +      is_key = 1;
211 +      break;
212 +    }
213 +  }
214 +
215 +  return 0;
216 +}
217 +
218 +URIHANDLER_FUNC(mod_h264_streaming_path_handler) {
219 +  plugin_data *p = p_d;
220 +  int s_len;
221 +  size_t k;
222 +
223 +  UNUSED(srv);
224 +
225 +  if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
226 +
227 +  mod_h264_streaming_patch_connection(srv, con, p);
228 +
229 +  s_len = con->physical.path->used - 1;
230 +
231 +  for (k = 0; k < p->conf.extensions->used; k++) {
232 +    data_string *ds = (data_string *)p->conf.extensions->data[k];
233 +    int ct_len = ds->value->used - 1;
234 +
235 +    if (ct_len > s_len) continue;
236 +    if (ds->value->used == 0) continue;
237 +
238 +    if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
239 +      data_string *get_param;
240 +      stat_cache_entry *sce = NULL;
241 +      double start = 0.0;
242 +      double end = 0.0;
243 +      char *err = NULL;
244 +      int client_is_flash = 0;
245 +
246 +      array_reset(p->get_params);
247 +      buffer_copy_string_buffer(p->query_str, con->uri.query);
248 +      split_get_params(p->get_params, p->query_str);
249 +
250 +      /* if there is a start=[0-9]+ in the header use it as start,
251 +       * otherwise send the full file */
252 +      if (NULL != (get_param = (data_string *)array_get_element(p->get_params, "start")))
253 +                        {
254 +        /* check if it is a number */
255 +        start = strtod(get_param->value->ptr, &err);
256 +        if (*err != '\0') {
257 +          return HANDLER_GO_ON;
258 +        }
259 +        if (start < 0) return HANDLER_GO_ON;
260 +                        }
261 +
262 +      /* if there is an end=[0-9]+ in the header use it as end */
263 +      if (NULL != (get_param = (data_string *)array_get_element(p->get_params, "end")))
264 +                        {
265 +        /* check if it is a number */
266 +        end = strtod(get_param->value->ptr, &err);
267 +        if (*err != '\0') {
268 +          return HANDLER_GO_ON;
269 +                          }
270 +        if (end < 0 || start >= end) return HANDLER_GO_ON;
271 +      }
272 +
273 +      if (NULL != (get_param = (data_string *)array_get_element(p->get_params, "client")))
274 +      {
275 +        client_is_flash = starts_with(get_param->value->ptr, "FLASH");
276 +      }
277 +
278 +      /* get file info */
279 +      if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
280 +        return HANDLER_GO_ON;
281 +      }
282 +
283 +      /* we are safe now, let's build a h264 header */
284 +      {
285 +        {
286 +          unsigned int filesize = sce->st.st_size;
287 +
288 +          void* mp4_header;
289 +          uint32_t mp4_header_size;
290 +          uint64_t mdat_offset;
291 +          uint64_t mdat_size;
292 +
293 +          int result = mp4_split(con->physical.path->ptr, filesize, start, end,
294 +                                 &mp4_header, &mp4_header_size,
295 +                                 &mdat_offset, &mdat_size, client_is_flash);
296 +
297 +          if(result)
298 +          {
299 +            buffer* b = chunkqueue_get_append_buffer(con->write_queue);
300 +            buffer_append_memory(b, mp4_header, mp4_header_size);
301 +            b->used++; /* add virtual \0 */
302 +
303 +            http_chunk_append_file(srv, con, con->physical.path,
304 +                                   mdat_offset, mdat_size);
305 +          }
306 +
307 +          if(mp4_header)
308 +          {
309 +            free(mp4_header);
310 +          }
311 +
312 +          if(!result)
313 +          {
314 +            return HANDLER_GO_ON;
315 +          }
316 +        }
317 +      }
318 +
319 +      response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/mp4"));
320 +      if(!client_is_flash)
321 +      {
322 +        response_header_overwrite(srv, con, CONST_STR_LEN("X-Mod-H264-Streaming"), CONST_STR_LEN("version=2.0"));
323 +      }
324 +      else
325 +      {
326 +        response_header_overwrite(srv, con, CONST_STR_LEN("X-Mod-H264-Streaming"), CONST_STR_LEN("version=2.0,client=flash"));
327 +      }
328 +
329 +      con->file_finished = 1;
330 +
331 +      return HANDLER_FINISHED;
332 +    }
333 +  }
334 +
335 +  /* not found */
336 +  return HANDLER_GO_ON;
337 +}
338 +
339 +/* this function is called at dlopen() time and inits the callbacks */
340 +
341 +int mod_h264_streaming_plugin_init(plugin *p) {
342 +  p->version     = LIGHTTPD_VERSION_ID;
343 +  p->name        = buffer_init_string("h264_streaming");
344 +
345 +  p->init        = mod_h264_streaming_init;
346 +  p->handle_physical = mod_h264_streaming_path_handler;
347 +  p->set_defaults  = mod_h264_streaming_set_defaults;
348 +  p->cleanup     = mod_h264_streaming_free;
349 +
350 +  p->data        = NULL;
351 +
352 +  return 0;
353 +}
354 +
355 --- /dev/null   2008-11-04 20:33:38.146691408 +0200
356 +++ lighttpd-1.4.18/src/moov.c  2009-01-26 21:00:05.071936866 +0200
357 @@ -0,0 +1,3031 @@
358 +/*******************************************************************************
359 + moov.c (version 2)
360 +
361 + moov - A library for splitting Quicktime/MPEG4 files.
362 + http://h264.code-shop.com
363 +
364 + Copyright (C) 2007-2009 CodeShop B.V.
365 +
366 + Licensing
367 + The H264 Streaming Module is licened under a Creative Common License. It allows
368 + you to use, modify and redistribute the module, but only for *noncommercial*
369 + purposes. For corporate use, please apply for a commercial license.
370 +
371 + Creative Commons License:
372 + http://creativecommons.org/licenses/by-nc-sa/3.0/
373 +
374 + Commercial License:
375 + http://h264.code-shop.com/trac/wiki/Mod-H264-Streaming-License-Version2
376 +******************************************************************************/ 
377 +
378 +#include "moov.h"
379 +
380 +#ifdef _MSVC_VER
381 +#define _CRTDBG_MAP_ALLOC
382 +#include <stdlib.h>
383 +#include <crtdbg.h>
384 +#endif
385 +
386 +#ifdef UNUSED
387 +#elif defined(__GNUC__)
388 +# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
389 +#elif defined(__LCLINT__)
390 +# define UNUSED(x) /*@unused@*/ x
391 +#else
392 +# define UNUSED(x) x
393 +#endif
394 +
395 +/* 
396 +  The QuickTime File Format PDF from Apple:
397 +    http://developer.apple.com/techpubs/quicktime/qtdevdocs/PDF/QTFileFormat.pdf
398 +*/
399 +
400 +#include <stdlib.h>
401 +#include <stdio.h>
402 +#include <string.h>
403 +#include <limits.h>
404 +#include <stdint.h>
405 +
406 +#ifdef HAVE_CONFIG_H
407 +#include "config.h"
408 +#endif
409 +
410 +#ifdef HAVE_STDINT_H
411 +# include <stdint.h>
412 +#endif
413 +#ifdef HAVE_INTTYPES_H
414 +# include <inttypes.h>
415 +#endif
416 +#if defined HAVE_ZLIB_H && defined HAVE_LIBZ
417 +// Compress the MOOV atom. Turn this off for Flash as it doesn't support it.
418 +// # define COMPRESS_MOOV_ATOM
419 +# include <zlib.h>
420 +#endif
421 +
422 +#ifdef WIN32
423 +#define ftello _ftelli64
424 +#define fseeko _fseeki64
425 +#endif
426 +
427 +#define MAX_TRACKS 8
428 +
429 +#define FOURCC(a, b, c, d) ((uint32_t)(a) << 24) + \
430 +                           ((uint32_t)(b) << 16) + \
431 +                           ((uint32_t)(c) << 8) + \
432 +                           ((uint32_t)(d))
433 +
434 +/* Returns true when the test string is a prefix of the input */
435 +int starts_with(const char* input, const char* test)
436 +{
437 +  while(*input && *test)
438 +  {
439 +    if(*input != *test)
440 +      return 0;
441 +    ++input;
442 +    ++test;
443 +  }
444 +
445 +  return *test == '\0';
446 +}
447 +
448 +static unsigned int read_8(unsigned char const* buffer)
449 +{
450 +  return buffer[0];
451 +}
452 +
453 +static unsigned char* write_8(unsigned char* buffer, unsigned char v)
454 +{
455 +  buffer[0] = v;
456 +
457 +  return buffer + 1;
458 +}
459 +
460 +static uint16_t read_16(unsigned char const* buffer)
461 +{
462 +  return (buffer[0] << 8) |
463 +         (buffer[1] << 0);
464 +}
465 +
466 +static unsigned char* write_16(unsigned char* buffer, unsigned int v)
467 +{
468 +  buffer[0] = (unsigned char)(v >> 8);
469 +  buffer[1] = (unsigned char)(v >> 0);
470 +
471 +  return buffer + 2;
472 +}
473 +
474 +static unsigned int read_24(unsigned char const* buffer)
475 +{
476 +  return (buffer[0] << 16) |
477 +         (buffer[1] << 8) |
478 +         (buffer[2] << 0);
479 +}
480 +
481 +static unsigned char* write_24(unsigned char* buffer, unsigned int v)
482 +{
483 +  buffer[0] = (unsigned char)(v >> 16);
484 +  buffer[1] = (unsigned char)(v >> 8);
485 +  buffer[2] = (unsigned char)(v >> 0);
486 +
487 +  return buffer + 3;
488 +}
489 +
490 +static uint32_t read_32(unsigned char const* buffer)
491 +{
492 +  return (buffer[0] << 24) |
493 +         (buffer[1] << 16) |
494 +         (buffer[2] << 8) |
495 +         (buffer[3] << 0);
496 +}
497 +
498 +static unsigned char* write_32(unsigned char* buffer, uint32_t v)
499 +{
500 +  buffer[0] = (unsigned char)(v >> 24);
501 +  buffer[1] = (unsigned char)(v >> 16);
502 +  buffer[2] = (unsigned char)(v >> 8);
503 +  buffer[3] = (unsigned char)(v >> 0);
504 +
505 +  return buffer + 4;
506 +}
507 +
508 +static uint64_t read_64(unsigned char const* buffer)
509 +{
510 +  return ((uint64_t)(read_32(buffer)) << 32) + read_32(buffer + 4);
511 +}
512 +
513 +static unsigned char* write_64(unsigned char* buffer, uint64_t v)
514 +{
515 +  write_32(buffer + 0, (uint32_t)(v >> 32));
516 +  write_32(buffer + 4, (uint32_t)(v >> 0));
517 +
518 +  return buffer + 8;
519 +}
520 +
521 +#define ATOM_PREAMBLE_SIZE 8
522 +
523 +struct atom_t
524 +{
525 + uint32_t type_;
526 + uint32_t short_size_;
527 + uint64_t size_;
528 + unsigned char* start_;
529 + unsigned char* end_;
530 +};
531 +
532 +static unsigned char* atom_read_header(unsigned char* buffer, struct atom_t* atom)
533 +{
534 +  atom->start_ = buffer;
535 +  atom->short_size_ = read_32(buffer);
536 +  atom->type_ = read_32(buffer + 4);
537 +
538 +  if(atom->short_size_ == 1)
539 +    atom->size_ = read_64(buffer + 8);
540 +  else
541 +    atom->size_ = atom->short_size_;
542 +
543 +  atom->end_ = atom->start_ + atom->size_;
544 +
545 +  return buffer + ATOM_PREAMBLE_SIZE + (atom->short_size_ == 1 ? 8 : 0);
546 +}
547 +
548 +static void atom_print(struct atom_t const* atom)
549 +{
550 +  printf("Atom(%c%c%c%c,%lld)\n",
551 +         atom->type_ >> 24,
552 +         atom->type_ >> 16,
553 +         atom->type_ >> 8,
554 +         atom->type_,
555 +         atom->size_);
556 +}
557 +
558 +struct unknown_atom_t
559 +{
560 +  void* atom_;
561 +  struct unknown_atom_t* next_;
562 +};
563 +
564 +static struct unknown_atom_t* unknown_atom_init()
565 +{
566 +  struct unknown_atom_t* atom = (struct unknown_atom_t*)malloc(sizeof(struct unknown_atom_t));
567 +  atom->atom_ = 0;
568 +  atom->next_ = 0;
569 +
570 +  return atom;
571 +}
572 +
573 +static void unknown_atom_exit(struct unknown_atom_t* atom)
574 +{
575 +  while(atom)
576 +  {
577 +    struct unknown_atom_t* next = atom->next_;
578 +    free(atom->atom_);
579 +    free(atom);
580 +    atom = next;
581 +  }
582 +}
583 +
584 +static struct unknown_atom_t* unknown_atom_add_atom(struct unknown_atom_t* parent, void* atom)
585 +{
586 +  size_t size = read_32(atom);
587 +  struct unknown_atom_t* unknown = unknown_atom_init();
588 +  unknown->atom_ = malloc(size);
589 +  memcpy(unknown->atom_, atom, size);
590 +  unknown->next_ = parent;
591 +  return unknown;
592 +}
593 +
594 +struct atom_read_list_t
595 +{
596 +  uint32_t type_;
597 +  void* parent_;
598 +  int (*destination_)(void* parent, void* child);
599 +  void* (*reader_)(void* parent, unsigned char* buffer, uint64_t size);
600 +};
601 +
602 +static int atom_reader(struct atom_read_list_t* atom_read_list,
603 +                       unsigned int atom_read_list_size,
604 +                       void* parent,
605 +                       unsigned char* buffer, uint64_t size)
606 +{
607 +  struct atom_t leaf_atom;
608 +  unsigned char* buffer_start = buffer;
609 +
610 +  while(buffer < buffer_start + size)
611 +  {
612 +    unsigned int i;
613 +    buffer = atom_read_header(buffer, &leaf_atom);
614 +
615 +    atom_print(&leaf_atom);
616 +
617 +    for(i = 0; i != atom_read_list_size; ++i)
618 +    {
619 +      if(leaf_atom.type_ == atom_read_list[i].type_)
620 +      {
621 +        break;
622 +      }
623 +    }
624 +
625 +    if(i == atom_read_list_size)
626 +    {
627 +      // add to unkown chunks
628 +      (*(struct unknown_atom_t**)parent) =
629 +        unknown_atom_add_atom(*(struct unknown_atom_t**)(parent), buffer - ATOM_PREAMBLE_SIZE);
630 +    }
631 +    else
632 +    {
633 +      void* child =
634 +        atom_read_list[i].reader_(parent, buffer,
635 +          leaf_atom.size_ - ATOM_PREAMBLE_SIZE);
636 +      if(!child)
637 +        break;
638 +      if(!atom_read_list[i].destination_(parent, child))
639 +        break;
640 +    }
641 +    buffer = leaf_atom.end_;
642 +  }
643 +
644 +  if(buffer < buffer_start + size)
645 +  {
646 +    return 0;
647 +  }
648 +
649 +  return 1;
650 +}
651 +
652 +struct atom_write_list_t
653 +{
654 +  uint32_t type_;
655 +  void* parent_;
656 +  void* source_;
657 +  unsigned char* (*writer_)(void* parent, void* atom, unsigned char* buffer);
658 +};
659 +
660 +static unsigned char* atom_writer_unknown(struct unknown_atom_t* atoms,
661 +                                          unsigned char* buffer)
662 +{
663 +  while(atoms)
664 +  {
665 +    size_t size = read_32(atoms->atom_);
666 +    memcpy(buffer, atoms->atom_, size);
667 +    buffer += size;
668 +    atoms = atoms->next_;
669 +  }
670 +
671 +  return buffer;
672 +}
673 +
674 +static unsigned char* atom_writer(struct unknown_atom_t* unknown_atoms,
675 +                                  struct atom_write_list_t* atom_write_list,
676 +                                  unsigned int atom_write_list_size,
677 +                                  unsigned char* buffer)
678 +{
679 +  unsigned i;
680 +  const int write_box64 = 0;
681 +
682 +  if(unknown_atoms)
683 +  {
684 +    buffer = atom_writer_unknown(unknown_atoms, buffer);
685 +  }
686 +
687 +  for(i = 0; i != atom_write_list_size; ++i)
688 +  {
689 +    if(atom_write_list[i].source_ != 0)
690 +    {
691 +      unsigned char* atom_start = buffer;
692 +      // atom size
693 +      if(write_box64)
694 +      {
695 +        write_32(buffer, 1); // box64
696 +      }
697 +      buffer += 4;
698 +
699 +      // atom type
700 +      buffer = write_32(buffer, atom_write_list[i].type_);
701 +      if(write_box64)
702 +      {
703 +        buffer += 8; // box64
704 +      }
705 +
706 +      // atom payload
707 +      buffer = atom_write_list[i].writer_(atom_write_list[i].parent_,
708 +                                          atom_write_list[i].source_, buffer);
709 +
710 +      if(write_box64)
711 +        write_64(atom_start + 8, buffer - atom_start);
712 +      else
713 +        write_32(atom_start, buffer - atom_start);
714 +    }
715 +  }
716 +
717 +  return buffer;
718 +}
719 +
720 +struct tkhd_t
721 +{
722 +  unsigned int version_;
723 +  unsigned int flags_;
724 +  uint64_t creation_time_;
725 +  uint64_t modification_time_;
726 +  uint32_t track_id_;
727 +  uint32_t reserved_;
728 +  uint64_t duration_;
729 +  uint32_t reserved2_[2];
730 +  uint16_t layer_;
731 +  uint16_t predefined_;
732 +  uint16_t volume_;
733 +  uint16_t reserved3_;
734 +  uint32_t matrix_[9];
735 +  uint32_t width_;
736 +  uint32_t height_;
737 +};
738 +
739 +struct mdhd_t
740 +{
741 +  unsigned int version_;
742 +  unsigned int flags_;
743 +  uint64_t creation_time_;
744 +  uint64_t modification_time_;
745 +  uint32_t timescale_;
746 +  uint64_t duration_;
747 +  unsigned int language_[3];
748 +  uint16_t predefined_;
749 +};
750 +
751 +struct vmhd_t
752 +{
753 +  unsigned int version_;
754 +  unsigned int flags_;
755 +  uint16_t graphics_mode_;
756 +  uint16_t opcolor_[3];
757 +};
758 +
759 +struct hdlr_t
760 +{
761 +  unsigned int version_;
762 +  unsigned int flags_;
763 +  uint32_t predefined_;
764 +  uint32_t handler_type_;
765 +  uint32_t reserved1_;
766 +  uint32_t reserved2_;
767 +  uint32_t reserved3_;
768 +  char* name_;
769 +};
770 +
771 +struct stbl_t
772 +{
773 +  struct unknown_atom_t* unknown_atoms_;
774 +//struct stsd_t* stsd_;     // sample description
775 +  struct stts_t* stts_;     // decoding time-to-sample
776 +  struct stss_t* stss_;     // sync sample
777 +  struct stsc_t* stsc_;     // sample-to-chunk
778 +  struct stsz_t* stsz_;     // sample size
779 +  struct stco_t* stco_;     // chunk offset
780 +  struct ctts_t* ctts_;     // composition time-to-sample
781 +
782 +  void* stco_inplace_;      // newly generated stco (patched inplace)
783 +};
784 +
785 +struct stts_table_t
786 +{
787 +  uint32_t sample_count_;
788 +  uint32_t sample_duration_;
789 +};
790 +
791 +struct stts_t
792 +{
793 +  unsigned int version_;
794 +  unsigned int flags_;
795 +  uint32_t entries_;
796 +  struct stts_table_t* table_;
797 +};
798 +
799 +struct stss_t
800 +{
801 +  unsigned int version_;
802 +  unsigned int flags_;
803 +  uint32_t entries_;
804 +  uint32_t* sample_numbers_;
805 +};
806 +
807 +struct stsc_table_t
808 +{
809 +  uint32_t chunk_;
810 +  uint32_t samples_;
811 +  uint32_t id_;
812 +};
813 +
814 +struct stsc_t
815 +{
816 +  unsigned int version_;
817 +  unsigned int flags_;
818 +  uint32_t entries_;
819 +  struct stsc_table_t* table_;
820 +};
821 +
822 +struct stsz_t
823 +{
824 +  unsigned int version_;
825 +  unsigned int flags_;
826 +  uint32_t sample_size_;
827 +  uint32_t entries_;
828 +  uint32_t* sample_sizes_;
829 +};
830 +
831 +struct stco_t
832 +{
833 +  unsigned int version_;
834 +  unsigned int flags_;
835 +  uint32_t entries_;
836 +  uint64_t* chunk_offsets_;
837 +};
838 +
839 +struct ctts_table_t
840 +{
841 +  uint32_t sample_count_;
842 +  uint32_t sample_offset_;
843 +};
844 +
845 +struct ctts_t
846 +{
847 +  unsigned int version_;
848 +  unsigned int flags_;
849 +  uint32_t entries_;
850 +  struct ctts_table_t* table_;
851 +};
852 +
853 +struct minf_t
854 +{
855 +  struct unknown_atom_t* unknown_atoms_;
856 +  struct vmhd_t* vmhd_;
857 +//  struct dinf_t* dinf_;
858 +  struct stbl_t* stbl_;
859 +};
860 +
861 +struct mdia_t
862 +{
863 +  struct unknown_atom_t* unknown_atoms_;
864 +  struct mdhd_t* mdhd_;
865 +  struct hdlr_t* hdlr_;
866 +  struct minf_t* minf_;
867 +};
868 +
869 +struct chunks_t
870 +{
871 +  unsigned int sample_;   // number of the first sample in the chunk
872 +  unsigned int size_;     // number of samples in the chunk
873 +  int id_;                // for multiple codecs mode - not used
874 +  uint64_t pos_;          // start byte position of chunk
875 +};
876 +
877 +struct samples_t
878 +{
879 +  unsigned int pts_;      // decoding/presentation time
880 +  unsigned int size_;     // size in bytes
881 +  uint64_t pos_;          // byte offset
882 +  unsigned int cto_;      // composition time offset
883 +};
884 +
885 +struct trak_t
886 +{
887 +  struct unknown_atom_t* unknown_atoms_;
888 +  struct tkhd_t* tkhd_;
889 +  struct mdia_t* mdia_;
890 +
891 +  /* temporary indices */
892 +  unsigned int chunks_size_;
893 +  struct chunks_t* chunks_;
894 +
895 +  unsigned int samples_size_;
896 +  struct samples_t* samples_;
897 +};
898 +
899 +struct mvhd_t
900 +{
901 +  unsigned int version_;
902 +  unsigned int flags_;
903 +  uint64_t creation_time_;
904 +  uint64_t modification_time_;
905 +  uint32_t timescale_;
906 +  uint64_t duration_;
907 +  uint32_t rate_;
908 +  uint16_t volume_;
909 +  uint16_t reserved1_;
910 +  uint32_t reserved2_[2];
911 +  uint32_t matrix_[9];
912 +  uint32_t predefined_[6];
913 +  uint32_t next_track_id_;
914 +};
915 +
916 +struct moov_t
917 +{
918 +  struct unknown_atom_t* unknown_atoms_;
919 +  struct mvhd_t* mvhd_;
920 +  unsigned int tracks_;
921 +  struct trak_t* traks_[MAX_TRACKS];
922 +};
923 +
924 +
925 +static struct tkhd_t* tkhd_init()
926 +{
927 +  struct tkhd_t* tkhd = (struct tkhd_t*)malloc(sizeof(struct tkhd_t));
928 +
929 +  return tkhd;
930 +}
931 +
932 +static void tkhd_exit(struct tkhd_t* tkhd)
933 +{
934 +  free(tkhd);
935 +}
936 +
937 +static void* tkhd_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
938 +{
939 +  unsigned int i;
940 +
941 +  struct tkhd_t* tkhd = tkhd_init();
942 +
943 +  tkhd->version_ = read_8(buffer + 0);
944 +  tkhd->flags_ = read_24(buffer + 1);
945 +  if(tkhd->version_ == 0)
946 +  {
947 +    if(size < 92-8)
948 +      return 0;
949 +
950 +    tkhd->creation_time_ = read_32(buffer + 4);
951 +    tkhd->modification_time_ = read_32(buffer + 8);
952 +    tkhd->track_id_ = read_32(buffer + 12);
953 +    tkhd->reserved_ = read_32(buffer + 16);
954 +    tkhd->duration_ = read_32(buffer + 20);
955 +    buffer += 24;
956 +  }
957 +  else
958 +  {
959 +    if(size < 104-8)
960 +      return 0;
961 +
962 +    tkhd->creation_time_ = read_64(buffer + 4);
963 +    tkhd->modification_time_ = read_64(buffer + 12);
964 +    tkhd->track_id_ = read_32(buffer + 20);
965 +    tkhd->reserved_ = read_32(buffer + 24);
966 +    tkhd->duration_ = read_64(buffer + 28);
967 +    buffer += 36;
968 +  }
969 +
970 +  tkhd->reserved2_[0] = read_32(buffer + 0);
971 +  tkhd->reserved2_[1] = read_32(buffer + 4);
972 +  tkhd->layer_ = read_16(buffer + 8);
973 +  tkhd->predefined_ = read_16(buffer + 10);
974 +  tkhd->volume_ = read_16(buffer + 12);
975 +  tkhd->reserved3_ = read_16(buffer + 14);
976 +  buffer += 16;
977 +
978 +  for(i = 0; i != 9; ++i)
979 +  {
980 +    tkhd->matrix_[i] = read_32(buffer);
981 +    buffer += 4;
982 +  }
983 +
984 +  tkhd->width_ = read_32(buffer + 0);
985 +  tkhd->height_ = read_32(buffer + 4);
986 +
987 +  return tkhd;
988 +}
989 +
990 +static unsigned char* tkhd_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
991 +{
992 +  struct tkhd_t const* tkhd = atom;
993 +  unsigned int i;
994 +
995 +  buffer = write_8(buffer, tkhd->version_);
996 +  buffer = write_24(buffer, tkhd->flags_);
997 +
998 +  if(tkhd->version_ == 0)
999 +  {
1000 +    buffer = write_32(buffer, (uint32_t)tkhd->creation_time_);
1001 +    buffer = write_32(buffer, (uint32_t)tkhd->modification_time_);
1002 +    buffer = write_32(buffer, tkhd->track_id_);
1003 +    buffer = write_32(buffer, tkhd->reserved_);
1004 +    buffer = write_32(buffer, (uint32_t)tkhd->duration_);
1005 +  }
1006 +  else
1007 +  {
1008 +    buffer = write_64(buffer, tkhd->creation_time_);
1009 +    buffer = write_64(buffer, tkhd->modification_time_);
1010 +    buffer = write_32(buffer, tkhd->track_id_);
1011 +    buffer = write_32(buffer, tkhd->reserved_);
1012 +    buffer = write_64(buffer, tkhd->duration_);
1013 +  }
1014 +
1015 +  buffer = write_32(buffer, tkhd->reserved2_[0]);
1016 +  buffer = write_32(buffer, tkhd->reserved2_[1]);
1017 +  buffer = write_16(buffer, tkhd->layer_);
1018 +  buffer = write_16(buffer, tkhd->predefined_);
1019 +  buffer = write_16(buffer, tkhd->volume_);
1020 +  buffer = write_16(buffer, tkhd->reserved3_);
1021 +
1022 +  for(i = 0; i != 9; ++i)
1023 +  {
1024 +    buffer = write_32(buffer, tkhd->matrix_[i]);
1025 +  }
1026 +
1027 +  buffer = write_32(buffer, tkhd->width_);
1028 +  buffer = write_32(buffer, tkhd->height_);
1029 +
1030 +  return buffer;
1031 +}
1032 +
1033 +static struct mdhd_t* mdhd_init()
1034 +{
1035 +  struct mdhd_t* mdhd = (struct mdhd_t*)malloc(sizeof(struct mdhd_t));
1036 +
1037 +  return mdhd;
1038 +}
1039 +
1040 +static void mdhd_exit(struct mdhd_t* mdhd)
1041 +{
1042 +  free(mdhd);
1043 +}
1044 +
1045 +static void* mdhd_read(void* UNUSED(parent), unsigned char* buffer, uint64_t UNUSED(size))
1046 +{
1047 +  uint16_t language;
1048 +  unsigned int i;
1049 +
1050 +  struct mdhd_t* mdhd = mdhd_init();
1051 +  mdhd->version_ = read_8(buffer + 0);
1052 +  mdhd->flags_ = read_24(buffer + 1);
1053 +  if(mdhd->version_ == 0)
1054 +  {
1055 +    mdhd->creation_time_ = read_32(buffer + 4);
1056 +    mdhd->modification_time_ = read_32(buffer + 8);
1057 +    mdhd->timescale_ = read_32(buffer + 12);
1058 +    mdhd->duration_ = read_32(buffer + 16);
1059 +    buffer += 20;
1060 +  }
1061 +  else
1062 +  {
1063 +    mdhd->creation_time_ = read_64(buffer + 4);
1064 +    mdhd->modification_time_ = read_64(buffer + 12);
1065 +    mdhd->timescale_ = read_32(buffer + 20);
1066 +    mdhd->duration_ = read_64(buffer + 24);
1067 +    buffer += 32;
1068 +  }
1069 +
1070 +  language = read_16(buffer + 0);
1071 +  for(i = 0; i != 3; ++i)
1072 +  {
1073 +    mdhd->language_[i] = ((language >> ((2 - i) * 5)) & 0x1f) + 0x60;
1074 +  }
1075 +
1076 +  mdhd->predefined_ = read_16(buffer + 2);
1077 +
1078 +  return mdhd;
1079 +}
1080 +
1081 +static unsigned char* mdhd_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
1082 +{
1083 +  struct mdhd_t const* mdhd = atom;
1084 +
1085 +  buffer = write_8(buffer, mdhd->version_);
1086 +  buffer = write_24(buffer, mdhd->flags_);
1087 +
1088 +  if(mdhd->version_ == 0)
1089 +  {
1090 +    buffer = write_32(buffer, (uint32_t)mdhd->creation_time_);
1091 +    buffer = write_32(buffer, (uint32_t)mdhd->modification_time_);
1092 +    buffer = write_32(buffer, mdhd->timescale_);
1093 +    buffer = write_32(buffer, (uint32_t)mdhd->duration_);
1094 +  }
1095 +  else
1096 +  {
1097 +    buffer = write_64(buffer, mdhd->creation_time_);
1098 +    buffer = write_64(buffer, mdhd->modification_time_);
1099 +    buffer = write_32(buffer, mdhd->timescale_);
1100 +    buffer = write_64(buffer, mdhd->duration_);
1101 +  }
1102 +
1103 +  buffer = write_16(buffer,
1104 +                    ((mdhd->language_[0] - 0x60) << 10) +
1105 +                    ((mdhd->language_[1] - 0x60) << 5) +
1106 +                    ((mdhd->language_[2] - 0x60) << 0));
1107 +
1108 +  buffer = write_16(buffer, mdhd->predefined_);
1109 +
1110 +  return buffer;
1111 +}
1112 +
1113 +static struct vmhd_t* vmhd_init()
1114 +{
1115 +  struct vmhd_t* atom = (struct vmhd_t*)malloc(sizeof(struct vmhd_t));
1116 +
1117 +  return atom;
1118 +}
1119 +
1120 +void vmhd_exit(struct vmhd_t* atom)
1121 +{
1122 +  free(atom);
1123 +}
1124 +
1125 +static void* vmhd_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
1126 +{
1127 +  unsigned int i;
1128 +
1129 +  struct vmhd_t* atom;
1130 +
1131 +  if(size < 20-8)
1132 +    return 0;
1133 +
1134 +  atom = vmhd_init();
1135 +  atom->version_ = read_8(buffer + 0);
1136 +  atom->flags_ = read_24(buffer + 1);
1137 +
1138 +  atom->graphics_mode_ = read_16(buffer + 4);
1139 +  buffer += 6;
1140 +  for(i = 0; i != 3; ++i)
1141 +  {
1142 +    atom->opcolor_[i] = read_16(buffer);
1143 +    buffer += 2;
1144 +  }
1145 +
1146 +  return atom;
1147 +}
1148 +
1149 +static unsigned char* vmhd_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
1150 +{
1151 +  struct vmhd_t const* vmhd = atom;
1152 +  unsigned int i;
1153 +
1154 +  buffer = write_8(buffer, vmhd->version_);
1155 +  buffer = write_24(buffer, vmhd->flags_);
1156 +  buffer = write_16(buffer, vmhd->graphics_mode_);
1157 +  for(i = 0; i != 3; ++i)
1158 +  {
1159 +    buffer = write_16(buffer, vmhd->opcolor_[i]);
1160 +  }
1161 +
1162 +  return buffer;
1163 +}
1164 +
1165 +static struct hdlr_t* hdlr_init()
1166 +{
1167 +  struct hdlr_t* atom = (struct hdlr_t*)malloc(sizeof(struct hdlr_t));
1168 +  atom->name_ = 0;
1169 +
1170 +  return atom;
1171 +}
1172 +
1173 +static void hdlr_exit(struct hdlr_t* atom)
1174 +{
1175 +  if(atom->name_)
1176 +  {
1177 +    free(atom->name_);
1178 +  }
1179 +  free(atom);
1180 +}
1181 +
1182 +static void* hdlr_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
1183 +{
1184 +  struct hdlr_t* atom;
1185 +
1186 +  if(size < 8)
1187 +    return 0;
1188 +
1189 +  atom = hdlr_init();
1190 +  atom->version_ = read_8(buffer + 0);
1191 +  atom->flags_ = read_24(buffer + 1);
1192 +  atom->predefined_ = read_32(buffer + 4);
1193 +  atom->handler_type_ = read_32(buffer + 8);
1194 +  atom->reserved1_ = read_32(buffer + 12);
1195 +  atom->reserved2_ = read_32(buffer + 16);
1196 +  atom->reserved3_ = read_32(buffer + 20);
1197 +  buffer += 24;
1198 +  size -= 24;
1199 +  if(size > 0)
1200 +  {
1201 +    size_t length = (size_t)size;
1202 +    atom->name_ = malloc(length + 1);
1203 +    if(atom->predefined_ == FOURCC('m', 'h', 'l', 'r'))
1204 +    {
1205 +      length = read_8(buffer);
1206 +      buffer += 1;
1207 +      if(size < length)
1208 +        length = (size_t)size;
1209 +    }
1210 +    memcpy(atom->name_, buffer, length);
1211 +    atom->name_[length] = '\0';
1212 +  }
1213 +
1214 +  return atom;
1215 +}
1216 +
1217 +static unsigned char* hdlr_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
1218 +{
1219 +  struct hdlr_t* hdlr = atom;
1220 +  buffer = write_8(buffer, hdlr->version_);
1221 +  buffer = write_24(buffer, hdlr->flags_);
1222 +
1223 +  buffer = write_32(buffer, hdlr->predefined_);
1224 +  buffer = write_32(buffer, hdlr->handler_type_);
1225 +  buffer = write_32(buffer, hdlr->reserved1_);
1226 +  buffer = write_32(buffer, hdlr->reserved2_);
1227 +  buffer = write_32(buffer, hdlr->reserved3_);
1228 +  if(hdlr->name_)
1229 +  {
1230 +    char const* p;
1231 +    if(hdlr->predefined_ == FOURCC('m', 'h', 'l', 'r'))
1232 +    {
1233 +      buffer = write_8(buffer, strlen(hdlr->name_));
1234 +    }
1235 +
1236 +    for(p = hdlr->name_; *p; ++p)
1237 +      buffer = write_8(buffer, *p);
1238 +  }
1239 +
1240 +  return buffer;
1241 +}
1242 +
1243 +static struct stts_t* stts_init()
1244 +{
1245 +  struct stts_t* atom = (struct stts_t*)malloc(sizeof(struct stts_t));
1246 +  atom->table_ = 0;
1247 +
1248 +  return atom;
1249 +}
1250 +
1251 +void stts_exit(struct stts_t* atom)
1252 +{
1253 +  if(atom->table_)
1254 +  {
1255 +    free(atom->table_);
1256 +  }
1257 +  free(atom);
1258 +}
1259 +
1260 +static void* stts_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
1261 +{
1262 +  unsigned int i;
1263 +
1264 +  struct stts_t* atom;
1265 +
1266 +  if(size < 8)
1267 +    return 0;
1268 +
1269 +  atom = stts_init();
1270 +  atom->version_ = read_8(buffer + 0);
1271 +  atom->flags_ = read_24(buffer + 1);
1272 +  atom->entries_ = read_32(buffer + 4);
1273 +
1274 +  if(size < 8 + atom->entries_ * sizeof(struct stts_table_t))
1275 +    return 0;
1276 +
1277 +  buffer += 8;
1278 +
1279 +  atom->table_ = (struct stts_table_t*)(malloc(atom->entries_ * sizeof(struct stts_table_t)));
1280 +
1281 +  for(i = 0; i != atom->entries_; ++i)
1282 +  {
1283 +    atom->table_[i].sample_count_ = read_32(buffer + 0);
1284 +    atom->table_[i].sample_duration_ = read_32(buffer + 4);
1285 +    buffer += 8;
1286 +  }
1287 +
1288 +  return atom;
1289 +}
1290 +
1291 +static unsigned char* stts_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
1292 +{
1293 +  struct stts_t* stts = atom;
1294 +  unsigned int i;
1295 +
1296 +  buffer = write_8(buffer, stts->version_);
1297 +  buffer = write_24(buffer, stts->flags_);
1298 +  buffer = write_32(buffer, stts->entries_);
1299 +  for(i = 0; i != stts->entries_; ++i)
1300 +  {
1301 +    buffer = write_32(buffer, stts->table_[i].sample_count_);
1302 +    buffer = write_32(buffer, stts->table_[i].sample_duration_);
1303 +  }
1304 +
1305 +  return buffer;
1306 +}
1307 +
1308 +static unsigned int stts_get_sample(struct stts_t const* stts, uint64_t time)
1309 +{
1310 +  unsigned int stts_index = 0;
1311 +  unsigned int stts_count;
1312 +
1313 +  unsigned int ret = 0;
1314 +  uint64_t time_count = 0;
1315 +
1316 +  for(; stts_index != stts->entries_; ++stts_index)
1317 +  {
1318 +    unsigned int sample_count = stts->table_[stts_index].sample_count_;
1319 +    unsigned int sample_duration = stts->table_[stts_index].sample_duration_;
1320 +    if(time_count + (uint64_t)sample_duration * (uint64_t)sample_count >= time)
1321 +    {
1322 +      stts_count = (unsigned int)((time - time_count) / sample_duration);
1323 +      time_count += (uint64_t)stts_count * (uint64_t)sample_duration;
1324 +      ret += stts_count;
1325 +      break;
1326 +    }
1327 +    else
1328 +    {
1329 +      time_count += (uint64_t)sample_duration * (uint64_t)sample_count;
1330 +      ret += sample_count;
1331 +    }
1332 +  }
1333 +  return ret;
1334 +}
1335 +
1336 +static uint64_t stts_get_time(struct stts_t const* stts, unsigned int sample)
1337 +{
1338 +  uint64_t ret = 0;
1339 +  unsigned int stts_index = 0;
1340 +  unsigned int sample_count = 0;
1341 +  
1342 +  for(;;)
1343 +  {
1344 +    unsigned int table_sample_count = stts->table_[stts_index].sample_count_;
1345 +    unsigned int table_sample_duration = stts->table_[stts_index].sample_duration_;
1346 +    if(sample_count + table_sample_count > sample)
1347 +    {
1348 +      unsigned int stts_count = (sample - sample_count);
1349 +      ret += (uint64_t)stts_count * (uint64_t)table_sample_duration;
1350 +      break;
1351 +    }
1352 +    else
1353 +    {
1354 +      sample_count += table_sample_count;
1355 +      ret += (uint64_t)table_sample_count * (uint64_t)table_sample_duration;
1356 +      stts_index++;
1357 +    }
1358 +  }
1359 +  return ret;
1360 +}
1361 +
1362 +static uint64_t stts_get_duration(struct stts_t const* stts)
1363 +{
1364 +  uint64_t duration = 0;
1365 +  unsigned int i;
1366 +  for(i = 0; i != stts->entries_; ++i)
1367 +  {
1368 +    unsigned int sample_count = stts->table_[i].sample_count_;
1369 +    unsigned int sample_duration = stts->table_[i].sample_duration_;
1370 +    duration += (uint64_t)sample_duration * (uint64_t)sample_count;
1371 +  }
1372 +
1373 +  return duration;
1374 +}
1375 +
1376 +static unsigned int stts_get_samples(struct stts_t const* stts)
1377 +{
1378 +  unsigned int samples = 0;
1379 +  unsigned int entries = stts->entries_;
1380 +  unsigned int i;
1381 +  for(i = 0; i != entries; ++i)
1382 +  {
1383 +    unsigned int sample_count = stts->table_[i].sample_count_;
1384 +//  unsigned int sample_duration = stts->table_[i].sample_duration_;
1385 +    samples += sample_count;
1386 +  }
1387 +
1388 +  return samples;
1389 +}
1390 +
1391 +static struct stss_t* stss_init()
1392 +{
1393 +  struct stss_t* atom = (struct stss_t*)malloc(sizeof(struct stss_t));
1394 +  atom->sample_numbers_ = 0;
1395 +
1396 +  return atom;
1397 +}
1398 +
1399 +void stss_exit(struct stss_t* atom)
1400 +{
1401 +  if(atom->sample_numbers_)
1402 +  {
1403 +    free(atom->sample_numbers_);
1404 +  }
1405 +  free(atom);
1406 +}
1407 +
1408 +static void* stss_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
1409 +{
1410 +  unsigned int i;
1411 +
1412 +  struct stss_t* atom;
1413 +
1414 +  if(size < 8)
1415 +    return 0;
1416 +
1417 +  atom = stss_init();
1418 +  atom->version_ = read_8(buffer + 0);
1419 +  atom->flags_ = read_24(buffer + 1);
1420 +  atom->entries_ = read_32(buffer + 4);
1421 +
1422 +  if(size < 8 + atom->entries_ * sizeof(uint32_t))
1423 +    return 0;
1424 +
1425 +  buffer += 8;
1426 +
1427 +  atom->sample_numbers_ = (uint32_t*)malloc(atom->entries_ * sizeof(uint32_t));
1428 +
1429 +  for(i = 0; i != atom->entries_; ++i)
1430 +  {
1431 +    atom->sample_numbers_[i] = read_32(buffer);
1432 +    buffer += 4;
1433 +  }
1434 +
1435 +  return atom;
1436 +}
1437 +
1438 +static unsigned char* stss_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
1439 +{
1440 +  struct stss_t const* stss = atom;
1441 +  unsigned int i;
1442 +
1443 +  buffer = write_8(buffer, stss->version_);
1444 +  buffer = write_24(buffer, stss->flags_);
1445 +  buffer = write_32(buffer, stss->entries_);
1446 +  for(i = 0; i != stss->entries_; ++i)
1447 +  {
1448 +    buffer = write_32(buffer, stss->sample_numbers_[i]);
1449 +  }
1450 +
1451 +  return buffer;
1452 +}
1453 +
1454 +static unsigned int stss_get_nearest_keyframe(struct stss_t const* stss, unsigned int sample)
1455 +{
1456 +  // scan the sync samples to find the key frame that precedes the sample number
1457 +  unsigned int i;
1458 +  unsigned int table_sample = 0;
1459 +  for(i = 0; i != stss->entries_; ++i)
1460 +  {
1461 +    table_sample = stss->sample_numbers_[i];
1462 +    if(table_sample >= sample)
1463 +      break;
1464 +  }
1465 +  if(table_sample == sample)
1466 +    return table_sample;
1467 +  else
1468 +    return stss->sample_numbers_[i - 1];
1469 +}
1470 +
1471 +static struct stsc_t* stsc_init()
1472 +{
1473 +  struct stsc_t* atom = (struct stsc_t*)malloc(sizeof(struct stsc_t));
1474 +  atom->table_ = 0;
1475 +
1476 +  return atom;
1477 +}
1478 +
1479 +static void stsc_exit(struct stsc_t* atom)
1480 +{
1481 +  if(atom->table_)
1482 +  {
1483 +    free(atom->table_);
1484 +  }
1485 +  free(atom);
1486 +}
1487 +
1488 +static void* stsc_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
1489 +{
1490 +  unsigned int i;
1491 +
1492 +  struct stsc_t* atom;
1493 +
1494 +  if(size < 8)
1495 +    return 0;
1496 +
1497 +  atom = stsc_init();
1498 +  atom->version_ = read_8(buffer + 0);
1499 +  atom->flags_ = read_24(buffer + 1);
1500 +  atom->entries_ = read_32(buffer + 4);
1501 +
1502 +  if(size < 8 + atom->entries_ * sizeof(struct stsc_table_t))
1503 +    return 0;
1504 +
1505 +  buffer += 8;
1506 +
1507 +  // reserve space for one extra entry as when splitting the video we may have to
1508 +  // split the first entry
1509 +  atom->table_ = (struct stsc_table_t*)(malloc((atom->entries_ + 1) * sizeof(struct stsc_table_t)));
1510 +
1511 +  for(i = 0; i != atom->entries_; ++i)
1512 +  {
1513 +    atom->table_[i].chunk_ = read_32(buffer + 0) - 1; // Note: we use zero based
1514 +    atom->table_[i].samples_ = read_32(buffer + 4);
1515 +    atom->table_[i].id_ = read_32(buffer + 8);
1516 +    buffer += 12;
1517 +  }
1518 +
1519 +  return atom;
1520 +}
1521 +
1522 +static unsigned char* stsc_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
1523 +{
1524 +  struct stsc_t* stsc = atom;
1525 +  unsigned int i;
1526 +
1527 +  buffer = write_8(buffer, stsc->version_);
1528 +  buffer = write_24(buffer, stsc->flags_);
1529 +  buffer = write_32(buffer, stsc->entries_);
1530 +  for(i = 0; i != stsc->entries_; ++i)
1531 +  {
1532 +    buffer = write_32(buffer, stsc->table_[i].chunk_ + 1);
1533 +    buffer = write_32(buffer, stsc->table_[i].samples_);
1534 +    buffer = write_32(buffer, stsc->table_[i].id_);
1535 +  }
1536 +
1537 +  return buffer;
1538 +}
1539 +
1540 +static struct stsz_t* stsz_init()
1541 +{
1542 +  struct stsz_t* atom = (struct stsz_t*)malloc(sizeof(struct stsz_t));
1543 +  atom->sample_sizes_ = 0;
1544 +
1545 +  return atom;
1546 +}
1547 +
1548 +static void stsz_exit(struct stsz_t* atom)
1549 +{
1550 +  if(atom->sample_sizes_)
1551 +  {
1552 +    free(atom->sample_sizes_);
1553 +  }
1554 +  free(atom);
1555 +}
1556 +
1557 +static void* stsz_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
1558 +{
1559 +  unsigned int i;
1560 +
1561 +  struct stsz_t* atom;
1562 +
1563 +  if(size < 12)
1564 +  {
1565 +    printf("Error: not enough bytes for stsz atom\n");
1566 +    return 0;
1567 +  }
1568 +
1569 +  atom = stsz_init();
1570 +  atom->version_ = read_8(buffer + 0);
1571 +  atom->flags_ = read_24(buffer + 1);
1572 +  atom->sample_size_ = read_32(buffer + 4);
1573 +  atom->entries_ = read_32(buffer + 8);
1574 +  buffer += 12;
1575 +
1576 +  // fix for clayton.mp4, it mistakenly says there is 1 entry
1577 +  if(atom->sample_size_ && atom->entries_)
1578 +    atom->entries_ = 0;
1579 +
1580 +  if(size < 12 + atom->entries_ * sizeof(uint32_t))
1581 +  {
1582 +    printf("Error: stsz.entries don't match with size\n");
1583 +    stsz_exit(atom);
1584 +    return 0;
1585 +  }
1586 +
1587 +  if(!atom->sample_size_)
1588 +  {
1589 +    atom->sample_sizes_ = (uint32_t*)malloc(atom->entries_ * sizeof(uint32_t));
1590 +    for(i = 0; i != atom->entries_; ++i)
1591 +    {
1592 +      atom->sample_sizes_[i] = read_32(buffer);
1593 +      buffer += 4;
1594 +    }
1595 +  }
1596 +
1597 +  return atom;
1598 +}
1599 +
1600 +static unsigned char* stsz_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
1601 +{
1602 +  struct stsz_t* stsz = atom;
1603 +  unsigned int i;
1604 +  unsigned int entries = stsz->sample_size_ ? 0 : stsz->entries_;
1605 +
1606 +  buffer = write_8(buffer, stsz->version_);
1607 +  buffer = write_24(buffer, stsz->flags_);
1608 +  buffer = write_32(buffer, stsz->sample_size_);
1609 +  buffer = write_32(buffer, entries);
1610 +  for(i = 0; i != entries; ++i)
1611 +  {
1612 +    buffer = write_32(buffer, stsz->sample_sizes_[i]);
1613 +  }
1614 +
1615 +  return buffer;
1616 +}
1617 +
1618 +static struct stco_t* stco_init()
1619 +{
1620 +  struct stco_t* atom = (struct stco_t*)malloc(sizeof(struct stco_t));
1621 +  atom->chunk_offsets_ = 0;
1622 +
1623 +  return atom;
1624 +}
1625 +
1626 +static void stco_exit(struct stco_t* atom)
1627 +{
1628 +  if(atom->chunk_offsets_)
1629 +  {
1630 +    free(atom->chunk_offsets_);
1631 +  }
1632 +  free(atom);
1633 +}
1634 +
1635 +static void* stco_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
1636 +{
1637 +  unsigned int i;
1638 +
1639 +  struct stco_t* atom;
1640 +
1641 +  if(size < 8)
1642 +    return 0;
1643 +
1644 +  atom = stco_init();
1645 +  atom->version_ = read_8(buffer + 0);
1646 +  atom->flags_ = read_24(buffer + 1);
1647 +  atom->entries_ = read_32(buffer + 4);
1648 +  buffer += 8;
1649 +
1650 +  if(size < 8 + atom->entries_ * sizeof(uint32_t))
1651 +    return 0;
1652 +
1653 +  atom->chunk_offsets_ = (uint64_t*)malloc(atom->entries_ * sizeof(uint64_t));
1654 +  for(i = 0; i != atom->entries_; ++i)
1655 +  {
1656 +    atom->chunk_offsets_[i] = read_32(buffer);
1657 +    buffer += 4;
1658 +  }
1659 +
1660 +  return atom;
1661 +}
1662 +
1663 +static void* co64_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
1664 +{
1665 +  unsigned int i;
1666 +
1667 +  struct stco_t* atom;
1668 +
1669 +  if(size < 8)
1670 +    return 0;
1671 +
1672 +  atom = stco_init();
1673 +  atom->version_ = read_8(buffer + 0);
1674 +  atom->flags_ = read_24(buffer + 1);
1675 +  atom->entries_ = read_32(buffer + 4);
1676 +  buffer += 8;
1677 +
1678 +  if(size < 8 + atom->entries_ * sizeof(uint64_t))
1679 +    return 0;
1680 +
1681 +  atom->chunk_offsets_ = (uint64_t*)malloc(atom->entries_ * sizeof(uint64_t));
1682 +  for(i = 0; i != atom->entries_; ++i)
1683 +  {
1684 +    atom->chunk_offsets_[i] = read_64(buffer);
1685 +    buffer += 8;
1686 +  }
1687 +
1688 +  return atom;
1689 +}
1690 +
1691 +static unsigned char* stco_write(void* parent, void* atom, unsigned char* buffer)
1692 +{
1693 +  struct stbl_t* stbl = parent;
1694 +  struct stco_t* stco = atom;
1695 +  unsigned int i;
1696 +
1697 +  stbl->stco_inplace_ = buffer;      // newly generated stco (patched inplace)
1698 +
1699 +  buffer = write_8(buffer, stco->version_);
1700 +  buffer = write_24(buffer, stco->flags_);
1701 +  buffer = write_32(buffer, stco->entries_);
1702 +  for(i = 0; i != stco->entries_; ++i)
1703 +  {
1704 +    buffer = write_32(buffer, (uint32_t)(stco->chunk_offsets_[i]));
1705 +  }
1706 +
1707 +  return buffer;
1708 +}
1709 +
1710 +static void stco_shift_offsets(struct stco_t* stco, int offset)
1711 +{
1712 +  unsigned int i;
1713 +  for(i = 0; i != stco->entries_; ++i)
1714 +    stco->chunk_offsets_[i] += offset;
1715 +}
1716 +
1717 +static void stco_shift_offsets_inplace(unsigned char* stco, int offset)
1718 +{
1719 +  unsigned int entries = read_32(stco + 4);
1720 +  unsigned int* table = (unsigned int*)(stco + 8);
1721 +  unsigned int i;
1722 +  for(i = 0; i != entries; ++i)
1723 +    write_32((unsigned char*)&table[i], (read_32((unsigned char*)&table[i]) + offset));
1724 +}
1725 +
1726 +static struct ctts_t* ctts_init()
1727 +{
1728 +  struct ctts_t* atom = (struct ctts_t*)malloc(sizeof(struct ctts_t));
1729 +  atom->table_ = 0;
1730 +
1731 +  return atom;
1732 +}
1733 +
1734 +static void ctts_exit(struct ctts_t* atom)
1735 +{
1736 +  if(atom->table_)
1737 +  {
1738 +    free(atom->table_);
1739 +  }
1740 +  free(atom);
1741 +}
1742 +
1743 +static void* ctts_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
1744 +{
1745 +  unsigned int i;
1746 +
1747 +  struct ctts_t* atom;
1748 +
1749 +  if(size < 8)
1750 +    return 0;
1751 +
1752 +  atom = ctts_init();
1753 +  atom->version_ = read_8(buffer + 0);
1754 +  atom->flags_ = read_24(buffer + 1);
1755 +  atom->entries_ = read_32(buffer + 4);
1756 +
1757 +  if(size < 8 + atom->entries_ * sizeof(struct ctts_table_t))
1758 +    return 0;
1759 +
1760 +  buffer += 8;
1761 +
1762 +  atom->table_ = (struct ctts_table_t*)(malloc(atom->entries_ * sizeof(struct ctts_table_t)));
1763 +
1764 +  for(i = 0; i != atom->entries_; ++i)
1765 +  {
1766 +    atom->table_[i].sample_count_ = read_32(buffer + 0);
1767 +    atom->table_[i].sample_offset_ = read_32(buffer + 4);
1768 +    buffer += 8;
1769 +  }
1770 +
1771 +  return atom;
1772 +}
1773 +
1774 +static unsigned char* ctts_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
1775 +{
1776 +  struct ctts_t const* ctts = atom;
1777 +  unsigned int i;
1778 +
1779 +  buffer = write_8(buffer, ctts->version_);
1780 +  buffer = write_24(buffer, ctts->flags_);
1781 +  buffer = write_32(buffer, ctts->entries_);
1782 +  for(i = 0; i != ctts->entries_; ++i)
1783 +  {
1784 +    buffer = write_32(buffer, (uint32_t)(ctts->table_[i].sample_count_));
1785 +    buffer = write_32(buffer, (uint32_t)(ctts->table_[i].sample_offset_));
1786 +  }
1787 +
1788 +  return buffer;
1789 +}
1790 +
1791 +static unsigned int ctts_get_samples(struct ctts_t const* ctts)
1792 +{
1793 +  unsigned int samples = 0;
1794 +  unsigned int entries = ctts->entries_;
1795 +  unsigned int i;
1796 +  for(i = 0; i != entries; ++i)
1797 +  {
1798 +    unsigned int sample_count = ctts->table_[i].sample_count_;
1799 +//  unsigned int sample_offset = ctts->table_[i].sample_offset_;
1800 +    samples += sample_count;
1801 +  }
1802 +
1803 +  return samples;
1804 +}
1805 +
1806 +static struct stbl_t* stbl_init()
1807 +{
1808 +  struct stbl_t* atom = (struct stbl_t*)malloc(sizeof(struct stbl_t));
1809 +  atom->unknown_atoms_ = 0;
1810 +  atom->stts_ = 0;
1811 +  atom->stss_ = 0;
1812 +  atom->stsc_ = 0;
1813 +  atom->stsz_ = 0;
1814 +  atom->stco_ = 0;
1815 +  atom->ctts_ = 0;
1816 +
1817 +  return atom;
1818 +}
1819 +
1820 +static void stbl_exit(struct stbl_t* atom)
1821 +{
1822 +  if(atom->unknown_atoms_)
1823 +  {
1824 +    unknown_atom_exit(atom->unknown_atoms_);
1825 +  }
1826 +  if(atom->stts_)
1827 +  {
1828 +    stts_exit(atom->stts_);
1829 +  }
1830 +  if(atom->stss_)
1831 +  {
1832 +    stss_exit(atom->stss_);
1833 +  }
1834 +  if(atom->stsc_)
1835 +  {
1836 +    stsc_exit(atom->stsc_);
1837 +  }
1838 +  if(atom->stsz_)
1839 +  {
1840 +    stsz_exit(atom->stsz_);
1841 +  }
1842 +  if(atom->stco_)
1843 +  {
1844 +    stco_exit(atom->stco_);
1845 +  }
1846 +  if(atom->ctts_)
1847 +  {
1848 +    ctts_exit(atom->ctts_);
1849 +  }
1850 +
1851 +  free(atom);
1852 +}
1853 +
1854 +static int stbl_add_stts(void* parent, void* child)
1855 +{
1856 +  struct stbl_t* stbl = parent;
1857 +  stbl->stts_ = child;
1858 +
1859 +  return 1;
1860 +}
1861 +
1862 +static int stbl_add_stss(void* parent, void* child)
1863 +{
1864 +  struct stbl_t* stbl = parent;
1865 +  stbl->stss_ = child;
1866 +
1867 +  return 1;
1868 +}
1869 +
1870 +static int stbl_add_stsc(void* parent, void* child)
1871 +{
1872 +  struct stbl_t* stbl = parent;
1873 +  stbl->stsc_ = child;
1874 +
1875 +  return 1;
1876 +}
1877 +
1878 +static int stbl_add_stsz(void* parent, void* child)
1879 +{
1880 +  struct stbl_t* stbl = parent;
1881 +  stbl->stsz_ = child;
1882 +
1883 +  return 1;
1884 +}
1885 +
1886 +static int stbl_add_stco(void* parent, void* child)
1887 +{
1888 +  struct stbl_t* stbl = parent;
1889 +  stbl->stco_ = child;
1890 +
1891 +  return 1;
1892 +}
1893 +
1894 +static int stbl_add_ctts(void* parent, void* child)
1895 +{
1896 +  struct stbl_t* stbl = parent;
1897 +  stbl->ctts_ = child;
1898 +
1899 +  return 1;
1900 +}
1901 +
1902 +static void* stbl_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
1903 +{
1904 +  struct stbl_t* atom = stbl_init();
1905 +
1906 +  struct atom_read_list_t atom_read_list[] = {
1907 +    { FOURCC('s', 't', 't', 's'), atom, &stbl_add_stts, &stts_read },
1908 +    { FOURCC('s', 't', 's', 's'), atom, &stbl_add_stss, &stss_read },
1909 +    { FOURCC('s', 't', 's', 'c'), atom, &stbl_add_stsc, &stsc_read },
1910 +    { FOURCC('s', 't', 's', 'z'), atom, &stbl_add_stsz, &stsz_read },
1911 +    { FOURCC('s', 't', 'c', 'o'), atom, &stbl_add_stco, &stco_read },
1912 +    { FOURCC('c', 'o', '6', '4'), atom, &stbl_add_stco, &co64_read },
1913 +    { FOURCC('c', 't', 't', 's'), atom, &stbl_add_ctts, &ctts_read },
1914 +  };
1915 +
1916 +  int result = atom_reader(atom_read_list,
1917 +                  sizeof(atom_read_list) / sizeof(atom_read_list[0]),
1918 +                  atom,
1919 +                  buffer, size);
1920 +
1921 +  // check for mandatory atoms
1922 +  if(!atom->stts_)
1923 +  {
1924 +    printf("stbl: missing stts\n");
1925 +    result = 0;
1926 +  }
1927 +
1928 +  if(!atom->stsc_)
1929 +  {
1930 +    printf("stbl: missing stsc\n");
1931 +    result = 0;
1932 +  }
1933 +
1934 +  if(!atom->stsz_)
1935 +  {
1936 +    printf("stbl: missing stsz\n");
1937 +    result = 0;
1938 +  }
1939 +
1940 +  if(!atom->stco_)
1941 +  {
1942 +    printf("stbl: missing stco\n");
1943 +    result = 0;
1944 +  }
1945 +
1946 +  if(!result)
1947 +  {
1948 +    stbl_exit(atom);
1949 +    return 0;
1950 +  }
1951 +
1952 +  return atom;
1953 +}
1954 +
1955 +static unsigned char* stbl_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
1956 +{
1957 +  struct stbl_t* stbl = atom;
1958 +  struct atom_write_list_t atom_write_list[] = {
1959 +    { FOURCC('s', 't', 't', 's'), stbl, stbl->stts_, &stts_write },
1960 +    { FOURCC('s', 't', 's', 's'), stbl, stbl->stss_, &stss_write },
1961 +    { FOURCC('s', 't', 's', 'c'), stbl, stbl->stsc_, &stsc_write },
1962 +    { FOURCC('s', 't', 's', 'z'), stbl, stbl->stsz_, &stsz_write },
1963 +    { FOURCC('s', 't', 'c', 'o'), stbl, stbl->stco_, &stco_write },
1964 +    { FOURCC('c', 't', 't', 's'), stbl, stbl->ctts_, &ctts_write },
1965 +  };
1966 +
1967 +  buffer = atom_writer(stbl->unknown_atoms_,
1968 +                       atom_write_list,
1969 +                       sizeof(atom_write_list) / sizeof(atom_write_list[0]),
1970 +                       buffer);
1971 +
1972 +  return buffer;
1973 +}
1974 +
1975 +static unsigned int stbl_get_nearest_keyframe(struct stbl_t const* stbl, unsigned int sample)
1976 +{
1977 +  // If the sync atom is not present, all samples are implicit sync samples.
1978 +  if(!stbl->stss_)
1979 +    return sample;
1980 +
1981 +  return stss_get_nearest_keyframe(stbl->stss_, sample);
1982 +}
1983 +
1984 +static struct minf_t* minf_init()
1985 +{
1986 +  struct minf_t* atom = (struct minf_t*)malloc(sizeof(struct minf_t));
1987 +  atom->unknown_atoms_ = 0;
1988 +  atom->vmhd_ = 0;
1989 +  atom->stbl_ = 0;
1990 +
1991 +  return atom;
1992 +}
1993 +
1994 +static void minf_exit(struct minf_t* atom)
1995 +{
1996 +  if(atom->unknown_atoms_)
1997 +  {
1998 +    unknown_atom_exit(atom->unknown_atoms_);
1999 +  }
2000 +  if(atom->vmhd_)
2001 +  {
2002 +    vmhd_exit(atom->vmhd_);
2003 +  }
2004 +  if(atom->stbl_)
2005 +  {
2006 +    stbl_exit(atom->stbl_);
2007 +  }
2008 +  free(atom);
2009 +}
2010 +
2011 +static int minf_add_vmhd(void* parent, void* child)
2012 +{
2013 +  struct minf_t* minf = parent;
2014 +  minf->vmhd_ = child;
2015 +
2016 +  return 1;
2017 +}
2018 +
2019 +static int minf_add_stbl(void* parent, void* child)
2020 +{
2021 +  struct minf_t* minf = parent;
2022 +  minf->stbl_ = child;
2023 +
2024 +  return 1;
2025 +}
2026 +
2027 +static void* minf_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
2028 +{
2029 +  struct minf_t* atom = minf_init();
2030 +
2031 +  struct atom_read_list_t atom_read_list[] = {
2032 +    { FOURCC('v', 'm', 'h', 'd'), atom, &minf_add_vmhd, &vmhd_read },
2033 +    { FOURCC('s', 't', 'b', 'l'), atom, &minf_add_stbl, &stbl_read }
2034 +  };
2035 +
2036 +  int result = atom_reader(atom_read_list,
2037 +                  sizeof(atom_read_list) / sizeof(atom_read_list[0]),
2038 +                  atom,
2039 +                  buffer, size);
2040 +
2041 +  // check for mandatory atoms
2042 +  if(!atom->stbl_)
2043 +  {
2044 +    printf("minf: missing stbl\n");
2045 +    result = 0;
2046 +  }
2047 +
2048 +  if(!result)
2049 +  {
2050 +    minf_exit(atom);
2051 +    return 0;
2052 +  }
2053 +
2054 +  return atom;
2055 +}
2056 +
2057 +static unsigned char* minf_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
2058 +{
2059 +  struct minf_t const* minf = atom;
2060 +  struct atom_write_list_t atom_write_list[] = {
2061 +    { FOURCC('v', 'm', 'h', 'd'), atom, minf->vmhd_, &vmhd_write },
2062 +    { FOURCC('s', 't', 'b', 'l'), atom, minf->stbl_, &stbl_write }
2063 +  };
2064 +
2065 +  buffer = atom_writer(minf->unknown_atoms_,
2066 +                       atom_write_list,
2067 +                       sizeof(atom_write_list) / sizeof(atom_write_list[0]),
2068 +                       buffer);
2069 +
2070 +  return buffer;
2071 +}
2072 +
2073 +static struct mdia_t* mdia_init()
2074 +{
2075 +  struct mdia_t* atom = (struct mdia_t*)malloc(sizeof(struct mdia_t));
2076 +  atom->unknown_atoms_ = 0;
2077 +  atom->mdhd_ = 0;
2078 +  atom->hdlr_ = 0;
2079 +  atom->minf_ = 0;
2080 +
2081 +  return atom;
2082 +}
2083 +
2084 +static void mdia_exit(struct mdia_t* atom)
2085 +{
2086 +  if(atom->unknown_atoms_)
2087 +  {
2088 +    unknown_atom_exit(atom->unknown_atoms_);
2089 +  }
2090 +  if(atom->mdhd_)
2091 +  {
2092 +    mdhd_exit(atom->mdhd_);
2093 +  }
2094 +  if(atom->hdlr_)
2095 +  {
2096 +    hdlr_exit(atom->hdlr_);
2097 +  }
2098 +  if(atom->minf_)
2099 +  {
2100 +    minf_exit(atom->minf_);
2101 +  }
2102 +  free(atom);
2103 +}
2104 +
2105 +static int mdia_add_mdhd(void* parent, void* child)
2106 +{
2107 +  struct mdia_t* mdia = parent;
2108 +  mdia->mdhd_ = child;
2109 +
2110 +  return 1;
2111 +}
2112 +
2113 +static int mdia_add_hdlr(void* parent, void* child)
2114 +{
2115 +  struct mdia_t* mdia = parent;
2116 +  mdia->hdlr_ = child;
2117 +
2118 +  return 1;
2119 +}
2120 +
2121 +static int mdia_add_minf(void* parent, void* child)
2122 +{
2123 +  struct mdia_t* mdia = parent;
2124 +  mdia->minf_ = child;
2125 +
2126 +  return 1;
2127 +}
2128 +
2129 +static void* mdia_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
2130 +{
2131 +  struct mdia_t* atom = mdia_init();
2132 +
2133 +  struct atom_read_list_t atom_read_list[] = {
2134 +    { FOURCC('m', 'd', 'h', 'd'), atom, &mdia_add_mdhd, &mdhd_read },
2135 +    { FOURCC('h', 'd', 'l', 'r'), atom, &mdia_add_hdlr, &hdlr_read },
2136 +    { FOURCC('m', 'i', 'n', 'f'), atom, &mdia_add_minf, &minf_read }
2137 +  };
2138 +
2139 +  int result = atom_reader(atom_read_list,
2140 +                  sizeof(atom_read_list) / sizeof(atom_read_list[0]),
2141 +                  atom,
2142 +                  buffer, size);
2143 +
2144 +  // check for mandatory atoms
2145 +  if(!atom->mdhd_)
2146 +  {
2147 +    printf("mdia: missing mdhd\n");
2148 +    result = 0;
2149 +  }
2150 +
2151 +  if(!atom->hdlr_)
2152 +  {
2153 +    printf("mdia: missing hdlr\n");
2154 +    result = 0;
2155 +  }
2156 +
2157 +  if(!atom->minf_)
2158 +  {
2159 +    printf("mdia: missing minf\n");
2160 +    result = 0;
2161 +  }
2162 +
2163 +  if(!result)
2164 +  {
2165 +    mdia_exit(atom);
2166 +    return 0;
2167 +  }
2168 +
2169 +  return atom;
2170 +}
2171 +
2172 +static unsigned char* mdia_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
2173 +{
2174 +  struct mdia_t const* mdia = atom;
2175 +  struct atom_write_list_t atom_write_list[] = {
2176 +    { FOURCC('m', 'd', 'h', 'd'), atom, mdia->mdhd_, &mdhd_write },
2177 +    { FOURCC('h', 'd', 'l', 'r'), atom, mdia->hdlr_, &hdlr_write },
2178 +    { FOURCC('m', 'i', 'n', 'f'), atom, mdia->minf_, &minf_write }
2179 +  };
2180 +
2181 +  buffer = atom_writer(mdia->unknown_atoms_,
2182 +                       atom_write_list,
2183 +                       sizeof(atom_write_list) / sizeof(atom_write_list[0]),
2184 +                       buffer);
2185 +
2186 +  return buffer;
2187 +}
2188 +
2189 +void trak_build_index(struct trak_t* trak)
2190 +{
2191 +  struct stco_t const* stco = trak->mdia_->minf_->stbl_->stco_;
2192 +
2193 +  trak->chunks_size_ = stco->entries_;
2194 +  trak->chunks_ = malloc(trak->chunks_size_ * sizeof(struct chunks_t));
2195 +
2196 +  {
2197 +    unsigned int i;
2198 +    for(i = 0; i != trak->chunks_size_; ++i)
2199 +    {
2200 +      trak->chunks_[i].pos_ = stco->chunk_offsets_[i];
2201 +    }
2202 +  }
2203 +
2204 +  // process chunkmap:
2205 +  {
2206 +    struct stsc_t const* stsc = trak->mdia_->minf_->stbl_->stsc_;
2207 +    unsigned int last = trak->chunks_size_;
2208 +    unsigned int i = stsc->entries_;
2209 +    while(i > 0)
2210 +    {
2211 +      unsigned int j;
2212 +
2213 +      --i;
2214 +
2215 +      for(j = stsc->table_[i].chunk_; j < last; j++)
2216 +      {
2217 +        trak->chunks_[j].id_ = stsc->table_[i].id_;
2218 +        trak->chunks_[j].size_ = stsc->table_[i].samples_;
2219 +      }
2220 +      last = stsc->table_[i].chunk_;
2221 +    }
2222 +  }
2223 +
2224 +  // calc pts of chunks:
2225 +  {
2226 +    struct stsz_t const* stsz = trak->mdia_->minf_->stbl_->stsz_;
2227 +    unsigned int sample_size = stsz->sample_size_;
2228 +    unsigned int s = 0;
2229 +    {
2230 +      unsigned int j;
2231 +      for(j = 0; j < trak->chunks_size_; j++)
2232 +      {
2233 +        trak->chunks_[j].sample_ = s;
2234 +        s += trak->chunks_[j].size_;
2235 +      }
2236 +    }
2237 +
2238 +    if(sample_size == 0)
2239 +    {
2240 +      trak->samples_size_ = stsz->entries_;
2241 +    }
2242 +    else
2243 +    {
2244 +      trak->samples_size_ = s;
2245 +    }
2246 +
2247 +    trak->samples_ = malloc(trak->samples_size_ * sizeof(struct samples_t));
2248 +
2249 +    if(sample_size == 0)
2250 +    {
2251 +      unsigned int i;
2252 +      for(i = 0; i != trak->samples_size_ ; ++i)
2253 +        trak->samples_[i].size_ = stsz->sample_sizes_[i];
2254 +    }
2255 +    else
2256 +    {
2257 +      unsigned int i;
2258 +      for(i = 0; i != trak->samples_size_ ; ++i)
2259 +        trak->samples_[i].size_ = sample_size;
2260 +    }
2261 +  }
2262 +
2263 +//  i = 0;
2264 +//  for (j = 0; j < trak->durmap_size; j++)
2265 +//    i += trak->durmap[j].num;
2266 +//  if (i != s) {
2267 +//    mp_msg(MSGT_DEMUX, MSGL_WARN,
2268 +//           "MOV: durmap and chunkmap sample count differ (%i vs %i)\n", i, s);
2269 +//    if (i > s) s = i;
2270 +//  }
2271 +
2272 +  // calc pts:
2273 +  {
2274 +    struct stts_t const* stts = trak->mdia_->minf_->stbl_->stts_;
2275 +    unsigned int s = 0;
2276 +    unsigned int pts = 0;
2277 +    unsigned int entries = stts->entries_;
2278 +    unsigned int j;
2279 +    for(j = 0; j < entries; j++)
2280 +    {
2281 +      unsigned int i;
2282 +      unsigned int sample_count = stts->table_[j].sample_count_;
2283 +      unsigned int sample_duration = stts->table_[j].sample_duration_;
2284 +      for(i = 0; i < sample_count; i++)
2285 +      {
2286 +        trak->samples_[s].pts_ = pts;
2287 +        ++s;
2288 +        pts += sample_duration;
2289 +      }
2290 +    }
2291 +  }
2292 +
2293 +  // calc composition times:
2294 +  {
2295 +    struct ctts_t const* ctts = trak->mdia_->minf_->stbl_->ctts_;
2296 +    if(ctts)
2297 +    {
2298 +      unsigned int s = 0;
2299 +      unsigned int entries = ctts->entries_;
2300 +      unsigned int j;
2301 +      for(j = 0; j != entries; j++)
2302 +      {
2303 +        unsigned int i;
2304 +        unsigned int sample_count = ctts->table_[j].sample_count_;
2305 +        unsigned int sample_offset = ctts->table_[j].sample_offset_;
2306 +        for(i = 0; i < sample_count; i++)
2307 +        {
2308 +          trak->samples_[s].cto_ = sample_offset;
2309 +          ++s;
2310 +        }
2311 +      }
2312 +    }
2313 +  }
2314 +
2315 +  // calc sample offsets
2316 +  {
2317 +    unsigned int s = 0;
2318 +    unsigned int j;
2319 +    for(j = 0; j != trak->chunks_size_; j++)
2320 +    {
2321 +      uint64_t pos = trak->chunks_[j].pos_;
2322 +      unsigned int i;
2323 +      for(i = 0; i != trak->chunks_[j].size_; i++)
2324 +      {
2325 +        trak->samples_[s].pos_ = pos;
2326 +        pos += trak->samples_[s].size_;
2327 +        ++s;
2328 +      }
2329 +    }
2330 +  }
2331 +}
2332 +
2333 +void trak_update_index(struct trak_t* trak, unsigned int start, unsigned int end)
2334 +{
2335 +  // write samples [start,end>
2336 +
2337 +  // stts = [entries * [sample_count, sample_duration]
2338 +  {
2339 +    struct stts_t* stts = trak->mdia_->minf_->stbl_->stts_;
2340 +
2341 +    unsigned int entries = 0;
2342 +    unsigned int s;
2343 +
2344 +    for(s = start; s != end; ++s)
2345 +    {
2346 +      unsigned int sample_count = 1;
2347 +      unsigned int sample_duration =
2348 +        trak->samples_[s + 1].pts_ - trak->samples_[s].pts_;
2349 +      while(s != end - 1)
2350 +      {
2351 +        if((trak->samples_[s + 1].pts_ - trak->samples_[s].pts_) != sample_duration)
2352 +          break;
2353 +        ++sample_count;
2354 +        ++s;
2355 +      }
2356 +      stts->table_[entries].sample_count_ = sample_count;
2357 +      stts->table_[entries].sample_duration_ = sample_duration;
2358 +      ++entries;
2359 +    }
2360 +    stts->entries_ = entries;
2361 +
2362 +    if(stts_get_samples(stts) != end - start)
2363 +    {
2364 +      printf("ERROR: stts_get_samples=%d, should be %d\n",
2365 +             stts_get_samples(stts), end - start);
2366 +    }
2367 +  }
2368 +
2369 +  // ctts = [entries * [sample_count, sample_offset]
2370 +  {
2371 +    struct ctts_t* ctts = trak->mdia_->minf_->stbl_->ctts_;
2372 +    if(ctts)
2373 +    {
2374 +      unsigned int entries = 0;
2375 +      unsigned int s;
2376 +
2377 +      for(s = start; s != end; ++s)
2378 +      {
2379 +        unsigned int sample_count = 1;
2380 +        unsigned int sample_offset = trak->samples_[s].cto_;
2381 +        while(s != end - 1)
2382 +        {
2383 +          if(trak->samples_[s + 1].cto_ != sample_offset)
2384 +            break;
2385 +          ++sample_count;
2386 +          ++s;
2387 +        }
2388 +        // write entry
2389 +        ctts->table_[entries].sample_count_ = sample_count;
2390 +        ctts->table_[entries].sample_offset_ = sample_offset;
2391 +        ++entries;
2392 +      }
2393 +      ctts->entries_ = entries;
2394 +      if(ctts_get_samples(ctts) != end - start)
2395 +      {
2396 +        printf("ERROR: ctts_get_samples=%d, should be %d\n",
2397 +               ctts_get_samples(ctts), end - start);
2398 +      }
2399 +    }
2400 +  }
2401 +
2402 +  // process chunkmap:
2403 +  {
2404 +    struct stsc_t* stsc = trak->mdia_->minf_->stbl_->stsc_;
2405 +    unsigned int i;
2406 +
2407 +    for(i = 0; i != trak->chunks_size_; ++i)
2408 +    {
2409 +      if(trak->chunks_[i].sample_ + trak->chunks_[i].size_ > start)
2410 +        break;
2411 +    }
2412 +
2413 +    {
2414 +      unsigned int stsc_entries = 0;
2415 +      unsigned int chunk_start = i;
2416 +      unsigned int chunk_end;
2417 +      // problem.mp4: reported by Jin-seok Lee. Second track contains no samples
2418 +      if(trak->chunks_size_ != 0)
2419 +      {
2420 +        unsigned int samples =
2421 +          trak->chunks_[i].sample_ + trak->chunks_[i].size_ - start;
2422 +        unsigned int id = trak->chunks_[i].id_;
2423 +
2424 +        // write entry [chunk,samples,id]
2425 +        stsc->table_[stsc_entries].chunk_ = 0;
2426 +        stsc->table_[stsc_entries].samples_ = samples;
2427 +        stsc->table_[stsc_entries].id_ = id;
2428 +        ++stsc_entries;
2429 +
2430 +        if(i != trak->chunks_size_)
2431 +        {
2432 +          for(i += 1; i != trak->chunks_size_; ++i)
2433 +          {
2434 +            if(trak->chunks_[i].sample_ >= end)
2435 +              break;
2436 +
2437 +            if(trak->chunks_[i].size_ != samples)
2438 +            {
2439 +              samples = trak->chunks_[i].size_;
2440 +              id = trak->chunks_[i].id_;
2441 +
2442 +              stsc->table_[stsc_entries].chunk_ = i - chunk_start;
2443 +              stsc->table_[stsc_entries].samples_ = samples;
2444 +              stsc->table_[stsc_entries].id_ = id;
2445 +              ++stsc_entries;
2446 +            }
2447 +          }
2448 +        }
2449 +      }
2450 +      chunk_end = i;
2451 +      stsc->entries_ = stsc_entries;
2452 +
2453 +      {
2454 +        struct stco_t* stco = trak->mdia_->minf_->stbl_->stco_;
2455 +        unsigned int entries = 0;
2456 +        for(i = chunk_start; i != chunk_end; ++i)
2457 +        {
2458 +          stco->chunk_offsets_[entries] = stco->chunk_offsets_[i];
2459 +          ++entries;
2460 +        }
2461 +        stco->entries_ = entries;
2462 +
2463 +        // patch first chunk with correct sample offset
2464 +        stco->chunk_offsets_[0] = (uint32_t)trak->samples_[start].pos_;
2465 +      }
2466 +    }
2467 +  }
2468 +
2469 +  // process sync samples:
2470 +  if(trak->mdia_->minf_->stbl_->stss_)
2471 +  {
2472 +    struct stss_t* stss = trak->mdia_->minf_->stbl_->stss_;
2473 +    unsigned int entries = 0;
2474 +    unsigned int stss_start;
2475 +    unsigned int i;
2476 +
2477 +    for(i = 0; i != stss->entries_; ++i)
2478 +    {
2479 +      if(stss->sample_numbers_[i] >= start + 1)
2480 +        break;
2481 +    }
2482 +    stss_start = i;
2483 +    for(; i != stss->entries_; ++i)
2484 +    {
2485 +      unsigned int sync_sample = stss->sample_numbers_[i];
2486 +      if(sync_sample >= end + 1)
2487 +        break;
2488 +      stss->sample_numbers_[entries] = sync_sample - start;
2489 +      ++entries;
2490 +    }
2491 +    stss->entries_ = entries;
2492 +  }
2493 +
2494 +  // process sample sizes
2495 +  {
2496 +    struct stsz_t* stsz = trak->mdia_->minf_->stbl_->stsz_;
2497 +
2498 +    if(stsz->sample_size_ == 0)
2499 +    {
2500 +      unsigned int entries = 0;
2501 +      unsigned int i;
2502 +      for(i = start; i != end; ++i)
2503 +      {
2504 +        stsz->sample_sizes_[entries] = stsz->sample_sizes_[i];
2505 +        ++entries;
2506 +      }
2507 +      stsz->entries_ = entries;
2508 +    }
2509 +  }
2510 +}
2511 +
2512 +static struct trak_t* trak_init()
2513 +{
2514 +  struct trak_t* trak = (struct trak_t*)malloc(sizeof(struct trak_t));
2515 +  trak->unknown_atoms_ = 0;
2516 +  trak->tkhd_ = 0;
2517 +  trak->mdia_ = 0;
2518 +  trak->chunks_size_ = 0;
2519 +  trak->chunks_ = 0;
2520 +  trak->samples_size_ = 0;
2521 +  trak->samples_ = 0;
2522 +
2523 +  return trak;
2524 +}
2525 +
2526 +static void trak_exit(struct trak_t* trak)
2527 +{
2528 +  if(trak->unknown_atoms_)
2529 +  {
2530 +    unknown_atom_exit(trak->unknown_atoms_);
2531 +  }
2532 +  if(trak->tkhd_)
2533 +  {
2534 +    tkhd_exit(trak->tkhd_);
2535 +  }
2536 +  if(trak->mdia_)
2537 +  {
2538 +    mdia_exit(trak->mdia_);
2539 +  }
2540 +  if(trak->chunks_)
2541 +  {
2542 +    free(trak->chunks_);
2543 +  }
2544 +  if(trak->samples_)
2545 +  {
2546 +    free(trak->samples_);
2547 +  }
2548 +  free(trak);
2549 +}
2550 +
2551 +static int trak_add_tkhd(void* parent, void* tkhd)
2552 +{
2553 +  struct trak_t* trak = parent;
2554 +  trak->tkhd_ = tkhd;
2555 +
2556 +  return 1;
2557 +}
2558 +
2559 +static int trak_add_mdia(void* parent, void* mdia)
2560 +{
2561 +  struct trak_t* trak = parent;
2562 +  trak->mdia_ = mdia;
2563 +
2564 +  return 1;
2565 +}
2566 +
2567 +static void* trak_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
2568 +{
2569 +  struct trak_t* atom = trak_init();
2570 +
2571 +  struct atom_read_list_t atom_read_list[] = {
2572 +    { FOURCC('t', 'k', 'h', 'd'), atom, &trak_add_tkhd, &tkhd_read },
2573 +    { FOURCC('m', 'd', 'i', 'a'), atom, &trak_add_mdia, &mdia_read }
2574 +  };
2575 +
2576 +  int result = atom_reader(atom_read_list,
2577 +                  sizeof(atom_read_list) / sizeof(atom_read_list[0]),
2578 +                  atom,
2579 +                  buffer, size);
2580 +
2581 +  // check for mandatory atoms
2582 +  if(!atom->tkhd_)
2583 +  {
2584 +    printf("trak: missing tkhd\n");
2585 +    result = 0;
2586 +  }
2587 +
2588 +  if(!atom->mdia_)
2589 +  {
2590 +    printf("trak: missing mdia\n");
2591 +    result = 0;
2592 +  }
2593 +
2594 +  if(!result)
2595 +  {
2596 +    trak_exit(atom);
2597 +    return 0;
2598 +  }
2599 +
2600 +  trak_build_index(atom);
2601 +
2602 +  return atom;
2603 +}
2604 +
2605 +static unsigned char* trak_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
2606 +{
2607 +  struct trak_t* trak = atom;
2608 +  struct atom_write_list_t atom_write_list[] = {
2609 +    { FOURCC('t', 'k', 'h', 'd'), atom, trak->tkhd_, &tkhd_write },
2610 +    { FOURCC('m', 'd', 'i', 'a'), atom, trak->mdia_, &mdia_write }
2611 +  };
2612 +
2613 +  buffer = atom_writer(trak->unknown_atoms_,
2614 +                       atom_write_list,
2615 +                       sizeof(atom_write_list) / sizeof(atom_write_list[0]),
2616 +                       buffer);
2617 +
2618 +  return buffer;
2619 +}
2620 +
2621 +void trak_shift_offsets(struct trak_t* trak, int64_t offset)
2622 +{
2623 +  struct stco_t* stco = trak->mdia_->minf_->stbl_->stco_;
2624 +  stco_shift_offsets(stco, (int32_t)offset);
2625 +}
2626 +
2627 +void trak_shift_offsets_inplace(struct trak_t* trak, int64_t offset)
2628 +{
2629 +  void* stco = trak->mdia_->minf_->stbl_->stco_inplace_;
2630 +  stco_shift_offsets_inplace(stco, (int32_t)offset);
2631 +}
2632 +
2633 +static struct mvhd_t* mvhd_init()
2634 +{
2635 +  struct mvhd_t* atom = (struct mvhd_t*)malloc(sizeof(struct mvhd_t));
2636 +
2637 +  return atom;
2638 +}
2639 +
2640 +void mvhd_exit(struct mvhd_t* atom)
2641 +{
2642 +  free(atom);
2643 +}
2644 +
2645 +static void* mvhd_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
2646 +{
2647 +  unsigned int i;
2648 +
2649 +  struct mvhd_t* atom = mvhd_init();
2650 +  atom->version_ = read_8(buffer + 0);
2651 +  atom->flags_ = read_24(buffer + 1);
2652 +  if(atom->version_ == 0)
2653 +  {
2654 +    if(size < 108-8)
2655 +      return 0;
2656 +
2657 +    atom->creation_time_ = read_32(buffer + 4);
2658 +    atom->modification_time_ = read_32(buffer + 8);
2659 +    atom->timescale_ = read_32(buffer + 12);
2660 +    atom->duration_ = read_32(buffer + 16);
2661 +    buffer += 20;
2662 +  }
2663 +  else
2664 +  {
2665 +    if(size < 120-8)
2666 +      return 0;
2667 +
2668 +    atom->creation_time_ = read_64(buffer + 4);
2669 +    atom->modification_time_ = read_64(buffer + 12);
2670 +    atom->timescale_ = read_32(buffer + 20);
2671 +    atom->duration_ = read_64(buffer + 24);
2672 +    buffer += 32;
2673 +  }
2674 +  atom->rate_ = read_32(buffer + 0);
2675 +  atom->volume_ = read_16(buffer + 4);
2676 +  atom->reserved1_ = read_16(buffer + 6);
2677 +  atom->reserved2_[0] = read_32(buffer + 8);
2678 +  atom->reserved2_[1] = read_32(buffer + 12);
2679 +  buffer += 16;
2680 +
2681 +  for(i = 0; i != 9; ++i)
2682 +  {
2683 +    atom->matrix_[i] = read_32(buffer);
2684 +    buffer += 4;
2685 +  }
2686 +
2687 +  for(i = 0; i != 6; ++i)
2688 +  {
2689 +    atom->predefined_[i] = read_32(buffer);
2690 +    buffer += 4;
2691 +  }
2692 +
2693 +  atom->next_track_id_ = read_32(buffer + 0);
2694 +
2695 +  return atom;
2696 +}
2697 +
2698 +static unsigned char* mvhd_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
2699 +{
2700 +  struct mvhd_t const* mvhd = atom;
2701 +  unsigned int i;
2702 +
2703 +  buffer = write_8(buffer, mvhd->version_);
2704 +  buffer = write_24(buffer, mvhd->flags_);
2705 +
2706 +  if(mvhd->version_ == 0)
2707 +  {
2708 +    buffer = write_32(buffer, (uint32_t)mvhd->creation_time_);
2709 +    buffer = write_32(buffer, (uint32_t)mvhd->modification_time_);
2710 +    buffer = write_32(buffer, mvhd->timescale_);
2711 +    buffer = write_32(buffer, (uint32_t)mvhd->duration_);
2712 +  }
2713 +  else
2714 +  {
2715 +    buffer = write_64(buffer, mvhd->creation_time_);
2716 +    buffer = write_64(buffer, mvhd->modification_time_);
2717 +    buffer = write_32(buffer, mvhd->timescale_);
2718 +    buffer = write_64(buffer, mvhd->duration_);
2719 +  }
2720 +
2721 +  buffer = write_32(buffer, mvhd->rate_);
2722 +  buffer = write_16(buffer, mvhd->volume_);
2723 +  buffer = write_16(buffer, mvhd->reserved1_);
2724 +  buffer = write_32(buffer, mvhd->reserved2_[0]);
2725 +  buffer = write_32(buffer, mvhd->reserved2_[1]);
2726 +
2727 +  for(i = 0; i != 9; ++i)
2728 +  {
2729 +    buffer = write_32(buffer, mvhd->matrix_[i]);
2730 +  }
2731 +
2732 +  for(i = 0; i != 6; ++i)
2733 +  {
2734 +    buffer = write_32(buffer, mvhd->predefined_[i]);
2735 +  }
2736 +
2737 +  buffer = write_32(buffer, mvhd->next_track_id_);
2738 +
2739 +  return buffer;
2740 +}
2741 +
2742 +static struct moov_t* moov_init()
2743 +{
2744 +  struct moov_t* moov = malloc(sizeof(struct moov_t));
2745 +  moov->unknown_atoms_ = 0;
2746 +  moov->mvhd_ = 0;
2747 +  moov->tracks_ = 0;
2748 +
2749 +  return moov;
2750 +}
2751 +
2752 +static void moov_exit(struct moov_t* atom)
2753 +{
2754 +  unsigned int i;
2755 +  if(atom->unknown_atoms_)
2756 +  {
2757 +    unknown_atom_exit(atom->unknown_atoms_);
2758 +  }
2759 +  if(atom->mvhd_)
2760 +  {
2761 +    mvhd_exit(atom->mvhd_);
2762 +  }
2763 +  for(i = 0; i != atom->tracks_; ++i)
2764 +  {
2765 +    trak_exit(atom->traks_[i]);
2766 +  }
2767 +  free(atom);
2768 +}
2769 +
2770 +static int moov_add_mvhd(void* parent, void* mvhd)
2771 +{
2772 +  struct moov_t* moov = parent;
2773 +  moov->mvhd_ = mvhd;
2774 +
2775 +  return 1;
2776 +}
2777 +
2778 +static int moov_add_trak(void* parent, void* child)
2779 +{
2780 +  struct moov_t* moov = parent;
2781 +  struct trak_t* trak = child;
2782 +  if(moov->tracks_ == MAX_TRACKS)
2783 +  {
2784 +    trak_exit(trak);
2785 +    return 0;
2786 +  }
2787 +
2788 +  if(trak->mdia_->hdlr_->handler_type_ != FOURCC('v', 'i', 'd', 'e') &&
2789 +     trak->mdia_->hdlr_->handler_type_ != FOURCC('s', 'o', 'u', 'n'))
2790 +  {
2791 +    printf("Trak ignored (handler_type=%c%c%c%c, name=%s)\n",
2792 +      trak->mdia_->hdlr_->handler_type_ >> 24,
2793 +      trak->mdia_->hdlr_->handler_type_ >> 16,
2794 +      trak->mdia_->hdlr_->handler_type_ >> 8,
2795 +      trak->mdia_->hdlr_->handler_type_,
2796 +      trak->mdia_->hdlr_->name_);
2797 +    trak_exit(trak);
2798 +    return 1; // continue
2799 +  }
2800 +  
2801 +  moov->traks_[moov->tracks_] = trak;
2802 +  ++moov->tracks_;
2803 +
2804 +  return 1;
2805 +}
2806 +
2807 +static void* moov_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
2808 +{
2809 +  struct moov_t* atom = moov_init();
2810 +
2811 +  struct atom_read_list_t atom_read_list[] = {
2812 +    { FOURCC('m', 'v', 'h', 'd'), atom, &moov_add_mvhd, &mvhd_read },
2813 +    { FOURCC('t', 'r', 'a', 'k'), atom, &moov_add_trak, &trak_read }
2814 +  };
2815 +
2816 +  int result = atom_reader(atom_read_list,
2817 +                  sizeof(atom_read_list) / sizeof(atom_read_list[0]),
2818 +                  atom,
2819 +                  buffer, size);
2820 +
2821 +  // check for mandatory atoms
2822 +  if(!atom->mvhd_)
2823 +  {
2824 +    printf("moov: missing mvhd\n");
2825 +    result = 0;
2826 +  }
2827 +
2828 +  if(!atom->tracks_)
2829 +  {
2830 +    printf("moov: missing trak\n");
2831 +    result = 0;
2832 +  }
2833 +
2834 +  if(!result)
2835 +  {
2836 +    moov_exit(atom);
2837 +    return 0;
2838 +  }
2839 +
2840 +  return atom;
2841 +}
2842 +
2843 +static void moov_write(struct moov_t* atom, unsigned char* buffer)
2844 +{
2845 +  unsigned i;
2846 +
2847 +  unsigned char* atom_start = buffer;
2848 +
2849 +  struct atom_write_list_t atom_write_list[] = {
2850 +    { FOURCC('m', 'v', 'h', 'd'), atom, atom->mvhd_, &mvhd_write },
2851 +  };
2852 +
2853 +  // atom size
2854 +  buffer += 4;
2855 +
2856 +  // atom type
2857 +  buffer = write_32(buffer, FOURCC('m', 'o', 'o', 'v'));
2858 +
2859 +  buffer = atom_writer(atom->unknown_atoms_,
2860 +                       atom_write_list,
2861 +                       sizeof(atom_write_list) / sizeof(atom_write_list[0]),
2862 +                       buffer);
2863 +
2864 +  for(i = 0; i != atom->tracks_; ++i)
2865 +  {
2866 +    struct atom_write_list_t trak_atom_write_list[] = {
2867 +      { FOURCC('t', 'r', 'a', 'k'), atom, atom->traks_[i], &trak_write },
2868 +    };
2869 +    buffer = atom_writer(0,
2870 +                         trak_atom_write_list,
2871 +                         sizeof(trak_atom_write_list) / sizeof(trak_atom_write_list[0]),
2872 +                         buffer);
2873 +  }
2874 +  write_32(atom_start, buffer - atom_start);
2875 +}
2876 +
2877 +void moov_shift_offsets(struct moov_t* moov, int64_t offset)
2878 +{
2879 +  unsigned int i;
2880 +  for(i = 0; i != moov->tracks_; ++i)
2881 +  {
2882 +    trak_shift_offsets(moov->traks_[i], offset);
2883 +  }
2884 +}
2885 +
2886 +void moov_shift_offsets_inplace(struct moov_t* moov, int64_t offset)
2887 +{
2888 +  unsigned int i;
2889 +  for(i = 0; i != moov->tracks_; ++i)
2890 +  {
2891 +    trak_shift_offsets_inplace(moov->traks_[i], offset);
2892 +  }
2893 +}
2894 +
2895 +unsigned int moov_seek(unsigned char* moov_data,
2896 +                       uint64_t* moov_size,
2897 +                       float start_time,
2898 +                       float end_time,
2899 +                       uint64_t* mdat_start,
2900 +                       uint64_t* mdat_size,
2901 +                       uint64_t offset,
2902 +                       int client_is_flash)
2903 +{
2904 +  struct moov_t* moov = moov_read(NULL, moov_data + ATOM_PREAMBLE_SIZE,
2905 +                                  *moov_size - ATOM_PREAMBLE_SIZE);
2906 +
2907 +  if(moov == 0 || moov->mvhd_ == 0)
2908 +  {
2909 +    printf("Error parsing moov header\n");
2910 +    return 0;
2911 +  }
2912 +
2913 +  {
2914 +    long moov_time_scale = moov->mvhd_->timescale_;
2915 +    unsigned int start = (unsigned int)(start_time * moov_time_scale);
2916 +    unsigned int end = (unsigned int)(end_time * moov_time_scale);
2917 +    uint64_t skip_from_start = UINT64_MAX;
2918 +    uint64_t end_offset = 0;
2919 +    unsigned int i;
2920 +    unsigned int pass;
2921 +
2922 +    // for every trak, convert seconds to sample (time-to-sample).
2923 +    // adjust sample to keyframe
2924 +    unsigned int trak_sample_start[MAX_TRACKS];
2925 +    unsigned int trak_sample_end[MAX_TRACKS];
2926 +
2927 +    uint64_t moov_duration = 0;
2928 +
2929 +    // clayton.mp4 has a third track with one sample that lasts the whole clip.
2930 +    // Assuming the first two tracks are the audio and video track, we patch
2931 +    // the remaining tracks to 'free' atoms.
2932 +//    if(moov->tracks_ > 2)
2933 +//    {
2934 +//      for(i = 2; i != moov->tracks_; ++i)
2935 +//      {
2936 +//        // patch 'trak' to 'free'
2937 +//        unsigned char* p = moov->traks_[i].start_ - 4;
2938 +//        p[0] = 'f';
2939 +//        p[1] = 'r';
2940 +//        p[2] = 'e';
2941 +//        p[3] = 'e';
2942 +//      }
2943 +//      moov->tracks_ = 2;
2944 +//    }
2945 +
2946 +    // reported by everwanna:
2947 +    // av out of sync because: 
2948 +    // audio track 0 without stss, seek to the exact time. 
2949 +    // video track 1 with stss, seek to the nearest key frame time.
2950 +    //
2951 +    // fixed:
2952 +    // first pass we get the new aligned times for traks with an stss present
2953 +    // second pass is for traks without an stss
2954 +    for(pass = 0; pass != 2; ++pass)
2955 +    {
2956 +      for(i = 0; i != moov->tracks_; ++i)
2957 +      {
2958 +        struct trak_t* trak = moov->traks_[i];
2959 +        struct stbl_t* stbl = trak->mdia_->minf_->stbl_;
2960 +        long trak_time_scale = trak->mdia_->mdhd_->timescale_;
2961 +        float moov_to_trak_time = (float)trak_time_scale / (float)moov_time_scale;
2962 +        float trak_to_moov_time = (float)moov_time_scale / (float)trak_time_scale;
2963 +
2964 +        // 1st pass: stss present, 2nd pass: no stss present
2965 +        if(pass == 0 && !stbl->stss_)
2966 +          continue;
2967 +        if(pass == 1 && stbl->stss_)
2968 +          continue;
2969 +
2970 +        // ignore empty track
2971 +        if(trak->mdia_->mdhd_->duration_ == 0)
2972 +          continue;
2973 +
2974 +        // get start
2975 +        if(start == 0)
2976 +        {
2977 +          trak_sample_start[i] = start;
2978 +        }
2979 +        else
2980 +        {
2981 +          start = stts_get_sample(stbl->stts_, (uint64_t)(start * moov_to_trak_time));
2982 +          printf("start=%u (trac time)=%.2f (seconds)", start,
2983 +            stts_get_time(stbl->stts_, start) / (float)trak_time_scale);
2984 +          start = stbl_get_nearest_keyframe(stbl, start + 1) - 1;
2985 +          printf("=%u (zero based keyframe)", start);
2986 +          trak_sample_start[i] = start;
2987 +          start = (unsigned int)(stts_get_time(stbl->stts_, start) * trak_to_moov_time);
2988 +          printf("=%u (moov time)\n", start);
2989 +        }
2990 +
2991 +        // get end
2992 +        if(end == 0)
2993 +        {
2994 +          trak_sample_end[i] = trak->samples_size_;
2995 +        }
2996 +        else
2997 +        {
2998 +          end = stts_get_sample(stbl->stts_, (uint64_t)(end * moov_to_trak_time));
2999 +          if(end >= trak->samples_size_)
3000 +          {
3001 +            end = trak->samples_size_;
3002 +          }
3003 +          else
3004 +          {
3005 +            end = stbl_get_nearest_keyframe(stbl, end + 1) - 1;
3006 +          }
3007 +          trak_sample_end[i] = end;
3008 +          printf("endframe=%u, samples_size_=%u\n", end, trak->samples_size_);
3009 +          end = (unsigned int)(stts_get_time(stbl->stts_, end) * trak_to_moov_time);
3010 +        }
3011 +      }
3012 +    }
3013 +
3014 +    printf("start=%u\n", start);
3015 +    printf("end=%u\n", end);
3016 +
3017 +    if(end && start >= end)
3018 +    {
3019 +      moov_exit(moov);
3020 +      return 0;
3021 +    }
3022 +
3023 +    for(i = 0; i != moov->tracks_; ++i)
3024 +    {
3025 +      struct trak_t* trak = moov->traks_[i];
3026 +      struct stbl_t* stbl = trak->mdia_->minf_->stbl_;
3027 +
3028 +      unsigned int start_sample = trak_sample_start[i];
3029 +      unsigned int end_sample = trak_sample_end[i];
3030 +
3031 +      // ignore empty track
3032 +      if(trak->mdia_->mdhd_->duration_ == 0)
3033 +        continue;
3034 +
3035 +      trak_update_index(trak, start_sample, end_sample);
3036 +
3037 +      {
3038 +        uint64_t skip =
3039 +          trak->samples_[start_sample].pos_ - trak->samples_[0].pos_;
3040 +        if(skip < skip_from_start)
3041 +          skip_from_start = skip;
3042 +        printf("Trak can skip %llu bytes\n", skip);
3043 +
3044 +        if(end_sample != trak->samples_size_)
3045 +        {
3046 +          uint64_t end_pos = trak->samples_[end_sample].pos_;
3047 +          if(end_pos > end_offset)
3048 +            end_offset = end_pos;
3049 +          printf("New endpos=%llu\n", end_pos);
3050 +          printf("Trak can skip %llu bytes at end\n",
3051 +                 *mdat_start + *mdat_size - end_offset);
3052 +        }
3053 +      }
3054 +
3055 +      {
3056 +        // fixup trak (duration)
3057 +        uint64_t trak_duration = stts_get_duration(stbl->stts_);
3058 +        long trak_time_scale = trak->mdia_->mdhd_->timescale_;
3059 +        float trak_to_moov_time = (float)moov_time_scale / (float)trak_time_scale;
3060 +        {
3061 +        uint64_t duration = (long)((float)trak_duration * trak_to_moov_time);
3062 +        trak->mdia_->mdhd_->duration_= trak_duration;
3063 +        trak->tkhd_->duration_ = duration;
3064 +        printf("trak: new_duration=%lld\n", duration);
3065 +
3066 +        if(duration > moov_duration)
3067 +          moov_duration = duration;
3068 +        }
3069 +      }
3070 +
3071 +//      printf("stco.size=%d, ", read_int32(stbl->stco_ + 4));
3072 +//      printf("stts.size=%d samples=%d\n", read_int32(stbl->stts_ + 4), stts_get_samples(stbl->stts_));
3073 +//      printf("stsz.size=%d\n", read_int32(stbl->stsz_ + 8));
3074 +//      printf("stsc.samples=%d\n", stsc_get_samples(stbl->stsc_));
3075 +    }
3076 +    moov->mvhd_->duration_ = moov_duration;
3077 +
3078 +    // subtract bytes we skip at the front of the mdat atom
3079 +    offset -= skip_from_start;
3080 +
3081 +    // subtract old moov size
3082 +    offset -= *moov_size;
3083 +
3084 +    printf("moov: writing header\n");
3085 +
3086 +    moov_write(moov, moov_data);
3087 +    *moov_size = read_32(moov_data);
3088 +
3089 +    // add new moov size
3090 +    offset += *moov_size;
3091 +
3092 +    printf("shifting offsets by %lld\n", offset);
3093 +    moov_shift_offsets_inplace(moov, offset);
3094 +
3095 +//    moov_write(moov, moov_data);
3096 +
3097 +#ifdef COMPRESS_MOOV_ATOM
3098 +    if(!client_is_flash)
3099 +    {
3100 +      uLong sourceLen = *moov_size - ATOM_PREAMBLE_SIZE;
3101 +      uLong destLen = compressBound(sourceLen);
3102 +      unsigned char* cmov = malloc(destLen);
3103 +      int zstatus = compress(cmov, &destLen, moov_data, sourceLen);
3104 +      if(zstatus == Z_OK)
3105 +      {
3106 +        printf("cmov size = %lu (%ld%%)\n", destLen, 100 * destLen / sourceLen);
3107 +      }
3108 +
3109 +      {
3110 +        const int extra_space = 4096;
3111 +        if(destLen + extra_space < sourceLen)
3112 +        {
3113 +          const int bytes_saved = sourceLen - destLen;
3114 +          uLong destLen2;
3115 +          int extra = 0;
3116 +          printf("shifting offsets by %d\n", -bytes_saved);
3117 +          moov_shift_offsets_inplace(moov, -bytes_saved);
3118 +
3119 +          extra += ATOM_PREAMBLE_SIZE + 4;            // dcom
3120 +          extra += ATOM_PREAMBLE_SIZE + 4;            // cmvd
3121 +          extra += ATOM_PREAMBLE_SIZE;                // cmov
3122 +          extra += ATOM_PREAMBLE_SIZE + extra_space;  // free
3123 +
3124 +          printf("shifting offsets by %d\n", extra);
3125 +          moov_shift_offsets_inplace(moov, extra);
3126 +
3127 +          // recompress
3128 +          destLen2 = compressBound(sourceLen);
3129 +          zstatus = compress(cmov, &destLen2, moov_data, sourceLen);
3130 +          if(zstatus == Z_OK)
3131 +          {
3132 +            printf("cmov size = %lu (%ld%%)\n", destLen2, 100 * destLen2 / sourceLen);
3133 +
3134 +            if(destLen2 < destLen + extra_space)
3135 +            {
3136 +              // copy compressed movie atom
3137 +              unsigned char* outbuffer = moov_data;
3138 +
3139 +              uint32_t dcom_size = ATOM_PREAMBLE_SIZE + 4;
3140 +              uint32_t cmvd_size = ATOM_PREAMBLE_SIZE + 4 + destLen2;
3141 +              uint32_t cmov_size = ATOM_PREAMBLE_SIZE + dcom_size + cmvd_size;
3142 +              uint32_t free_size = ATOM_PREAMBLE_SIZE + extra_space + destLen - destLen2;
3143 +              *moov_size = ATOM_PREAMBLE_SIZE + cmov_size + free_size;
3144 +
3145 +              outbuffer = write_32(outbuffer, (uint32_t)*moov_size);
3146 +
3147 +              // skip 'moov'
3148 +              outbuffer += 4;
3149 +
3150 +              outbuffer = write_32(outbuffer, cmov_size);
3151 +              {
3152 +                outbuffer = write_32(outbuffer, FOURCC('c', 'm', 'o', 'v'));
3153 +                outbuffer = write_32(outbuffer, dcom_size);
3154 +                outbuffer = write_32(outbuffer, FOURCC('d', 'c', 'o', 'm'));
3155 +                outbuffer = write_32(outbuffer, FOURCC('z', 'l', 'i', 'b'));
3156 +
3157 +                outbuffer = write_32(outbuffer, cmvd_size);
3158 +                {
3159 +                  outbuffer = write_32(outbuffer, FOURCC('c', 'm', 'v', 'd'));
3160 +                  outbuffer = write_32(outbuffer, sourceLen);
3161 +                  memcpy(outbuffer, cmov, destLen2);
3162 +                  outbuffer += destLen2;
3163 +                }
3164 +              }
3165 +
3166 +              // add final padding
3167 +              outbuffer = write_32(outbuffer, free_size);
3168 +              outbuffer = write_32(outbuffer, FOURCC('f', 'r', 'e', 'e'));
3169 +              {
3170 +                const char free_bytes[8] =
3171 +                {
3172 +                  'C', 'o', 'd', 'e','S','h', 'o', 'p'
3173 +                };
3174 +                uint32_t padding_index;
3175 +                for(padding_index = ATOM_PREAMBLE_SIZE; padding_index != free_size; ++padding_index)
3176 +                {
3177 +                  outbuffer[padding_index] = free_bytes[padding_index % 8];
3178 +                }
3179 +              }
3180 +            }
3181 +            else
3182 +            {
3183 +              printf("2nd pass compress overflow\n");
3184 +            }
3185 +          }
3186 +        }
3187 +      }
3188 +      free(cmov);
3189 +    }
3190 +#endif
3191 +
3192 +    *mdat_start += skip_from_start;
3193 +    if(end_offset != 0)
3194 +    {
3195 +      *mdat_size = end_offset;
3196 +    }
3197 +    *mdat_size -= skip_from_start;
3198 +  }
3199 +
3200 +  moov_exit(moov);
3201 +
3202 +  return 1;
3203 +}
3204 +
3205 +////////////////////////////////////////////////////////////////////////////////
3206 +
3207 +struct mp4_atom_t
3208 +{
3209 +  uint32_t type_;
3210 +  uint32_t short_size_;
3211 +  uint64_t size_;
3212 +  uint64_t start_;
3213 +  uint64_t end_;
3214 +};
3215 +
3216 +static int mp4_atom_read_header(FILE* infile, struct mp4_atom_t* atom)
3217 +{
3218 +  unsigned char atom_header[8];
3219 +
3220 +  atom->start_ = ftell(infile);
3221 +  fread(atom_header, 8, 1, infile);
3222 +  atom->short_size_ = read_32(&atom_header[0]);
3223 +  atom->type_ = read_32(&atom_header[4]);
3224 +
3225 +  if(atom->short_size_ == 1)
3226 +  {
3227 +    fread(atom_header, 8, 1, infile);
3228 +    atom->size_ = read_64(&atom_header[0]);
3229 +  }
3230 +  else
3231 +  {
3232 +    atom->size_ = atom->short_size_;
3233 +  }
3234 +
3235 +  atom->end_ = atom->start_ + atom->size_;
3236 +
3237 +  return 1;
3238 +}
3239 +
3240 +static int mp4_atom_write_header(unsigned char* outbuffer, struct mp4_atom_t* atom)
3241 +{
3242 +  int write_box64 = atom->short_size_ == 1 ? 1 : 0;
3243 +
3244 +  if(write_box64)
3245 +    write_32(outbuffer, 1);
3246 +  else
3247 +    write_32(outbuffer, (uint32_t)atom->size_);
3248 +
3249 +  write_32(outbuffer + 4, atom->type_);
3250 +
3251 +  if(write_box64)
3252 +  {
3253 +    write_64(outbuffer + 8, atom->size_);
3254 +    return 16;
3255 +  }
3256 +  else
3257 +  {
3258 +    return 8;
3259 +  }
3260 +}
3261 +
3262 +int mp4_split(const char* filename, int64_t filesize,
3263 +              float start_time, float end_time,
3264 +              void** mp4_header, uint32_t* mp4_header_size,
3265 +              uint64_t* mdat_offset, uint64_t* mdat_size,
3266 +              int client_is_flash)
3267 +{
3268 +  FILE* infile;
3269 +  struct mp4_atom_t ftyp_atom;
3270 +  struct mp4_atom_t moov_atom;
3271 +  struct mp4_atom_t mdat_atom;
3272 +  unsigned char* moov_data = 0;
3273 +  unsigned char* buffer;
3274 +  uint64_t new_mdat_start;
3275 +
3276 +  *mp4_header = 0;
3277 +  memset(&ftyp_atom, 0, sizeof(ftyp_atom));
3278 +  memset(&moov_atom, 0, sizeof(moov_atom));
3279 +  memset(&mdat_atom, 0, sizeof(mdat_atom));
3280 +
3281 +  infile = fopen(filename, "rb");
3282 +  if(infile == NULL)
3283 +  {
3284 +    return 0;
3285 +  }
3286 +
3287 +  while(ftello(infile) < filesize)
3288 +  {
3289 +    struct mp4_atom_t leaf_atom;
3290 +
3291 +    if(!mp4_atom_read_header(infile, &leaf_atom))
3292 +      break;
3293 +
3294 +    printf("Atom(%c%c%c%c,%lld)\n",
3295 +           leaf_atom.type_ >> 24, leaf_atom.type_ >> 16,
3296 +           leaf_atom.type_ >> 8, leaf_atom.type_,
3297 +           leaf_atom.size_);
3298 +
3299 +    switch(leaf_atom.type_)
3300 +    {
3301 +    case FOURCC('f', 't', 'y', 'p'):
3302 +      ftyp_atom = leaf_atom;
3303 +      break;
3304 +    case FOURCC('m', 'o', 'o', 'v'):
3305 +      moov_atom = leaf_atom;
3306 +      moov_data = (unsigned char*)malloc((size_t)moov_atom.size_);
3307 +      fseeko(infile, moov_atom.start_, SEEK_SET);
3308 +      fread(moov_data, (off_t)moov_atom.size_, 1, infile);
3309 +      break;
3310 +    case FOURCC('m', 'd', 'a', 't'):
3311 +      mdat_atom = leaf_atom;
3312 +      break;
3313 +    }
3314 +    fseeko(infile, leaf_atom.end_, SEEK_SET);
3315 +  }
3316 +
3317 +  if(moov_atom.size_ == 0)
3318 +  {
3319 +    printf("Error: moov atom not found\n");
3320 +    fclose(infile);
3321 +    return 0;
3322 +  }
3323 +
3324 +  if(mdat_atom.size_ == 0)
3325 +  {
3326 +    printf("Error: mdat atom not found\n");
3327 +    fclose(infile);
3328 +    return 0;
3329 +  }
3330 +
3331 +  buffer = (unsigned char*)malloc((uint32_t)moov_atom.size_ + 4 * 1024);
3332 +  *mp4_header = buffer;
3333 +
3334 +  if(ftyp_atom.size_)
3335 +  {
3336 +    fseeko(infile, ftyp_atom.start_, SEEK_SET);
3337 +    fread(buffer, (off_t)ftyp_atom.size_, 1, infile);
3338 +    buffer += ftyp_atom.size_;
3339 +  }
3340 +
3341 +  {
3342 +    static char const free_data[] = {
3343 +      0x0, 0x0, 0x0,  42, 'f', 'r', 'e', 'e',
3344 +      'v', 'i', 'd', 'e', 'o', ' ', 's', 'e',
3345 +      'r', 'v', 'e', 'd', ' ', 'b', 'y', ' ',
3346 +      'm', 'o', 'd', '_', 'h', '2', '6', '4',
3347 +      '_', 's', 't', 'r', 'e', 'a', 'm', 'i',
3348 +      'n', 'g'
3349 +    };
3350 +    memcpy(buffer, free_data, sizeof(free_data));
3351 +    buffer += sizeof(free_data);
3352 +  }
3353 +
3354 +  new_mdat_start = buffer - (unsigned char*)(*mp4_header) + moov_atom.size_;
3355 +  if(!moov_seek(moov_data,
3356 +                &moov_atom.size_,
3357 +                start_time,
3358 +                end_time,
3359 +                &mdat_atom.start_,
3360 +                &mdat_atom.size_,
3361 +                new_mdat_start - mdat_atom.start_,
3362 +                client_is_flash))
3363 +  {
3364 +    free(moov_data);
3365 +    fclose(infile);
3366 +    return 0;
3367 +  }
3368 +
3369 +  memcpy(buffer, moov_data, (uint32_t)moov_atom.size_);
3370 +  buffer += moov_atom.size_;
3371 +  free(moov_data);
3372 +
3373 +  {
3374 +    int mdat_header_size = mp4_atom_write_header(buffer, &mdat_atom);
3375 +    buffer += mdat_header_size;
3376 +    *mdat_offset = mdat_atom.start_ + mdat_header_size;
3377 +    *mdat_size = mdat_atom.size_ - mdat_header_size;
3378 +  }
3379 +
3380 +  *mp4_header_size = (uint32_t)(buffer - (unsigned char*)(*mp4_header));
3381 +
3382 +  fclose(infile);
3383 +
3384 +  return 1;
3385 +}
3386 +
3387 +// End Of File
3388 +
3389 --- /dev/null   2008-11-04 20:33:38.146691408 +0200
3390 +++ lighttpd-1.4.18/src/moov.h  2009-01-26 21:00:05.071936866 +0200
3391 @@ -0,0 +1,49 @@
3392 +/*******************************************************************************
3393 + moov.h (version 2)
3394 +
3395 + moov - A library for splitting Quicktime/MPEG4 files.
3396 + http://h264.code-shop.com
3397 +
3398 + Copyright (C) 2007-2009 CodeShop B.V.
3399 +
3400 + Licensing
3401 + The H264 Streaming Module is licened under a Creative Common License. It allows
3402 + you to use, modify and redistribute the module, but only for *noncommercial*
3403 + purposes. For corporate use, please apply for a commercial license.
3404 +
3405 + Creative Commons License:
3406 + http://creativecommons.org/licenses/by-nc-sa/3.0/
3407 +
3408 + Commercial License:
3409 + http://h264.code-shop.com/trac/wiki/Mod-H264-Streaming-License-Version2
3410 +******************************************************************************/ 
3411 +
3412 +// NOTE: don't include stdio.h (for FILE) or sys/types.h (for off_t).
3413 +// nginx redefines _FILE_OFFSET_BITS and off_t will have different sizes
3414 +// depending on include order
3415 +
3416 +#ifndef _MSC_VER
3417 +#include <inttypes.h>
3418 +#else
3419 +#include "inttypes.h"
3420 +#endif
3421 +
3422 +#ifdef __cplusplus
3423 +extern "C" {
3424 +#endif
3425 +
3426 +extern int mp4_split(const char* infile, int64_t filesize,
3427 +                     float start_time, float end_time,
3428 +                     void** mp4_header, uint32_t* mp4_header_size,
3429 +                     uint64_t* mdat_offset, uint64_t* mdat_size,
3430 +                     int client_is_flash);
3431 +
3432 +/* Returns true when the test string is a prefix of the input */
3433 +extern int starts_with(const char* input, const char* test);
3434 +
3435 +#ifdef __cplusplus
3436 +} /* extern C definitions */
3437 +#endif
3438 +
3439 +// End Of File
3440 +
This page took 0.570972 seconds and 3 git commands to generate.