35 #define fseeko(x, y, z) fseeko64(x, y, z) 37 #define ftello(x) ftello64(x) 40 #define fseeko(x, y, z) _fseeki64(x, y, z) 42 #define ftello(x) _ftelli64(x) 45 #define MIN(a,b) ((a) > (b) ? (b) : (a)) 47 #define BE_32(x) (((uint32_t)(((uint8_t*)(x))[0]) << 24) | \ 48 (((uint8_t*)(x))[1] << 16) | \ 49 (((uint8_t*)(x))[2] << 8) | \ 52 #define BE_64(x) (((uint64_t)(((uint8_t*)(x))[0]) << 56) | \ 53 ((uint64_t)(((uint8_t*)(x))[1]) << 48) | \ 54 ((uint64_t)(((uint8_t*)(x))[2]) << 40) | \ 55 ((uint64_t)(((uint8_t*)(x))[3]) << 32) | \ 56 ((uint64_t)(((uint8_t*)(x))[4]) << 24) | \ 57 ((uint64_t)(((uint8_t*)(x))[5]) << 16) | \ 58 ((uint64_t)(((uint8_t*)(x))[6]) << 8) | \ 59 ((uint64_t)( (uint8_t*)(x))[7])) 61 #define AV_WB32(p, val) { \ 62 ((uint8_t*)(p))[0] = ((val) >> 24) & 0xff; \ 63 ((uint8_t*)(p))[1] = ((val) >> 16) & 0xff; \ 64 ((uint8_t*)(p))[2] = ((val) >> 8) & 0xff; \ 65 ((uint8_t*)(p))[3] = (val) & 0xff; \ 68 #define AV_WB64(p, val) { \ 69 AV_WB32(p, (val) >> 32) \ 73 #define BE_FOURCC(ch0, ch1, ch2, ch3) \ 74 ( (uint32_t)(unsigned char)(ch3) | \ 75 ((uint32_t)(unsigned char)(ch2) << 8) | \ 76 ((uint32_t)(unsigned char)(ch1) << 16) | \ 77 ((uint32_t)(unsigned char)(ch0) << 24) ) 79 #define QT_ATOM BE_FOURCC 81 #define FREE_ATOM QT_ATOM('f', 'r', 'e', 'e') 82 #define JUNK_ATOM QT_ATOM('j', 'u', 'n', 'k') 83 #define MDAT_ATOM QT_ATOM('m', 'd', 'a', 't') 84 #define MOOV_ATOM QT_ATOM('m', 'o', 'o', 'v') 85 #define PNOT_ATOM QT_ATOM('p', 'n', 'o', 't') 86 #define SKIP_ATOM QT_ATOM('s', 'k', 'i', 'p') 87 #define WIDE_ATOM QT_ATOM('w', 'i', 'd', 'e') 88 #define PICT_ATOM QT_ATOM('P', 'I', 'C', 'T') 89 #define FTYP_ATOM QT_ATOM('f', 't', 'y', 'p') 90 #define UUID_ATOM QT_ATOM('u', 'u', 'i', 'd') 92 #define CMOV_ATOM QT_ATOM('c', 'm', 'o', 'v') 93 #define TRAK_ATOM QT_ATOM('t', 'r', 'a', 'k') 94 #define MDIA_ATOM QT_ATOM('m', 'd', 'i', 'a') 95 #define MINF_ATOM QT_ATOM('m', 'i', 'n', 'f') 96 #define STBL_ATOM QT_ATOM('s', 't', 'b', 'l') 97 #define STCO_ATOM QT_ATOM('s', 't', 'c', 'o') 98 #define CO64_ATOM QT_ATOM('c', 'o', '6', '4') 100 #define ATOM_PREAMBLE_SIZE 8 101 #define COPY_BUFFER_SIZE 33554432 102 #define MAX_FTYP_ATOM_SIZE 1048576 133 unsigned char *
pos = buf;
134 unsigned char *end = pos +
size;
147 fprintf(stderr,
"not enough room for 64 bit atom size\n");
162 fprintf(stderr,
"atom size %"PRIu64
" too small\n", atom.
size);
168 if (atom.
size > end - pos) {
169 fprintf(stderr,
"atom size %"PRIu64
" too big\n", atom.
size);
187 uint32_t current_offset;
188 uint32_t offset_count;
192 printf(
" patching stco atom...\n");
193 if (atom->
size < 8) {
194 fprintf(stderr,
"stco atom size %"PRIu64
" too small\n", atom->
size);
199 if (offset_count > (atom->
size - 8) / 4) {
200 fprintf(stderr,
"stco offset count %"PRIu32
" too big\n", offset_count);
207 for (pos = atom->
data + 8, end = pos + offset_count * 4;
210 current_offset =
BE_32(pos);
223 uint64_t current_offset;
224 uint32_t offset_count;
228 printf(
" patching co64 atom...\n");
229 if (atom->
size < 8) {
230 fprintf(stderr,
"co64 atom size %"PRIu64
" too small\n", atom->
size);
235 if (offset_count > (atom->
size - 8) / 8) {
236 fprintf(stderr,
"co64 offset count %"PRIu32
" too big\n", offset_count);
240 for (pos = atom->
data + 8, end = pos + offset_count * 8;
243 current_offset =
BE_64(pos);
256 switch (atom->
type) {
269 if (context->
depth > 10) {
270 fprintf(stderr,
"atoms too deeply nested\n");
288 switch (header_size) {
304 uint32_t offset_count;
305 uint32_t original_offset;
318 for (pos = atom->
data + 8, end = pos + offset_count * 4;
322 new_offset = (uint64_t)original_offset + context->
new_moov_size;
331 unsigned char *start_pos;
334 switch (atom->
type) {
346 start_pos = context->
dest;
365 context->
dest += copy_size;
373 unsigned char **moov_atom,
374 uint64_t *moov_atom_size)
378 unsigned char *new_moov_atom;
386 &update_context) < 0) {
394 printf(
" upgrading stco atoms to co64...\n");
400 if (new_moov_atom ==
NULL) {
401 fprintf(stderr,
"could not allocate %"PRIu64
" bytes for updated moov atom\n",
407 upgrade_context.
dest = new_moov_atom;
413 &upgrade_context) < 0) {
419 *moov_atom = new_moov_atom;
422 if (upgrade_context.
dest != *moov_atom + *moov_atom_size) {
423 fprintf(stderr,
"unexpected - wrong number of moov bytes written\n");
430 int main(
int argc,
char *argv[])
435 uint32_t atom_type = 0;
436 uint64_t atom_size = 0;
437 uint64_t atom_offset = 0;
439 unsigned char *moov_atom =
NULL;
440 unsigned char *ftyp_atom =
NULL;
441 uint64_t moov_atom_size;
442 uint64_t ftyp_atom_size = 0;
443 int64_t start_offset = 0;
444 unsigned char *copy_buffer =
NULL;
446 uint64_t free_size = 0;
447 uint64_t moov_size = 0;
450 printf(
"Usage: qt-faststart <infile.mov> <outfile.mov>\n" 451 "Note: alternatively you can use -movflags +faststart in ffmpeg\n");
455 if (!strcmp(argv[1], argv[2])) {
456 fprintf(stderr,
"input and output files need to be different\n");
460 infile = fopen(argv[1],
"rb");
468 while (!feof(infile)) {
472 atom_size =
BE_32(&atom_bytes[0]);
473 atom_type =
BE_32(&atom_bytes[4]);
478 fprintf(stderr,
"ftyp atom size %"PRIu64
" too big\n",
482 ftyp_atom_size = atom_size;
484 ftyp_atom = malloc(ftyp_atom_size);
486 fprintf(stderr,
"could not allocate %"PRIu64
" bytes for ftyp atom\n",
491 fread(ftyp_atom, atom_size, 1, infile) != 1 ||
492 (start_offset = ftello(infile)) < 0) {
499 if (atom_size == 1) {
503 atom_size =
BE_64(&atom_bytes[0]);
513 printf(
"%c%c%c%c %10"PRIu64
" %"PRIu64
"\n",
514 (atom_type >> 24) & 255,
515 (atom_type >> 16) & 255,
516 (atom_type >> 8) & 255,
517 (atom_type >> 0) & 255,
530 fprintf(stderr,
"encountered non-QT top-level atom (is this a QuickTime file?)\n");
533 atom_offset += atom_size;
542 moov_size = atom_size;
544 if (moov_size && atom_type ==
FREE_ATOM) {
545 free_size += atom_size;
547 atom_size = moov_size;
552 printf(
"last atom in file was not a moov atom\n");
558 if (atom_size < 16) {
559 fprintf(stderr,
"bad moov atom size\n");
565 if (fseeko(infile, -(atom_size + free_size), SEEK_END)) {
569 last_offset = ftello(infile);
570 if (last_offset < 0) {
574 moov_atom_size = atom_size;
575 moov_atom = malloc(moov_atom_size);
577 fprintf(stderr,
"could not allocate %"PRIu64
" bytes for moov atom\n", atom_size);
580 if (fread(moov_atom, atom_size, 1, infile) != 1) {
588 fprintf(stderr,
"this utility does not support compressed moov atoms yet\n");
601 infile = fopen(argv[1],
"rb");
607 if (start_offset > 0) {
608 if (fseeko(infile, start_offset, SEEK_SET)) {
613 last_offset -= start_offset;
616 outfile = fopen(argv[2],
"wb");
623 if (ftyp_atom_size > 0) {
624 printf(
" writing ftyp atom...\n");
625 if (fwrite(ftyp_atom, ftyp_atom_size, 1, outfile) != 1) {
632 printf(
" writing moov atom...\n");
633 if (fwrite(moov_atom, moov_atom_size, 1, outfile) != 1) {
640 copy_buffer = malloc(bytes_to_copy);
642 fprintf(stderr,
"could not allocate %d bytes for copy_buffer\n", bytes_to_copy);
645 printf(
" copying rest of file...\n");
646 while (last_offset) {
647 bytes_to_copy =
MIN(bytes_to_copy, last_offset);
649 if (fread(copy_buffer, bytes_to_copy, 1, infile) != 1) {
653 if (fwrite(copy_buffer, bytes_to_copy, 1, outfile) != 1) {
657 last_offset -= bytes_to_copy;
static int parse_atoms(unsigned char *buf, uint64_t size, parse_atoms_callback_t callback, void *context)
int(* parse_atoms_callback_t)(void *context, atom_t *atom)
static int update_co64_offsets(update_chunk_offsets_context_t *context, atom_t *atom)
static int update_moov_atom(unsigned char **moov_atom, uint64_t *moov_atom_size)
#define ATOM_PREAMBLE_SIZE
uint64_t original_moov_size
static const uint8_t header[24]
#define MAX_FTYP_ATOM_SIZE
static void callback(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time, enum dshowDeviceType devtype)
static int upgrade_stco_callback(void *ctx, atom_t *atom)
static void update_context(VignetteContext *s, AVFilterLink *inlink, AVFrame *frame)
static void set_atom_size(unsigned char *header, uint32_t header_size, uint64_t size)
uint64_t stco_offset_count
static int update_chunk_offsets_callback(void *ctx, atom_t *atom)
int main(int argc, char *argv[])
printf("static const uint8_t my_array[100] = {\n")
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option keep it simple and lowercase description are in without and describe what they for example set the foo of the bar offset is the offset of the field in your local context
static int update_stco_offsets(update_chunk_offsets_context_t *context, atom_t *atom)
static void upgrade_stco_atom(upgrade_stco_context_t *context, atom_t *atom)