]> git.pld-linux.org Git - packages/lighttpd.git/blame - lighttpd-mod_h264_streaming.patch
up to 1.4.38
[packages/lighttpd.git] / lighttpd-mod_h264_streaming.patch
CommitLineData
cdbbc5bb
ER
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
7f6c2427
ER
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 @@
cdbbc5bb
ER
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+
7f6c2427 24+ Copyright (C) 2007-2009 CodeShop B.V.
cdbbc5bb
ER
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+
7f6c2427
ER
45+#include "moov.h"
46+
cdbbc5bb
ER
47+/* plugin config for all request/connections */
48+
49+typedef struct {
7f6c2427 50+ array *extensions;
cdbbc5bb
ER
51+} plugin_config;
52+
53+typedef struct {
7f6c2427 54+ PLUGIN_DATA;
cdbbc5bb 55+
7f6c2427
ER
56+ buffer *query_str;
57+ array *get_params;
cdbbc5bb 58+
7f6c2427 59+ plugin_config **config_storage;
cdbbc5bb 60+
7f6c2427 61+ plugin_config conf;
cdbbc5bb
ER
62+} plugin_data;
63+
64+/* init the plugin data */
65+INIT_FUNC(mod_h264_streaming_init) {
7f6c2427 66+ plugin_data *p;
cdbbc5bb 67+
7f6c2427 68+ p = calloc(1, sizeof(*p));
cdbbc5bb 69+
7f6c2427
ER
70+ p->query_str = buffer_init();
71+ p->get_params = array_init();
cdbbc5bb 72+
7f6c2427 73+ return p;
cdbbc5bb
ER
74+}
75+
76+/* detroy the plugin data */
77+FREE_FUNC(mod_h264_streaming_free) {
7f6c2427 78+ plugin_data *p = p_d;
cdbbc5bb 79+
7f6c2427 80+ UNUSED(srv);
cdbbc5bb 81+
7f6c2427 82+ if (!p) return HANDLER_GO_ON;
cdbbc5bb 83+
7f6c2427
ER
84+ if (p->config_storage) {
85+ size_t i;
cdbbc5bb 86+
7f6c2427
ER
87+ for (i = 0; i < srv->config_context->used; i++) {
88+ plugin_config *s = p->config_storage[i];
cdbbc5bb 89+
7f6c2427 90+ if (!s) continue;
cdbbc5bb 91+
7f6c2427 92+ array_free(s->extensions);
cdbbc5bb 93+
7f6c2427
ER
94+ free(s);
95+ }
96+ free(p->config_storage);
97+ }
cdbbc5bb 98+
7f6c2427
ER
99+ buffer_free(p->query_str);
100+ array_free(p->get_params);
cdbbc5bb 101+
7f6c2427 102+ free(p);
cdbbc5bb 103+
7f6c2427 104+ return HANDLER_GO_ON;
cdbbc5bb
ER
105+}
106+
107+/* handle plugin config and check values */
108+
109+SETDEFAULTS_FUNC(mod_h264_streaming_set_defaults) {
7f6c2427
ER
110+ plugin_data *p = p_d;
111+ size_t i = 0;
cdbbc5bb 112+
7f6c2427
ER
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+ };
cdbbc5bb 117+
7f6c2427 118+ if (!p) return HANDLER_ERROR;
cdbbc5bb 119+
7f6c2427 120+ p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
cdbbc5bb 121+
7f6c2427
ER
122+ for (i = 0; i < srv->config_context->used; i++) {
123+ plugin_config *s;
cdbbc5bb 124+
7f6c2427
ER
125+ s = calloc(1, sizeof(plugin_config));
126+ s->extensions = array_init();
cdbbc5bb 127+
7f6c2427 128+ cv[0].destination = s->extensions;
cdbbc5bb 129+
7f6c2427 130+ p->config_storage[i] = s;
cdbbc5bb 131+
7f6c2427
ER
132+ if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
133+ return HANDLER_ERROR;
134+ }
135+ }
cdbbc5bb 136+
7f6c2427 137+ return HANDLER_GO_ON;
cdbbc5bb
ER
138+}
139+
140+#define PATCH(x) \
7f6c2427 141+ p->conf.x = s->x;
cdbbc5bb 142+static int mod_h264_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
7f6c2427
ER
143+ size_t i, j;
144+ plugin_config *s = p->config_storage[0];
cdbbc5bb 145+
7f6c2427 146+ PATCH(extensions);
cdbbc5bb 147+
7f6c2427
ER
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];
cdbbc5bb 152+
7f6c2427
ER
153+ /* condition didn't match */
154+ if (!config_check_cond(srv, con, dc)) continue;
cdbbc5bb 155+
7f6c2427
ER
156+ /* merge config */
157+ for (j = 0; j < dc->value->used; j++) {
158+ data_unset *du = dc->value->data[j];
cdbbc5bb 159+
7f6c2427
ER
160+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("h264-streaming.extensions"))) {
161+ PATCH(extensions);
162+ }
163+ }
164+ }
cdbbc5bb 165+
7f6c2427 166+ return 0;
cdbbc5bb
ER
167+}
168+#undef PATCH
169+
170+static int split_get_params(array *get_params, buffer *qrystr) {
7f6c2427
ER
171+ size_t is_key = 1;
172+ size_t i;
173+ char *key = NULL, *val = NULL;
cdbbc5bb 174+
7f6c2427 175+ key = qrystr->ptr;
cdbbc5bb 176+
7f6c2427
ER
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;
cdbbc5bb 183+
7f6c2427 184+ qrystr->ptr[i] = '\0';
cdbbc5bb 185+
7f6c2427
ER
186+ is_key = 0;
187+ }
cdbbc5bb 188+
7f6c2427
ER
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 & */
cdbbc5bb 195+
7f6c2427
ER
196+ /* terminate the value */
197+ qrystr->ptr[i] = '\0';
cdbbc5bb 198+
7f6c2427
ER
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));
cdbbc5bb 204+
7f6c2427
ER
205+ array_insert_unique(get_params, (data_unset *)ds);
206+ }
cdbbc5bb 207+
7f6c2427
ER
208+ key = qrystr->ptr + i + 1;
209+ val = NULL;
210+ is_key = 1;
211+ break;
212+ }
213+ }
cdbbc5bb 214+
7f6c2427 215+ return 0;
cdbbc5bb
ER
216+}
217+
7f6c2427
ER
218+URIHANDLER_FUNC(mod_h264_streaming_path_handler) {
219+ plugin_data *p = p_d;
220+ int s_len;
221+ size_t k;
cdbbc5bb 222+
7f6c2427 223+ UNUSED(srv);
cdbbc5bb 224+
7f6c2427 225+ if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
cdbbc5bb 226+
7f6c2427 227+ mod_h264_streaming_patch_connection(srv, con, p);
cdbbc5bb 228+
7f6c2427 229+ s_len = con->physical.path->used - 1;
cdbbc5bb 230+
7f6c2427
ER
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;
cdbbc5bb 234+
7f6c2427
ER
235+ if (ct_len > s_len) continue;
236+ if (ds->value->used == 0) continue;
cdbbc5bb 237+
7f6c2427
ER
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;
cdbbc5bb 245+
7f6c2427
ER
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);
cdbbc5bb 249+
7f6c2427
ER
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+ }
cdbbc5bb 272+
7f6c2427
ER
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+ }
cdbbc5bb 277+
7f6c2427
ER
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+ }
cdbbc5bb 282+
7f6c2427
ER
283+ /* we are safe now, let's build a h264 header */
284+ {
285+ {
286+ unsigned int filesize = sce->st.st_size;
cdbbc5bb 287+
7f6c2427
ER
288+ void* mp4_header;
289+ uint32_t mp4_header_size;
290+ uint64_t mdat_offset;
291+ uint64_t mdat_size;
cdbbc5bb 292+
7f6c2427
ER
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);
cdbbc5bb 296+
7f6c2427
ER
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 */
cdbbc5bb 302+
7f6c2427
ER
303+ http_chunk_append_file(srv, con, con->physical.path,
304+ mdat_offset, mdat_size);
305+ }
cdbbc5bb 306+
7f6c2427
ER
307+ if(mp4_header)
308+ {
309+ free(mp4_header);
310+ }
cdbbc5bb 311+
7f6c2427
ER
312+ if(!result)
313+ {
314+ return HANDLER_GO_ON;
315+ }
316+ }
317+ }
cdbbc5bb 318+
7f6c2427
ER
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+ }
cdbbc5bb 328+
7f6c2427 329+ con->file_finished = 1;
cdbbc5bb 330+
7f6c2427
ER
331+ return HANDLER_FINISHED;
332+ }
333+ }
cdbbc5bb 334+
7f6c2427
ER
335+ /* not found */
336+ return HANDLER_GO_ON;
cdbbc5bb
ER
337+}
338+
339+/* this function is called at dlopen() time and inits the callbacks */
340+
341+int mod_h264_streaming_plugin_init(plugin *p) {
7f6c2427
ER
342+ p->version = LIGHTTPD_VERSION_ID;
343+ p->name = buffer_init_string("h264_streaming");
cdbbc5bb 344+
7f6c2427
ER
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;
cdbbc5bb 349+
7f6c2427 350+ p->data = NULL;
cdbbc5bb 351+
7f6c2427 352+ return 0;
cdbbc5bb
ER
353+}
354+
7f6c2427
ER
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)
cdbbc5bb
ER
360+
361+ moov - A library for splitting Quicktime/MPEG4 files.
362+ http://h264.code-shop.com
363+
7f6c2427 364+ Copyright (C) 2007-2009 CodeShop B.V.
cdbbc5bb 365+
7f6c2427
ER
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.
cdbbc5bb 370+
7f6c2427
ER
371+ Creative Commons License:
372+ http://creativecommons.org/licenses/by-nc-sa/3.0/
cdbbc5bb 373+
7f6c2427
ER
374+ Commercial License:
375+ http://h264.code-shop.com/trac/wiki/Mod-H264-Streaming-License-Version2
cdbbc5bb
ER
376+******************************************************************************/
377+
7f6c2427 378+#include "moov.h"
cdbbc5bb 379+
7f6c2427
ER
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+/*
cdbbc5bb
ER
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>
7f6c2427 404+#include <stdint.h>
cdbbc5bb 405+
7f6c2427
ER
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
cdbbc5bb 426+
7f6c2427
ER
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)
cdbbc5bb 436+{
7f6c2427
ER
437+ while(*input && *test)
438+ {
439+ if(*input != *test)
440+ return 0;
441+ ++input;
442+ ++test;
443+ }
444+
445+ return *test == '\0';
cdbbc5bb
ER
446+}
447+
7f6c2427 448+static unsigned int read_8(unsigned char const* buffer)
cdbbc5bb 449+{
7f6c2427 450+ return buffer[0];
cdbbc5bb
ER
451+}
452+
7f6c2427 453+static unsigned char* write_8(unsigned char* buffer, unsigned char v)
cdbbc5bb 454+{
7f6c2427 455+ buffer[0] = v;
cdbbc5bb 456+
7f6c2427
ER
457+ return buffer + 1;
458+}
cdbbc5bb 459+
7f6c2427 460+static uint16_t read_16(unsigned char const* buffer)
cdbbc5bb 461+{
7f6c2427
ER
462+ return (buffer[0] << 8) |
463+ (buffer[1] << 0);
cdbbc5bb
ER
464+}
465+
7f6c2427 466+static unsigned char* write_16(unsigned char* buffer, unsigned int v)
cdbbc5bb 467+{
7f6c2427
ER
468+ buffer[0] = (unsigned char)(v >> 8);
469+ buffer[1] = (unsigned char)(v >> 0);
cdbbc5bb 470+
7f6c2427 471+ return buffer + 2;
cdbbc5bb
ER
472+}
473+
7f6c2427 474+static unsigned int read_24(unsigned char const* buffer)
cdbbc5bb 475+{
7f6c2427
ER
476+ return (buffer[0] << 16) |
477+ (buffer[1] << 8) |
478+ (buffer[2] << 0);
cdbbc5bb
ER
479+}
480+
7f6c2427 481+static unsigned char* write_24(unsigned char* buffer, unsigned int v)
cdbbc5bb 482+{
7f6c2427
ER
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;
cdbbc5bb
ER
488+}
489+
7f6c2427 490+static uint32_t read_32(unsigned char const* buffer)
cdbbc5bb 491+{
7f6c2427
ER
492+ return (buffer[0] << 24) |
493+ (buffer[1] << 16) |
494+ (buffer[2] << 8) |
495+ (buffer[3] << 0);
cdbbc5bb
ER
496+}
497+
7f6c2427
ER
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+}
cdbbc5bb 507+
7f6c2427 508+static uint64_t read_64(unsigned char const* buffer)
cdbbc5bb 509+{
7f6c2427 510+ return ((uint64_t)(read_32(buffer)) << 32) + read_32(buffer + 4);
cdbbc5bb
ER
511+}
512+
7f6c2427 513+static unsigned char* write_64(unsigned char* buffer, uint64_t v)
cdbbc5bb 514+{
7f6c2427
ER
515+ write_32(buffer + 0, (uint32_t)(v >> 32));
516+ write_32(buffer + 4, (uint32_t)(v >> 0));
517+
518+ return buffer + 8;
cdbbc5bb
ER
519+}
520+
7f6c2427
ER
521+#define ATOM_PREAMBLE_SIZE 8
522+
523+struct atom_t
cdbbc5bb 524+{
7f6c2427
ER
525+ uint32_t type_;
526+ uint32_t short_size_;
527+ uint64_t size_;
528+ unsigned char* start_;
529+ unsigned char* end_;
cdbbc5bb
ER
530+};
531+
7f6c2427 532+static unsigned char* atom_read_header(unsigned char* buffer, struct atom_t* atom)
cdbbc5bb 533+{
7f6c2427
ER
534+ atom->start_ = buffer;
535+ atom->short_size_ = read_32(buffer);
536+ atom->type_ = read_32(buffer + 4);
cdbbc5bb 537+
7f6c2427
ER
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);
cdbbc5bb
ER
546+}
547+
7f6c2427 548+static void atom_print(struct atom_t const* atom)
cdbbc5bb 549+{
7f6c2427
ER
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_);
cdbbc5bb
ER
556+}
557+
7f6c2427 558+struct unknown_atom_t
cdbbc5bb 559+{
7f6c2427
ER
560+ void* atom_;
561+ struct unknown_atom_t* next_;
cdbbc5bb
ER
562+};
563+
7f6c2427 564+static struct unknown_atom_t* unknown_atom_init()
cdbbc5bb 565+{
7f6c2427
ER
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+}
cdbbc5bb 572+
7f6c2427 573+static void unknown_atom_exit(struct unknown_atom_t* atom)
cdbbc5bb 574+{
7f6c2427
ER
575+ while(atom)
576+ {
577+ struct unknown_atom_t* next = atom->next_;
578+ free(atom->atom_);
579+ free(atom);
580+ atom = next;
581+ }
cdbbc5bb
ER
582+}
583+
7f6c2427 584+static struct unknown_atom_t* unknown_atom_add_atom(struct unknown_atom_t* parent, void* atom)
cdbbc5bb 585+{
7f6c2427
ER
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;
cdbbc5bb
ER
592+}
593+
7f6c2427 594+struct atom_read_list_t
cdbbc5bb 595+{
7f6c2427
ER
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+};
cdbbc5bb 601+
7f6c2427
ER
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;
cdbbc5bb 609+
7f6c2427
ER
610+ while(buffer < buffer_start + size)
611+ {
612+ unsigned int i;
613+ buffer = atom_read_header(buffer, &leaf_atom);
cdbbc5bb 614+
7f6c2427 615+ atom_print(&leaf_atom);
cdbbc5bb 616+
7f6c2427
ER
617+ for(i = 0; i != atom_read_list_size; ++i)
618+ {
619+ if(leaf_atom.type_ == atom_read_list[i].type_)
cdbbc5bb 620+ {
7f6c2427 621+ break;
cdbbc5bb 622+ }
7f6c2427 623+ }
cdbbc5bb 624+
7f6c2427 625+ if(i == atom_read_list_size)
cdbbc5bb 626+ {
7f6c2427
ER
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);
cdbbc5bb
ER
630+ }
631+ else
7f6c2427
ER
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_;
cdbbc5bb 642+ }
cdbbc5bb 643+
7f6c2427 644+ if(buffer < buffer_start + size)
cdbbc5bb 645+ {
7f6c2427 646+ return 0;
cdbbc5bb 647+ }
cdbbc5bb 648+
7f6c2427 649+ return 1;
cdbbc5bb
ER
650+}
651+
7f6c2427 652+struct atom_write_list_t
cdbbc5bb 653+{
7f6c2427
ER
654+ uint32_t type_;
655+ void* parent_;
656+ void* source_;
657+ unsigned char* (*writer_)(void* parent, void* atom, unsigned char* buffer);
658+};
cdbbc5bb 659+
7f6c2427
ER
660+static unsigned char* atom_writer_unknown(struct unknown_atom_t* atoms,
661+ unsigned char* buffer)
cdbbc5bb 662+{
7f6c2427 663+ while(atoms)
cdbbc5bb 664+ {
7f6c2427
ER
665+ size_t size = read_32(atoms->atom_);
666+ memcpy(buffer, atoms->atom_, size);
667+ buffer += size;
668+ atoms = atoms->next_;
cdbbc5bb
ER
669+ }
670+
7f6c2427 671+ return buffer;
cdbbc5bb
ER
672+}
673+
7f6c2427
ER
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)
cdbbc5bb 678+{
7f6c2427
ER
679+ unsigned i;
680+ const int write_box64 = 0;
681+
682+ if(unknown_atoms)
cdbbc5bb 683+ {
7f6c2427 684+ buffer = atom_writer_unknown(unknown_atoms, buffer);
cdbbc5bb
ER
685+ }
686+
7f6c2427 687+ for(i = 0; i != atom_write_list_size; ++i)
cdbbc5bb 688+ {
7f6c2427 689+ if(atom_write_list[i].source_ != 0)
cdbbc5bb 690+ {
7f6c2427
ER
691+ unsigned char* atom_start = buffer;
692+ // atom size
693+ if(write_box64)
694+ {
695+ write_32(buffer, 1); // box64
696+ }
697+ buffer += 4;
cdbbc5bb 698+
7f6c2427
ER
699+ // atom type
700+ buffer = write_32(buffer, atom_write_list[i].type_);
701+ if(write_box64)
702+ {
703+ buffer += 8; // box64
704+ }
cdbbc5bb 705+
7f6c2427
ER
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);
cdbbc5bb
ER
714+ }
715+ }
cdbbc5bb 716+
7f6c2427
ER
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+};
cdbbc5bb 738+
7f6c2427 739+struct mdhd_t
cdbbc5bb 740+{
7f6c2427
ER
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_;
cdbbc5bb
ER
749+};
750+
7f6c2427 751+struct vmhd_t
cdbbc5bb 752+{
7f6c2427
ER
753+ unsigned int version_;
754+ unsigned int flags_;
755+ uint16_t graphics_mode_;
756+ uint16_t opcolor_[3];
757+};
cdbbc5bb 758+
7f6c2427
ER
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)
cdbbc5bb 946+ {
7f6c2427
ER
947+ if(size < 92-8)
948+ return 0;
cdbbc5bb 949+
7f6c2427
ER
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;
cdbbc5bb 961+
7f6c2427
ER
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'))
cdbbc5bb 1204+ {
7f6c2427
ER
1205+ length = read_8(buffer);
1206+ buffer += 1;
1207+ if(size < length)
1208+ length = (size_t)size;
cdbbc5bb 1209+ }
7f6c2427
ER
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'))
cdbbc5bb 1232+ {
7f6c2427 1233+ buffer = write_8(buffer, strlen(hdlr->name_));
cdbbc5bb
ER
1234+ }
1235+
7f6c2427
ER
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;
cdbbc5bb
ER
1892+}
1893+
7f6c2427 1894+static int stbl_add_ctts(void* parent, void* child)
cdbbc5bb 1895+{
7f6c2427
ER
1896+ struct stbl_t* stbl = parent;
1897+ stbl->ctts_ = child;
cdbbc5bb 1898+
7f6c2427
ER
1899+ return 1;
1900+}
1901+
1902+static void* stbl_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
cdbbc5bb 1903+{
7f6c2427 1904+ struct stbl_t* atom = stbl_init();
cdbbc5bb 1905+
7f6c2427
ER
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_)
cdbbc5bb 1923+ {
7f6c2427
ER
1924+ printf("stbl: missing stts\n");
1925+ result = 0;
1926+ }
cdbbc5bb 1927+
7f6c2427
ER
1928+ if(!atom->stsc_)
1929+ {
1930+ printf("stbl: missing stsc\n");
1931+ result = 0;
1932+ }
cdbbc5bb 1933+
7f6c2427
ER
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+ }
cdbbc5bb 1945+
7f6c2427
ER
1946+ if(!result)
1947+ {
1948+ stbl_exit(atom);
1949+ return 0;
cdbbc5bb 1950+ }
7f6c2427
ER
1951+
1952+ return atom;
cdbbc5bb
ER
1953+}
1954+
7f6c2427 1955+static unsigned char* stbl_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
cdbbc5bb 1956+{
7f6c2427
ER
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+}
cdbbc5bb 1974+
7f6c2427 1975+static unsigned int stbl_get_nearest_keyframe(struct stbl_t const* stbl, unsigned int sample)
cdbbc5bb 1976+{
7f6c2427
ER
1977+ // If the sync atom is not present, all samples are implicit sync samples.
1978+ if(!stbl->stss_)
1979+ return sample;
cdbbc5bb 1980+
7f6c2427
ER
1981+ return stss_get_nearest_keyframe(stbl->stss_, sample);
1982+}
cdbbc5bb 1983+
7f6c2427
ER
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;
cdbbc5bb 1990+
7f6c2427
ER
1991+ return atom;
1992+}
cdbbc5bb 1993+
7f6c2427
ER
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_);
cdbbc5bb 2003+ }
7f6c2427
ER
2004+ if(atom->stbl_)
2005+ {
2006+ stbl_exit(atom->stbl_);
2007+ }
2008+ free(atom);
cdbbc5bb
ER
2009+}
2010+
7f6c2427 2011+static int minf_add_vmhd(void* parent, void* child)
cdbbc5bb 2012+{
7f6c2427
ER
2013+ struct minf_t* minf = parent;
2014+ minf->vmhd_ = child;
cdbbc5bb 2015+
7f6c2427
ER
2016+ return 1;
2017+}
2018+
2019+static int minf_add_stbl(void* parent, void* child)
cdbbc5bb 2020+{
7f6c2427
ER
2021+ struct minf_t* minf = parent;
2022+ minf->stbl_ = child;
cdbbc5bb 2023+
7f6c2427
ER
2024+ return 1;
2025+}
2026+
2027+static void* minf_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
cdbbc5bb 2028+{
7f6c2427 2029+ struct minf_t* atom = minf_init();
cdbbc5bb 2030+
7f6c2427
ER
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+ };
cdbbc5bb 2035+
7f6c2427
ER
2036+ int result = atom_reader(atom_read_list,
2037+ sizeof(atom_read_list) / sizeof(atom_read_list[0]),
2038+ atom,
2039+ buffer, size);
cdbbc5bb 2040+
7f6c2427
ER
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;
cdbbc5bb
ER
2055+}
2056+
7f6c2427 2057+static unsigned char* minf_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
cdbbc5bb 2058+{
7f6c2427
ER
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;
cdbbc5bb
ER
2071+}
2072+
7f6c2427 2073+static struct mdia_t* mdia_init()
cdbbc5bb 2074+{
7f6c2427
ER
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;
cdbbc5bb 2080+
7f6c2427
ER
2081+ return atom;
2082+}
cdbbc5bb 2083+
7f6c2427
ER
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+}
cdbbc5bb 2104+
7f6c2427
ER
2105+static int mdia_add_mdhd(void* parent, void* child)
2106+{
2107+ struct mdia_t* mdia = parent;
2108+ mdia->mdhd_ = child;
cdbbc5bb 2109+
7f6c2427 2110+ return 1;
cdbbc5bb
ER
2111+}
2112+
7f6c2427 2113+static int mdia_add_hdlr(void* parent, void* child)
cdbbc5bb 2114+{
7f6c2427
ER
2115+ struct mdia_t* mdia = parent;
2116+ mdia->hdlr_ = child;
2117+
2118+ return 1;
2119+}
cdbbc5bb 2120+
7f6c2427 2121+static int mdia_add_minf(void* parent, void* child)
cdbbc5bb 2122+{
7f6c2427
ER
2123+ struct mdia_t* mdia = parent;
2124+ mdia->minf_ = child;
2125+
2126+ return 1;
cdbbc5bb
ER
2127+}
2128+
7f6c2427 2129+static void* mdia_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
cdbbc5bb 2130+{
7f6c2427
ER
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)
cdbbc5bb 2164+ {
7f6c2427
ER
2165+ mdia_exit(atom);
2166+ return 0;
cdbbc5bb 2167+ }
7f6c2427
ER
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;
cdbbc5bb
ER
2187+}
2188+
2189+void trak_build_index(struct trak_t* trak)
2190+{
7f6c2427 2191+ struct stco_t const* stco = trak->mdia_->minf_->stbl_->stco_;
cdbbc5bb 2192+
7f6c2427 2193+ trak->chunks_size_ = stco->entries_;
cdbbc5bb
ER
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+ {
7f6c2427 2200+ trak->chunks_[i].pos_ = stco->chunk_offsets_[i];
cdbbc5bb
ER
2201+ }
2202+ }
2203+
2204+ // process chunkmap:
2205+ {
7f6c2427 2206+ struct stsc_t const* stsc = trak->mdia_->minf_->stbl_->stsc_;
cdbbc5bb 2207+ unsigned int last = trak->chunks_size_;
7f6c2427 2208+ unsigned int i = stsc->entries_;
cdbbc5bb
ER
2209+ while(i > 0)
2210+ {
cdbbc5bb
ER
2211+ unsigned int j;
2212+
2213+ --i;
2214+
7f6c2427 2215+ for(j = stsc->table_[i].chunk_; j < last; j++)
cdbbc5bb 2216+ {
7f6c2427
ER
2217+ trak->chunks_[j].id_ = stsc->table_[i].id_;
2218+ trak->chunks_[j].size_ = stsc->table_[i].samples_;
cdbbc5bb 2219+ }
7f6c2427 2220+ last = stsc->table_[i].chunk_;
cdbbc5bb
ER
2221+ }
2222+ }
2223+
2224+ // calc pts of chunks:
2225+ {
7f6c2427
ER
2226+ struct stsz_t const* stsz = trak->mdia_->minf_->stbl_->stsz_;
2227+ unsigned int sample_size = stsz->sample_size_;
cdbbc5bb
ER
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+ {
7f6c2427 2240+ trak->samples_size_ = stsz->entries_;
cdbbc5bb
ER
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)
7f6c2427 2253+ trak->samples_[i].size_ = stsz->sample_sizes_[i];
cdbbc5bb
ER
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+ {
7f6c2427 2274+ struct stts_t const* stts = trak->mdia_->minf_->stbl_->stts_;
cdbbc5bb 2275+ unsigned int s = 0;
7f6c2427
ER
2276+ unsigned int pts = 0;
2277+ unsigned int entries = stts->entries_;
cdbbc5bb
ER
2278+ unsigned int j;
2279+ for(j = 0; j < entries; j++)
2280+ {
2281+ unsigned int i;
7f6c2427
ER
2282+ unsigned int sample_count = stts->table_[j].sample_count_;
2283+ unsigned int sample_duration = stts->table_[j].sample_duration_;
cdbbc5bb
ER
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+ {
7f6c2427 2295+ struct ctts_t const* ctts = trak->mdia_->minf_->stbl_->ctts_;
cdbbc5bb
ER
2296+ if(ctts)
2297+ {
2298+ unsigned int s = 0;
7f6c2427 2299+ unsigned int entries = ctts->entries_;
cdbbc5bb 2300+ unsigned int j;
7f6c2427 2301+ for(j = 0; j != entries; j++)
cdbbc5bb
ER
2302+ {
2303+ unsigned int i;
7f6c2427
ER
2304+ unsigned int sample_count = ctts->table_[j].sample_count_;
2305+ unsigned int sample_offset = ctts->table_[j].sample_offset_;
cdbbc5bb
ER
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;
7f6c2427 2319+ for(j = 0; j != trak->chunks_size_; j++)
cdbbc5bb 2320+ {
7f6c2427 2321+ uint64_t pos = trak->chunks_[j].pos_;
cdbbc5bb 2322+ unsigned int i;
7f6c2427 2323+ for(i = 0; i != trak->chunks_[j].size_; i++)
cdbbc5bb
ER
2324+ {
2325+ trak->samples_[s].pos_ = pos;
2326+ pos += trak->samples_[s].size_;
2327+ ++s;
2328+ }
2329+ }
2330+ }
2331+}
2332+
7f6c2427 2333+void trak_update_index(struct trak_t* trak, unsigned int start, unsigned int end)
cdbbc5bb
ER
2334+{
2335+ // write samples [start,end>
2336+
2337+ // stts = [entries * [sample_count, sample_duration]
2338+ {
7f6c2427
ER
2339+ struct stts_t* stts = trak->mdia_->minf_->stbl_->stts_;
2340+
cdbbc5bb 2341+ unsigned int entries = 0;
cdbbc5bb 2342+ unsigned int s;
7f6c2427 2343+
cdbbc5bb
ER
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+ }
7f6c2427
ER
2356+ stts->table_[entries].sample_count_ = sample_count;
2357+ stts->table_[entries].sample_duration_ = sample_duration;
cdbbc5bb
ER
2358+ ++entries;
2359+ }
7f6c2427
ER
2360+ stts->entries_ = entries;
2361+
cdbbc5bb
ER
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+ {
7f6c2427 2371+ struct ctts_t* ctts = trak->mdia_->minf_->stbl_->ctts_;
cdbbc5bb
ER
2372+ if(ctts)
2373+ {
2374+ unsigned int entries = 0;
cdbbc5bb 2375+ unsigned int s;
7f6c2427 2376+
cdbbc5bb
ER
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
7f6c2427
ER
2389+ ctts->table_[entries].sample_count_ = sample_count;
2390+ ctts->table_[entries].sample_offset_ = sample_offset;
cdbbc5bb
ER
2391+ ++entries;
2392+ }
7f6c2427 2393+ ctts->entries_ = entries;
cdbbc5bb
ER
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+ {
7f6c2427 2404+ struct stsc_t* stsc = trak->mdia_->minf_->stbl_->stsc_;
cdbbc5bb 2405+ unsigned int i;
7f6c2427 2406+
cdbbc5bb
ER
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;
7f6c2427
ER
2416+ unsigned int chunk_end;
2417+ // problem.mp4: reported by Jin-seok Lee. Second track contains no samples
2418+ if(trak->chunks_size_ != 0)
cdbbc5bb 2419+ {
7f6c2427
ER
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_)
cdbbc5bb 2431+ {
7f6c2427 2432+ for(i += 1; i != trak->chunks_size_; ++i)
cdbbc5bb 2433+ {
7f6c2427
ER
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+ }
cdbbc5bb
ER
2447+ }
2448+ }
2449+ }
7f6c2427
ER
2450+ chunk_end = i;
2451+ stsc->entries_ = stsc_entries;
2452+
cdbbc5bb 2453+ {
7f6c2427
ER
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;
cdbbc5bb
ER
2462+
2463+ // patch first chunk with correct sample offset
7f6c2427 2464+ stco->chunk_offsets_[0] = (uint32_t)trak->samples_[start].pos_;
cdbbc5bb
ER
2465+ }
2466+ }
2467+ }
2468+
2469+ // process sync samples:
7f6c2427 2470+ if(trak->mdia_->minf_->stbl_->stss_)
cdbbc5bb 2471+ {
7f6c2427
ER
2472+ struct stss_t* stss = trak->mdia_->minf_->stbl_->stss_;
2473+ unsigned int entries = 0;
cdbbc5bb
ER
2474+ unsigned int stss_start;
2475+ unsigned int i;
7f6c2427
ER
2476+
2477+ for(i = 0; i != stss->entries_; ++i)
cdbbc5bb 2478+ {
7f6c2427 2479+ if(stss->sample_numbers_[i] >= start + 1)
cdbbc5bb
ER
2480+ break;
2481+ }
2482+ stss_start = i;
7f6c2427 2483+ for(; i != stss->entries_; ++i)
cdbbc5bb 2484+ {
7f6c2427 2485+ unsigned int sync_sample = stss->sample_numbers_[i];
cdbbc5bb
ER
2486+ if(sync_sample >= end + 1)
2487+ break;
7f6c2427
ER
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;
cdbbc5bb 2656+
7f6c2427
ER
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;
cdbbc5bb 2662+ }
7f6c2427
ER
2663+ else
2664+ {
2665+ if(size < 120-8)
2666+ return 0;
cdbbc5bb 2667+
7f6c2427
ER
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)
cdbbc5bb 2682+ {
7f6c2427
ER
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;
cdbbc5bb 2691+ }
7f6c2427
ER
2692+
2693+ atom->next_track_id_ = read_32(buffer + 0);
2694+
2695+ return atom;
cdbbc5bb
ER
2696+}
2697+
7f6c2427 2698+static unsigned char* mvhd_write(void* UNUSED(parent), void* atom, unsigned char* buffer)
cdbbc5bb 2699+{
7f6c2427
ER
2700+ struct mvhd_t const* mvhd = atom;
2701+ unsigned int i;
cdbbc5bb 2702+
7f6c2427
ER
2703+ buffer = write_8(buffer, mvhd->version_);
2704+ buffer = write_24(buffer, mvhd->flags_);
2705+
2706+ if(mvhd->version_ == 0)
cdbbc5bb 2707+ {
7f6c2427
ER
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+ }
cdbbc5bb 2720+
7f6c2427
ER
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]);
cdbbc5bb 2726+
7f6c2427
ER
2727+ for(i = 0; i != 9; ++i)
2728+ {
2729+ buffer = write_32(buffer, mvhd->matrix_[i]);
cdbbc5bb
ER
2730+ }
2731+
7f6c2427 2732+ for(i = 0; i != 6; ++i)
cdbbc5bb 2733+ {
7f6c2427 2734+ buffer = write_32(buffer, mvhd->predefined_[i]);
cdbbc5bb
ER
2735+ }
2736+
7f6c2427 2737+ buffer = write_32(buffer, mvhd->next_track_id_);
cdbbc5bb 2738+
7f6c2427 2739+ return buffer;
cdbbc5bb
ER
2740+}
2741+
7f6c2427 2742+static struct moov_t* moov_init()
cdbbc5bb 2743+{
7f6c2427
ER
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;
cdbbc5bb
ER
2750+}
2751+
7f6c2427 2752+static void moov_exit(struct moov_t* atom)
cdbbc5bb
ER
2753+{
2754+ unsigned int i;
7f6c2427
ER
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)
cdbbc5bb 2764+ {
7f6c2427 2765+ trak_exit(atom->traks_[i]);
cdbbc5bb 2766+ }
7f6c2427 2767+ free(atom);
cdbbc5bb
ER
2768+}
2769+
7f6c2427 2770+static int moov_add_mvhd(void* parent, void* mvhd)
cdbbc5bb 2771+{
7f6c2427
ER
2772+ struct moov_t* moov = parent;
2773+ moov->mvhd_ = mvhd;
2774+
2775+ return 1;
cdbbc5bb
ER
2776+}
2777+
7f6c2427 2778+static int moov_add_trak(void* parent, void* child)
cdbbc5bb 2779+{
7f6c2427
ER
2780+ struct moov_t* moov = parent;
2781+ struct trak_t* trak = child;
2782+ if(moov->tracks_ == MAX_TRACKS)
cdbbc5bb 2783+ {
7f6c2427
ER
2784+ trak_exit(trak);
2785+ return 0;
cdbbc5bb 2786+ }
7f6c2427
ER
2787+
2788+ if(trak->mdia_->hdlr_->handler_type_ != FOURCC('v', 'i', 'd', 'e') &&
2789+ trak->mdia_->hdlr_->handler_type_ != FOURCC('s', 'o', 'u', 'n'))
cdbbc5bb 2790+ {
7f6c2427
ER
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
cdbbc5bb 2799+ }
7f6c2427
ER
2800+
2801+ moov->traks_[moov->tracks_] = trak;
2802+ ++moov->tracks_;
cdbbc5bb 2803+
7f6c2427 2804+ return 1;
cdbbc5bb
ER
2805+}
2806+
7f6c2427 2807+static void* moov_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size)
cdbbc5bb 2808+{
7f6c2427 2809+ struct moov_t* atom = moov_init();
cdbbc5bb 2810+
7f6c2427
ER
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_)
cdbbc5bb 2823+ {
7f6c2427
ER
2824+ printf("moov: missing mvhd\n");
2825+ result = 0;
cdbbc5bb 2826+ }
7f6c2427
ER
2827+
2828+ if(!atom->tracks_)
cdbbc5bb 2829+ {
7f6c2427
ER
2830+ printf("moov: missing trak\n");
2831+ result = 0;
cdbbc5bb 2832+ }
cdbbc5bb 2833+
7f6c2427
ER
2834+ if(!result)
2835+ {
2836+ moov_exit(atom);
2837+ return 0;
2838+ }
2839+
2840+ return atom;
cdbbc5bb
ER
2841+}
2842+
7f6c2427 2843+static void moov_write(struct moov_t* atom, unsigned char* buffer)
cdbbc5bb 2844+{
7f6c2427
ER
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);
cdbbc5bb
ER
2875+}
2876+
7f6c2427 2877+void moov_shift_offsets(struct moov_t* moov, int64_t offset)
cdbbc5bb 2878+{
cdbbc5bb 2879+ unsigned int i;
7f6c2427 2880+ for(i = 0; i != moov->tracks_; ++i)
cdbbc5bb 2881+ {
7f6c2427 2882+ trak_shift_offsets(moov->traks_[i], offset);
cdbbc5bb 2883+ }
cdbbc5bb
ER
2884+}
2885+
7f6c2427 2886+void moov_shift_offsets_inplace(struct moov_t* moov, int64_t offset)
cdbbc5bb 2887+{
7f6c2427
ER
2888+ unsigned int i;
2889+ for(i = 0; i != moov->tracks_; ++i)
2890+ {
2891+ trak_shift_offsets_inplace(moov->traks_[i], offset);
2892+ }
cdbbc5bb
ER
2893+}
2894+
7f6c2427
ER
2895+unsigned int moov_seek(unsigned char* moov_data,
2896+ uint64_t* moov_size,
cdbbc5bb 2897+ float start_time,
7f6c2427
ER
2898+ float end_time,
2899+ uint64_t* mdat_start,
2900+ uint64_t* mdat_size,
2901+ uint64_t offset,
2902+ int client_is_flash)
cdbbc5bb 2903+{
7f6c2427
ER
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)
cdbbc5bb 2908+ {
7f6c2427 2909+ printf("Error parsing moov header\n");
cdbbc5bb
ER
2910+ return 0;
2911+ }
2912+
2913+ {
7f6c2427 2914+ long moov_time_scale = moov->mvhd_->timescale_;
cdbbc5bb 2915+ unsigned int start = (unsigned int)(start_time * moov_time_scale);
7f6c2427
ER
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;
cdbbc5bb 2919+ unsigned int i;
7f6c2427 2920+ unsigned int pass;
cdbbc5bb
ER
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];
7f6c2427 2925+ unsigned int trak_sample_end[MAX_TRACKS];
cdbbc5bb 2926+
7f6c2427 2927+ uint64_t moov_duration = 0;
cdbbc5bb
ER
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.
7f6c2427
ER
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)
cdbbc5bb 2955+ {
7f6c2427 2956+ for(i = 0; i != moov->tracks_; ++i)
cdbbc5bb 2957+ {
7f6c2427
ER
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+ }
cdbbc5bb 3011+ }
cdbbc5bb
ER
3012+ }
3013+
7f6c2427
ER
3014+ printf("start=%u\n", start);
3015+ printf("end=%u\n", end);
3016+
3017+ if(end && start >= end)
cdbbc5bb 3018+ {
7f6c2427
ER
3019+ moov_exit(moov);
3020+ return 0;
cdbbc5bb
ER
3021+ }
3022+
cdbbc5bb
ER
3023+ for(i = 0; i != moov->tracks_; ++i)
3024+ {
7f6c2427
ER
3025+ struct trak_t* trak = moov->traks_[i];
3026+ struct stbl_t* stbl = trak->mdia_->minf_->stbl_;
cdbbc5bb
ER
3027+
3028+ unsigned int start_sample = trak_sample_start[i];
7f6c2427
ER
3029+ unsigned int end_sample = trak_sample_end[i];
3030+
3031+ // ignore empty track
3032+ if(trak->mdia_->mdhd_->duration_ == 0)
3033+ continue;
cdbbc5bb 3034+
7f6c2427 3035+ trak_update_index(trak, start_sample, end_sample);
cdbbc5bb
ER
3036+
3037+ {
7f6c2427 3038+ uint64_t skip =
cdbbc5bb 3039+ trak->samples_[start_sample].pos_ - trak->samples_[0].pos_;
7f6c2427
ER
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+ }
cdbbc5bb
ER
3053+ }
3054+
3055+ {
3056+ // fixup trak (duration)
7f6c2427
ER
3057+ uint64_t trak_duration = stts_get_duration(stbl->stts_);
3058+ long trak_time_scale = trak->mdia_->mdhd_->timescale_;
cdbbc5bb 3059+ float trak_to_moov_time = (float)moov_time_scale / (float)trak_time_scale;
7f6c2427
ER
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);
cdbbc5bb
ER
3065+
3066+ if(duration > moov_duration)
3067+ moov_duration = duration;
7f6c2427 3068+ }
cdbbc5bb
ER
3069+ }
3070+
7f6c2427
ER
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_));
cdbbc5bb 3075+ }
7f6c2427
ER
3076+ moov->mvhd_->duration_ = moov_duration;
3077+
3078+ // subtract bytes we skip at the front of the mdat atom
3079+ offset -= skip_from_start;
cdbbc5bb 3080+
7f6c2427
ER
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+ }
cdbbc5bb 3108+
7f6c2427
ER
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
cdbbc5bb 3191+
7f6c2427
ER
3192+ *mdat_start += skip_from_start;
3193+ if(end_offset != 0)
3194+ {
3195+ *mdat_size = end_offset;
3196+ }
3197+ *mdat_size -= skip_from_start;
cdbbc5bb
ER
3198+ }
3199+
3200+ moov_exit(moov);
cdbbc5bb
ER
3201+
3202+ return 1;
3203+}
3204+
7f6c2427
ER
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+
cdbbc5bb
ER
3439+// End Of File
3440+
This page took 0.603901 seconds and 4 git commands to generate.