"Fossies" - the Fresh Open Source Software Archive

Member "faac-1_30/frontend/mp4write.c" (16 Oct 2019, 20231 Bytes) of package /linux/misc/faac-1_30.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mp4write.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.29.9_vs_1.29.9.2.

    1 /****************************************************************************
    2     MP4 output module
    3 
    4     Copyright (C) 2017 Krzysztof Nikiel
    5 
    6     This program is free software: you can redistribute it and/or modify
    7     it under the terms of the GNU General Public License as published by
    8     the Free Software Foundation, either version 3 of the License, or
    9     (at your option) any later version.
   10 
   11     This program is distributed in the hope that it will be useful,
   12     but WITHOUT ANY WARRANTY; without even the implied warranty of
   13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14     GNU General Public License for more details.
   15 
   16     You should have received a copy of the GNU General Public License
   17     along with this program.  If not, see <http://www.gnu.org/licenses/>.
   18 ****************************************************************************/
   19 
   20 #ifdef HAVE_CONFIG_H
   21 #include "config.h"
   22 #endif
   23 
   24 #include <stdlib.h>
   25 #include <stdio.h>
   26 #ifndef WORDS_BIGENDIAN
   27 //#include <byteswap.h>
   28 #endif
   29 #include <string.h>
   30 #include <time.h>
   31 #include <unistd.h>
   32 
   33 #include "mp4write.h"
   34 
   35 enum ATOM_TYPE
   36 {
   37     ATOM_STOP = 0 /* end of atoms */ ,
   38     ATOM_NAME /* plain atom */ ,
   39     ATOM_DESCENT,               /* starts group of children */
   40     ATOM_ASCENT,                /* ends group */
   41     ATOM_DATA,
   42 };
   43 typedef struct
   44 {
   45     uint16_t opcode;
   46     void *data;
   47 } creator_t;
   48 
   49 mp4config_t mp4config = { 0 };
   50 
   51 static FILE *g_fout = NULL;
   52 
   53 static inline uint32_t be32(uint32_t u32)
   54 {
   55 #ifndef WORDS_BIGENDIAN
   56 #if defined (__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)))
   57     return __builtin_bswap32(u32);
   58 #elif defined (_MSC_VER)
   59     return _byteswap_ulong(u32);
   60 #else
   61     return (u32 << 24) | ((u32 << 8) & 0xFF0000) | ((u32 >> 8) & 0xFF00) | (u32 >> 24);
   62 #endif
   63 #else
   64     return u32;
   65 #endif
   66 }
   67 
   68 static inline uint16_t be16(uint16_t u16)
   69 {
   70 #ifndef WORDS_BIGENDIAN
   71 #if defined (__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)))
   72     return __builtin_bswap16(u16);
   73 #elif defined (_MSC_VER)
   74     return _byteswap_ushort(u16);
   75 #else
   76     return (u16 << 8) | (u16 >> 8);
   77 #endif
   78 #else
   79     return u16;
   80 #endif
   81 }
   82 
   83 static int dataout(const void *data, int size)
   84 {
   85     if (fwrite(data, 1, size, g_fout) != size)
   86     {
   87         perror("mp4out");
   88         return -1;
   89     }
   90     return size;
   91 }
   92 
   93 static int stringout(const char *txt)
   94 {
   95     return dataout(txt, strlen(txt));
   96 }
   97 
   98 static int u32out(uint32_t u32)
   99 {
  100     u32 = be32(u32);
  101     return dataout(&u32, 4);
  102 }
  103 
  104 static int u16out(uint16_t u16)
  105 {
  106     u16 = be16(u16);
  107     return dataout(&u16, 2);
  108 }
  109 
  110 static int u8out(uint8_t u8)
  111 {
  112     if (fwrite(&u8, 1, 1, g_fout) != 1)
  113     {
  114         perror("mp4 out");
  115         return 0;
  116     }
  117     return 1;
  118 }
  119 
  120 static int ftypout(void)
  121 {
  122     int size = 0;
  123 
  124     size += stringout("M4A ");
  125     size += u32out(0);
  126     size += stringout("M4A ");
  127     size += stringout("mp42");
  128     size += stringout("isom");
  129     size += u32out(0);
  130 
  131     return size;
  132 }
  133 
  134 enum
  135 { SECSINDAY = 24 * 60 * 60 };
  136 static time_t mp4time(void)
  137 {
  138     int y;
  139     time_t t;
  140 
  141     time(&t);
  142 
  143     // add some time from the start of 1904 to the start of 1970
  144     for (y = 1904; y < 1970; y++)
  145     {
  146         t += 365 * SECSINDAY;
  147         if (!(y & 3))
  148             t += SECSINDAY;
  149     }
  150 
  151     return t;
  152 }
  153 
  154 static int mvhdout(void)
  155 {
  156     int size = 0;
  157     int cnt;
  158 
  159     // version
  160     size += u8out(0);
  161     // flags
  162     size += u8out(0);
  163     size += u16out(0);
  164     // Creation time
  165     size += u32out(mp4time());
  166     // Modification time
  167     size += u32out(mp4time());
  168     // Time scale (samplerate)
  169     size += u32out(mp4config.samplerate);
  170     // Duration
  171     size += u32out(mp4config.samples);
  172     // rate
  173     size += u32out(0x00010000);
  174     // volume
  175     size += u16out(0x0100);
  176     // reserved
  177     size += u16out(0);
  178     size += u32out(0);
  179     size += u32out(0);
  180     // matrix
  181     size += u32out(0x00010000);
  182     size += u32out(0);
  183     size += u32out(0);
  184     size += u32out(0);
  185     size += u32out(0x00010000);
  186     size += u32out(0);
  187     size += u32out(0);
  188     size += u32out(0);
  189     size += u32out(0x40000000);
  190 
  191     for (cnt = 0; cnt < 6; cnt++)
  192         size += u32out(0);
  193     // Next track ID
  194     size += u32out(2);
  195 
  196     return size;
  197 };
  198 
  199 static int tkhdout(void)
  200 {
  201     int size = 0;
  202 
  203     // version
  204     size += u8out(0);
  205     // flags
  206     // bits 8-23
  207     size += u16out(0);
  208     // bits 0-7
  209     size += u8out(1 /*track enabled */ );
  210     // Creation time
  211     size += u32out(mp4time());
  212     // Modification time
  213     size += u32out(mp4time());
  214     // Track ID
  215     size += u32out(1);
  216     // Reserved
  217     size += u32out(0);
  218     // Duration
  219     size += u32out(mp4config.samples);
  220     // Reserved
  221     size += u32out(0);
  222     size += u32out(0);
  223     // Layer
  224     size += u16out(0);
  225     // Alternate group
  226     size += u16out(0);
  227     // Volume
  228     size += u16out(0x0100);
  229     // Reserved
  230     size += u16out(0);
  231     // matrix
  232     size += u32out(0x00010000);
  233     size += u32out(0);
  234     size += u32out(0);
  235     size += u32out(0);
  236     size += u32out(0x00010000);
  237     size += u32out(0);
  238     size += u32out(0);
  239     size += u32out(0);
  240     size += u32out(0x40000000);
  241 
  242     // Track width
  243     size += u32out(0);
  244     // Track height
  245     size += u32out(0);
  246 
  247     return size;
  248 };
  249 
  250 static int mdhdout(void)
  251 {
  252     int size = 0;
  253 
  254     // version/flags
  255     size += u32out(0);
  256     // Creation time
  257     size += u32out(mp4time());
  258     // Modification time
  259     size += u32out(mp4time());
  260     // Time scale
  261     size += u32out(mp4config.samplerate);
  262     // Duration
  263     size += u32out(mp4config.samples);
  264     // Language
  265     size += u16out(0 /*0=English */ );
  266     // pre_defined
  267     size += u16out(0);
  268 
  269     return size;
  270 };
  271 
  272 
  273 static int hdlr1out(void)
  274 {
  275     int size = 0;
  276 
  277     // version/flags
  278     size += u32out(0);
  279     // pre_defined
  280     size += u32out(0);
  281     // Component subtype
  282     size += stringout("soun");
  283     // reserved
  284     size += u32out(0);
  285     size += u32out(0);
  286     size += u32out(0);
  287     // name
  288     // null terminate
  289     size += u8out(0);
  290 
  291     return size;
  292 };
  293 
  294 static int smhdout(void)
  295 {
  296     int size = 0;
  297 
  298     // version/flags
  299     size += u32out(0);
  300     // Balance
  301     size += u16out(0 /*center */ );
  302     // Reserved
  303     size += u16out(0);
  304 
  305     return size;
  306 };
  307 
  308 static int drefout(void)
  309 {
  310     int size = 0;
  311 
  312     // version/flags
  313     size += u32out(0);
  314     // Number of entries
  315     size += u32out(1 /*url reference */ );
  316 
  317     return size;
  318 };
  319 
  320 static int urlout(void)
  321 {
  322     int size = 0;
  323 
  324     size += u32out(1);
  325 
  326     return size;
  327 };
  328 
  329 static int stsdout(void)
  330 {
  331     int size = 0;
  332 
  333     // version/flags
  334     size += u32out(0);
  335     // Number of entries(one 'mp4a')
  336     size += u32out(1);
  337 
  338     return size;
  339 };
  340 
  341 static int mp4aout(void)
  342 {
  343     int size = 0;
  344     // Reserved (6 bytes)
  345     size += u32out(0);
  346     size += u16out(0);
  347     // Data reference index
  348     size += u16out(1);
  349     // Version
  350     size += u16out(0);
  351     // Revision level
  352     size += u16out(0);
  353     // Vendor
  354     size += u32out(0);
  355     // Number of channels
  356     size += u16out(mp4config.channels);
  357     // Sample size (bits)
  358     size += u16out(mp4config.bits);
  359     // Compression ID
  360     size += u16out(0);
  361     // Packet size
  362     size += u16out(0);
  363     // Sample rate (16.16)
  364     // rate integer part
  365     size += u16out(mp4config.samplerate);
  366     // rate reminder part
  367     size += u16out(0);
  368 
  369     return size;
  370 }
  371 
  372 static int esdsout(void)
  373 {
  374     int size = 0;
  375     // descriptor definitions:
  376     // systems/mp4_file_format/libisomediafile/src/MP4Descriptors.h
  377     // systems/mp4_file_format/libisomediafile/src/MP4Descriptors.c
  378     //
  379     // descriptor tree:
  380     // MP4ES_Descriptor
  381     //   MP4DecoderConfigDescriptor
  382     //      MP4DecSpecificInfoDescriptor
  383     //   MP4SLConfigDescriptor
  384     struct
  385     {
  386         int es;
  387         int dc;                 // DecoderConfig
  388         int dsi;                // DecSpecificInfo
  389         int sl;                 // SLConfig
  390     } dsize;
  391 
  392     enum
  393     { TAG_ES = 3, TAG_DC = 4, TAG_DSI = 5, TAG_SLC = 6 };
  394 
  395     // calc sizes
  396 #define DESCSIZE(x) (x + 5/*.tag+.size*/)
  397     dsize.sl = 1;
  398     dsize.dsi = mp4config.asc.size;
  399     dsize.dc = 13 + DESCSIZE(dsize.dsi);
  400     dsize.es = 3 + DESCSIZE(dsize.dc) + DESCSIZE(dsize.sl);
  401 
  402     // output esds atom data
  403     // version/flags ?
  404     size += u32out(0);
  405     // mp4es
  406     size += u8out(TAG_ES);
  407     size += u8out(0x80);
  408     size += u8out(0x80);
  409     size += u8out(0x80);
  410     size += u8out(dsize.es);
  411     // ESID
  412     size += u16out(0);
  413     // flags(url(bit 6); ocr(5); streamPriority (0-4)):
  414     size += u8out(0);
  415 
  416     size += u8out(TAG_DC);
  417     size += u8out(0x80);
  418     size += u8out(0x80);
  419     size += u8out(0x80);
  420     size += u8out(dsize.dc);
  421     size += u8out(0x40 /*MPEG-4 audio */ );
  422     size += u8out((5 << 2) /* AudioStream */ | 1 /* reserved = 1 */);
  423     // decode buffer size bytes
  424 #if 0
  425     size += u16out(mp4config.buffersize >> 8);
  426     size += u8out(mp4config.buffersize && 0xff);
  427 #else
  428     size += u8out(0);
  429     size += u8out(0x18);
  430     size += u8out(0);
  431 #endif
  432     // bitrate
  433     size += u32out(mp4config.bitrate.max);
  434     size += u32out(mp4config.bitrate.avg);
  435 
  436     size += u8out(TAG_DSI);
  437     size += u8out(0x80);
  438     size += u8out(0x80);
  439     size += u8out(0x80);
  440     size += u8out(dsize.dsi);
  441     // AudioSpecificConfig
  442     size += dataout(mp4config.asc.data, mp4config.asc.size);
  443 
  444     size += u8out(TAG_SLC);
  445     size += u8out(0x80);
  446     size += u8out(0x80);
  447     size += u8out(0x80);
  448     size += u8out(dsize.sl);
  449     // "predefined" (no idea)
  450     size += u8out(2);
  451 
  452     return size;
  453 }
  454 
  455 static int sttsout(void)
  456 {
  457     int size = 0;
  458 
  459     // version/flags
  460     size += u32out(0);
  461     // Number of entries
  462     size += u32out(1);
  463     // only one entry
  464     // Sample count (number of frames)
  465     size += u32out(mp4config.frame.ents);
  466     // Sample duration (samples per frame)
  467     size += u32out(mp4config.framesamples);
  468 
  469     return size;
  470 }
  471 
  472 static int stszout(void)
  473 {
  474     int size = 0;
  475     int cnt;
  476 
  477     // version/flags
  478     size += u32out(0);
  479     // Sample size
  480     size += u32out(0 /*i.e. variable size */ );
  481     // Number of entries
  482     if (!mp4config.frame.ents)
  483         return size;
  484     if (!mp4config.frame.data)
  485         return size;
  486 
  487     size += u32out(mp4config.frame.ents);
  488     for (cnt = 0; cnt < mp4config.frame.ents; cnt++)
  489         size += u32out(mp4config.frame.data[cnt]);
  490 
  491     return size;
  492 }
  493 
  494 static int stscout(void)
  495 {
  496     int size = 0;
  497 
  498     // version/flags
  499     size += u32out(0);
  500     // Number of entries
  501     size += u32out(1);
  502     // first chunk
  503     size += u32out(1);
  504     // frames in chunk
  505     size += u32out(mp4config.frame.ents);
  506     // sample id
  507     size += u32out(1);
  508 
  509     return size;
  510 }
  511 
  512 static int stcoout(void)
  513 {
  514     int size = 0;
  515 
  516     // version/flags
  517     size += u32out(0);
  518     // Number of entries
  519     size += u32out(1);
  520     // Chunk offset table
  521     size += u32out(mp4config.mdatofs);
  522 
  523     return size;
  524 }
  525 
  526 static int tagtxt(char *tagname, const char *tagtxt)
  527 {
  528     int txtsize = strlen(tagtxt);
  529     int size = 0;
  530     int datasize = txtsize + 16;
  531 
  532     size += u32out(datasize + 8);
  533     size += dataout(tagname, 4);
  534     size += u32out(datasize);
  535     size += dataout("data", 4);
  536     size += u32out(1); // data type text
  537     size += u32out(0);
  538     size += dataout(tagtxt, txtsize);
  539 
  540     return size;
  541 }
  542 
  543 static int tagu16(char *tagname, int n /*number of stored fields*/)
  544 {
  545     int numsize = n * 2;
  546     int size = 0;
  547     int datasize = numsize + 16;
  548 
  549     size += u32out(datasize + 8);
  550     size += dataout(tagname, 4);
  551     size += u32out(datasize);
  552     size += dataout("data", 4);
  553     size += u32out(0); // data type uint16
  554     size += u32out(0);
  555 
  556     return size;
  557 }
  558 
  559 static int tagu8(char *tagname, int n /*number of stored fields*/)
  560 {
  561     int numsize = n * 1;
  562     int size = 0;
  563     int datasize = numsize + 16;
  564 
  565     size += u32out(datasize + 8);
  566     size += dataout(tagname, 4);
  567     size += u32out(datasize);
  568     size += dataout("data", 4);
  569     size += u32out(0x15); // data type uint8
  570     size += u32out(0);
  571 
  572     return size;
  573 }
  574 
  575 static int tagimage(char *tagname, int n /*image size*/)
  576 {
  577     int numsize = n;
  578     int size = 0;
  579     int datasize = numsize + 16;
  580 
  581     size += u32out(datasize + 8);
  582     size += dataout(tagname, 4);
  583     size += u32out(datasize);
  584     size += dataout("data", 4);
  585     size += u32out(0x0d); // data type: image
  586     size += u32out(0);
  587 
  588     return size;
  589 }
  590 
  591 static int metaout(void)
  592 {
  593     int size = 0;
  594 
  595     // version/flags
  596     size += u32out(0);
  597 
  598     return size;
  599 }
  600 
  601 static int hdlr2out(void)
  602 {
  603     int size = 0;
  604 
  605     // version/flags
  606     size += u32out(0);
  607     // Predefined
  608     size += u32out(0);
  609     // Handler type
  610     size += stringout("mdir");
  611     size += stringout("appl");
  612     // Reserved
  613     size += u32out(0);
  614     size += u32out(0);
  615     // null terminator
  616     size += u8out(0);
  617 
  618     return size;
  619 };
  620 
  621 static int ilstout(void)
  622 {
  623     int size = 0;
  624     int cnt;
  625 
  626     size += tagtxt("\xa9" "too", mp4config.tag.encoder);
  627     if (mp4config.tag.artist)
  628         size += tagtxt("\xa9" "ART", mp4config.tag.artist);
  629     if (mp4config.tag.composer)
  630         size += tagtxt("\xa9" "wrt", mp4config.tag.composer);
  631     if (mp4config.tag.title)
  632         size += tagtxt("\xa9" "nam", mp4config.tag.title);
  633     if (mp4config.tag.genre)
  634     {
  635         size += tagu16("gnre", 1);
  636         size += u16out(mp4config.tag.genre);
  637     }
  638     if (mp4config.tag.album)
  639         size += tagtxt("\xa9" "alb", mp4config.tag.album);
  640     if (mp4config.tag.compilation)
  641     {
  642         size += tagu8("cpil", 1);
  643         size += u8out(mp4config.tag.compilation);
  644     }
  645     if (mp4config.tag.trackno)
  646     {
  647         size += tagu16("trkn", 4);
  648         size += u16out(0);
  649         size += u16out(mp4config.tag.trackno);
  650         size += u16out(mp4config.tag.ntracks);
  651         size += u16out(0);
  652     }
  653     if (mp4config.tag.discno)
  654     {
  655         size += tagu16("disk", 4);
  656         size += u16out(0);
  657         size += u16out(mp4config.tag.discno);
  658         size += u16out(mp4config.tag.ndiscs);
  659         size += u16out(0);
  660     }
  661     if (mp4config.tag.year)
  662         size += tagtxt("\xa9" "day", mp4config.tag.year);
  663     if (mp4config.tag.cover.data)
  664     {
  665         size += tagimage("covr", mp4config.tag.cover.size);
  666         size += dataout(mp4config.tag.cover.data, mp4config.tag.cover.size);
  667     }
  668     if (mp4config.tag.comment)
  669         size += tagtxt("\xa9" "cmt", mp4config.tag.comment);
  670 
  671     // ----(mean(com.apple.iTunes),name(name),data(data))
  672     for (cnt = 0; cnt < mp4config.tag.extnum; cnt++)
  673     {
  674         static const char *mean = "faac";//"com.apple.iTunes";
  675         const char *name = mp4config.tag.ext[cnt].name;
  676         const char *data = mp4config.tag.ext[cnt].data;
  677         uint32_t len1 = 8 + strlen(mean) + 4;
  678         uint32_t len2 = 8 + strlen(name) + 4;
  679         uint32_t len3 = 8 + strlen(data) + 4 + 4;
  680         u32out(8 + len1 + len2 + len3);
  681         size += 8 + len1 + len2 + len3;
  682         stringout("----");
  683         u32out(len1);
  684         stringout("mean");
  685         u32out(0);
  686         stringout(mean);
  687         u32out(len2);
  688         stringout("name");
  689         u32out(0);
  690         stringout(name);
  691         u32out(len3);
  692         stringout("data");
  693         u32out(1);
  694         u32out(0);
  695         stringout(data);
  696     }
  697 
  698     return size;
  699 };
  700 
  701 static creator_t g_head[] = {
  702     {ATOM_NAME, "ftyp"},
  703     {ATOM_DATA, ftypout},
  704     {ATOM_NAME, "free"},
  705     {ATOM_NAME, "mdat"},
  706     {0}
  707 };
  708 
  709 static creator_t g_tail[] = {
  710     {ATOM_NAME, "moov"},
  711     {ATOM_DESCENT},
  712     {ATOM_NAME, "mvhd"},
  713     {ATOM_DATA, mvhdout},
  714     {ATOM_NAME, "trak"},
  715     {ATOM_DESCENT},
  716     {ATOM_NAME, "tkhd"},
  717     {ATOM_DATA, tkhdout},
  718     {ATOM_NAME, "mdia"},
  719     {ATOM_DESCENT},
  720     {ATOM_NAME, "mdhd"},
  721     {ATOM_DATA, mdhdout},
  722     {ATOM_NAME, "hdlr"},
  723     {ATOM_DATA, hdlr1out},
  724     {ATOM_NAME, "minf"},
  725     {ATOM_DESCENT},
  726     {ATOM_NAME, "smhd"},
  727     {ATOM_DATA, smhdout},
  728     {ATOM_NAME, "dinf"},
  729     {ATOM_DESCENT},
  730     {ATOM_NAME, "dref"},
  731     {ATOM_DATA, drefout},
  732     {ATOM_DESCENT},
  733     {ATOM_NAME, "url "},
  734     {ATOM_DATA, urlout},
  735     {ATOM_ASCENT},
  736     {ATOM_ASCENT},
  737     {ATOM_NAME, "stbl"},
  738     {ATOM_DESCENT},
  739     {ATOM_NAME, "stsd"},
  740     {ATOM_DATA, stsdout},
  741     {ATOM_DESCENT},
  742     {ATOM_NAME, "mp4a"},
  743     {ATOM_DATA, mp4aout},
  744     {ATOM_DESCENT},
  745     {ATOM_NAME, "esds"},
  746     {ATOM_DATA, esdsout},
  747     {ATOM_ASCENT},
  748     {ATOM_ASCENT},
  749     {ATOM_NAME, "stts"},
  750     {ATOM_DATA, sttsout},
  751     {ATOM_NAME, "stsc"},
  752     {ATOM_DATA, stscout},
  753     {ATOM_NAME, "stsz"},
  754     {ATOM_DATA, stszout},
  755     {ATOM_NAME, "stco"},
  756     {ATOM_DATA, stcoout},
  757     {ATOM_ASCENT},
  758     {ATOM_ASCENT},
  759     {ATOM_ASCENT},
  760     {ATOM_ASCENT},
  761     {ATOM_NAME, "udta"},
  762     {ATOM_DESCENT},
  763     {ATOM_NAME, "meta"},
  764     {ATOM_DATA, metaout},
  765     {ATOM_DESCENT},
  766     {ATOM_NAME, "hdlr"},
  767     {ATOM_DATA, hdlr2out},
  768     {ATOM_NAME, "ilst"},
  769     {ATOM_DATA, ilstout},
  770     {0}
  771 };
  772 
  773 static creator_t *g_atom = 0;
  774 static int create(void)
  775 {
  776     long apos = ftell(g_fout);;
  777     int size;
  778 
  779     size = u32out(8);
  780     size += dataout(g_atom->data, 4);
  781 
  782     g_atom++;
  783     if (g_atom->opcode == ATOM_DATA)
  784     {
  785         size += ((int (*)(void)) g_atom->data) ();
  786         g_atom++;
  787     }
  788     if (g_atom->opcode == ATOM_DESCENT)
  789     {
  790         g_atom++;
  791         while (g_atom->opcode != ATOM_STOP)
  792         {
  793             if (g_atom->opcode == ATOM_ASCENT)
  794             {
  795                 g_atom++;
  796                 break;
  797             }
  798             size += create();
  799         }
  800     }
  801 
  802     fseek(g_fout, apos, SEEK_SET);
  803     u32out(size);
  804     fseek(g_fout, apos + size, SEEK_SET);
  805 
  806     return size;
  807 }
  808 
  809 enum {BUFSTEP = 0x4000};
  810 int mp4atom_frame(uint8_t * buf, int size, int samples)
  811 {
  812     if (mp4config.framesamples <= samples)
  813     {
  814         int bitrate;
  815 
  816         mp4config.bitrate.samples += samples;
  817         mp4config.bitrate.size += size;
  818 
  819         if (mp4config.bitrate.samples >= mp4config.samplerate)
  820         {
  821             bitrate = 8.0 * mp4config.bitrate.size * mp4config.samplerate
  822                 / mp4config.bitrate.samples;
  823             mp4config.bitrate.size = 0;
  824             mp4config.bitrate.samples = 0;
  825 
  826             if (mp4config.bitrate.max < bitrate)
  827                 mp4config.bitrate.max = bitrate;
  828         }
  829         mp4config.framesamples = samples;
  830     }
  831     if (mp4config.buffersize < size)
  832         mp4config.buffersize = size;
  833     mp4config.samples += samples;
  834     mp4config.mdatsize += dataout(buf, size);
  835 
  836     if (((mp4config.frame.ents + 1) * sizeof(*(mp4config.frame.data)))
  837         > mp4config.frame.bufsize)
  838     {
  839         mp4config.frame.bufsize += BUFSTEP;
  840         mp4config.frame.data = realloc(mp4config.frame.data,
  841                                        mp4config.frame.bufsize);
  842     }
  843     mp4config.frame.data[mp4config.frame.ents++] = size;
  844 
  845     return 0;
  846 }
  847 
  848 int mp4atom_close(void)
  849 {
  850     if (g_fout)
  851     {
  852         fseek(g_fout, mp4config.mdatofs - 8, SEEK_SET);
  853         u32out(mp4config.mdatsize + 8);
  854         fclose(g_fout);
  855         g_fout = 0;
  856     }
  857     if (mp4config.frame.data)
  858     {
  859         free(mp4config.frame.data);
  860         mp4config.frame.data = 0;
  861     }
  862     return 0;
  863 }
  864 
  865 int mp4atom_open(char *name, int over)
  866 {
  867     mp4atom_close();
  868 
  869     if (!access(name, W_OK) && !over)
  870     {
  871         fprintf(stderr, "output file exists, use --overwrite option\n");
  872         return 1;
  873     }
  874     if (!(g_fout = fopen(name, "wb")))
  875     {
  876         perror(name);
  877         return 1;
  878     }
  879 
  880     mp4config.mdatsize = 0;
  881     mp4config.frame.bufsize = BUFSTEP;
  882     mp4config.frame.data = malloc(mp4config.frame.bufsize);
  883 
  884     return 0;
  885 }
  886 
  887 
  888 int mp4atom_head(void)
  889 {
  890     g_atom = g_head;
  891     while (g_atom->opcode != ATOM_STOP)
  892         create();
  893     mp4config.mdatofs = ftell(g_fout);
  894 
  895     return 0;
  896 }
  897 
  898 int mp4atom_tail(void)
  899 {
  900     mp4config.bitrate.avg = 8.0 * mp4config.mdatsize
  901         * mp4config.samplerate / mp4config.samples;
  902     if (!mp4config.bitrate.max)
  903         mp4config.bitrate.max = mp4config.bitrate.avg;
  904 
  905     g_atom = g_tail;
  906     while (g_atom->opcode != ATOM_STOP)
  907         create();
  908 
  909     return 0;
  910 }
  911 
  912 int mp4tag_add(const char *name, const char *data)
  913 {
  914     int idx = mp4config.tag.extnum;
  915 
  916     if (idx >= TAGMAX)
  917     {
  918         fprintf(stderr, "To many tags\n");
  919         return -1;
  920     }
  921 
  922     mp4config.tag.ext[idx].name = name;
  923     mp4config.tag.ext[idx].data = data;
  924     mp4config.tag.extnum++;
  925 
  926     return 0;
  927 }