• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/movenc.c

Go to the documentation of this file.
00001 /*
00002  * MOV, 3GP, MP4 muxer
00003  * Copyright (c) 2003 Thomas Raivio
00004  * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
00005  * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
00006  *
00007  * This file is part of FFmpeg.
00008  *
00009  * FFmpeg is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  * FFmpeg is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with FFmpeg; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00022  */
00023 
00024 #include "movenc.h"
00025 #include "avformat.h"
00026 #include "riff.h"
00027 #include "avio.h"
00028 #include "isom.h"
00029 #include "avc.h"
00030 #include "libavcodec/get_bits.h"
00031 #include "libavcodec/put_bits.h"
00032 #include "internal.h"
00033 #include "libavutil/avstring.h"
00034 
00035 #undef NDEBUG
00036 #include <assert.h>
00037 
00038 //FIXME support 64 bit variant with wide placeholders
00039 static int64_t updateSize(ByteIOContext *pb, int64_t pos)
00040 {
00041     int64_t curpos = url_ftell(pb);
00042     url_fseek(pb, pos, SEEK_SET);
00043     put_be32(pb, curpos - pos); /* rewrite size */
00044     url_fseek(pb, curpos, SEEK_SET);
00045 
00046     return curpos - pos;
00047 }
00048 
00049 /* Chunk offset atom */
00050 static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack *track)
00051 {
00052     int i;
00053     int mode64 = 0; //   use 32 bit size variant if possible
00054     int64_t pos = url_ftell(pb);
00055     put_be32(pb, 0); /* size */
00056     if (pos > UINT32_MAX) {
00057         mode64 = 1;
00058         put_tag(pb, "co64");
00059     } else
00060         put_tag(pb, "stco");
00061     put_be32(pb, 0); /* version & flags */
00062     put_be32(pb, track->entry); /* entry count */
00063     for (i=0; i<track->entry; i++) {
00064         if(mode64 == 1)
00065             put_be64(pb, track->cluster[i].pos);
00066         else
00067             put_be32(pb, track->cluster[i].pos);
00068     }
00069     return updateSize(pb, pos);
00070 }
00071 
00072 /* Sample size atom */
00073 static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack *track)
00074 {
00075     int equalChunks = 1;
00076     int i, j, entries = 0, tst = -1, oldtst = -1;
00077 
00078     int64_t pos = url_ftell(pb);
00079     put_be32(pb, 0); /* size */
00080     put_tag(pb, "stsz");
00081     put_be32(pb, 0); /* version & flags */
00082 
00083     for (i=0; i<track->entry; i++) {
00084         tst = track->cluster[i].size/track->cluster[i].entries;
00085         if(oldtst != -1 && tst != oldtst) {
00086             equalChunks = 0;
00087         }
00088         oldtst = tst;
00089         entries += track->cluster[i].entries;
00090     }
00091     if (equalChunks) {
00092         int sSize = track->cluster[0].size/track->cluster[0].entries;
00093         put_be32(pb, sSize); // sample size
00094         put_be32(pb, entries); // sample count
00095     }
00096     else {
00097         put_be32(pb, 0); // sample size
00098         put_be32(pb, entries); // sample count
00099         for (i=0; i<track->entry; i++) {
00100             for (j=0; j<track->cluster[i].entries; j++) {
00101                 put_be32(pb, track->cluster[i].size /
00102                          track->cluster[i].entries);
00103             }
00104         }
00105     }
00106     return updateSize(pb, pos);
00107 }
00108 
00109 /* Sample to chunk atom */
00110 static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack *track)
00111 {
00112     int index = 0, oldval = -1, i;
00113     int64_t entryPos, curpos;
00114 
00115     int64_t pos = url_ftell(pb);
00116     put_be32(pb, 0); /* size */
00117     put_tag(pb, "stsc");
00118     put_be32(pb, 0); // version & flags
00119     entryPos = url_ftell(pb);
00120     put_be32(pb, track->entry); // entry count
00121     for (i=0; i<track->entry; i++) {
00122         if(oldval != track->cluster[i].samplesInChunk)
00123         {
00124             put_be32(pb, i+1); // first chunk
00125             put_be32(pb, track->cluster[i].samplesInChunk); // samples per chunk
00126             put_be32(pb, 0x1); // sample description index
00127             oldval = track->cluster[i].samplesInChunk;
00128             index++;
00129         }
00130     }
00131     curpos = url_ftell(pb);
00132     url_fseek(pb, entryPos, SEEK_SET);
00133     put_be32(pb, index); // rewrite size
00134     url_fseek(pb, curpos, SEEK_SET);
00135 
00136     return updateSize(pb, pos);
00137 }
00138 
00139 /* Sync sample atom */
00140 static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack *track, uint32_t flag)
00141 {
00142     int64_t curpos, entryPos;
00143     int i, index = 0;
00144     int64_t pos = url_ftell(pb);
00145     put_be32(pb, 0); // size
00146     put_tag(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
00147     put_be32(pb, 0); // version & flags
00148     entryPos = url_ftell(pb);
00149     put_be32(pb, track->entry); // entry count
00150     for (i=0; i<track->entry; i++) {
00151         if (track->cluster[i].flags & flag) {
00152             put_be32(pb, i+1);
00153             index++;
00154         }
00155     }
00156     curpos = url_ftell(pb);
00157     url_fseek(pb, entryPos, SEEK_SET);
00158     put_be32(pb, index); // rewrite size
00159     url_fseek(pb, curpos, SEEK_SET);
00160     return updateSize(pb, pos);
00161 }
00162 
00163 static int mov_write_amr_tag(ByteIOContext *pb, MOVTrack *track)
00164 {
00165     put_be32(pb, 0x11); /* size */
00166     if (track->mode == MODE_MOV) put_tag(pb, "samr");
00167     else                         put_tag(pb, "damr");
00168     put_tag(pb, "FFMP");
00169     put_byte(pb, 0); /* decoder version */
00170 
00171     put_be16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
00172     put_byte(pb, 0x00); /* Mode change period (no restriction) */
00173     put_byte(pb, 0x01); /* Frames per sample */
00174     return 0x11;
00175 }
00176 
00177 static int mov_write_ac3_tag(ByteIOContext *pb, MOVTrack *track)
00178 {
00179     GetBitContext gbc;
00180     PutBitContext pbc;
00181     uint8_t buf[3];
00182     int fscod, bsid, bsmod, acmod, lfeon, frmsizecod;
00183 
00184     if (track->vosLen < 7)
00185         return -1;
00186 
00187     put_be32(pb, 11);
00188     put_tag(pb, "dac3");
00189 
00190     init_get_bits(&gbc, track->vosData+4, track->vosLen-4);
00191     fscod      = get_bits(&gbc, 2);
00192     frmsizecod = get_bits(&gbc, 6);
00193     bsid       = get_bits(&gbc, 5);
00194     bsmod      = get_bits(&gbc, 3);
00195     acmod      = get_bits(&gbc, 3);
00196     if (acmod == 2) {
00197         skip_bits(&gbc, 2); // dsurmod
00198     } else {
00199         if ((acmod & 1) && acmod != 1)
00200             skip_bits(&gbc, 2); // cmixlev
00201         if (acmod & 4)
00202             skip_bits(&gbc, 2); // surmixlev
00203     }
00204     lfeon = get_bits1(&gbc);
00205 
00206     init_put_bits(&pbc, buf, sizeof(buf));
00207     put_bits(&pbc, 2, fscod);
00208     put_bits(&pbc, 5, bsid);
00209     put_bits(&pbc, 3, bsmod);
00210     put_bits(&pbc, 3, acmod);
00211     put_bits(&pbc, 1, lfeon);
00212     put_bits(&pbc, 5, frmsizecod>>1); // bit_rate_code
00213     put_bits(&pbc, 5, 0); // reserved
00214 
00215     flush_put_bits(&pbc);
00216     put_buffer(pb, buf, sizeof(buf));
00217 
00218     return 11;
00219 }
00220 
00225 static int mov_write_extradata_tag(ByteIOContext *pb, MOVTrack *track)
00226 {
00227     put_buffer(pb, track->enc->extradata, track->enc->extradata_size);
00228     return track->enc->extradata_size;
00229 }
00230 
00231 static int mov_write_enda_tag(ByteIOContext *pb)
00232 {
00233     put_be32(pb, 10);
00234     put_tag(pb, "enda");
00235     put_be16(pb, 1); /* little endian */
00236     return 10;
00237 }
00238 
00239 static unsigned int descrLength(unsigned int len)
00240 {
00241     int i;
00242     for(i=1; len>>(7*i); i++);
00243     return len + 1 + i;
00244 }
00245 
00246 static void putDescr(ByteIOContext *pb, int tag, unsigned int size)
00247 {
00248     int i= descrLength(size) - size - 2;
00249     put_byte(pb, tag);
00250     for(; i>0; i--)
00251         put_byte(pb, (size>>(7*i)) | 0x80);
00252     put_byte(pb, size & 0x7F);
00253 }
00254 
00255 static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack *track) // Basic
00256 {
00257     int64_t pos = url_ftell(pb);
00258     int decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0;
00259 
00260     put_be32(pb, 0); // size
00261     put_tag(pb, "esds");
00262     put_be32(pb, 0); // Version
00263 
00264     // ES descriptor
00265     putDescr(pb, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) +
00266              descrLength(1));
00267     put_be16(pb, track->trackID);
00268     put_byte(pb, 0x00); // flags (= no flags)
00269 
00270     // DecoderConfig descriptor
00271     putDescr(pb, 0x04, 13 + decoderSpecificInfoLen);
00272 
00273     // Object type indication
00274     if ((track->enc->codec_id == CODEC_ID_MP2 ||
00275          track->enc->codec_id == CODEC_ID_MP3) &&
00276         track->enc->sample_rate > 24000)
00277         put_byte(pb, 0x6B); // 11172-3
00278     else
00279         put_byte(pb, ff_codec_get_tag(ff_mp4_obj_type, track->enc->codec_id));
00280 
00281     // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
00282     // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
00283     if(track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
00284         put_byte(pb, 0x15); // flags (= Audiostream)
00285     else
00286         put_byte(pb, 0x11); // flags (= Visualstream)
00287 
00288     put_byte(pb,  track->enc->rc_buffer_size>>(3+16));    // Buffersize DB (24 bits)
00289     put_be16(pb, (track->enc->rc_buffer_size>>3)&0xFFFF); // Buffersize DB
00290 
00291     put_be32(pb, FFMAX(track->enc->bit_rate, track->enc->rc_max_rate)); // maxbitrate (FIXME should be max rate in any 1 sec window)
00292     if(track->enc->rc_max_rate != track->enc->rc_min_rate || track->enc->rc_min_rate==0)
00293         put_be32(pb, 0); // vbr
00294     else
00295         put_be32(pb, track->enc->rc_max_rate); // avg bitrate
00296 
00297     if (track->vosLen) {
00298         // DecoderSpecific info descriptor
00299         putDescr(pb, 0x05, track->vosLen);
00300         put_buffer(pb, track->vosData, track->vosLen);
00301     }
00302 
00303     // SL descriptor
00304     putDescr(pb, 0x06, 1);
00305     put_byte(pb, 0x02);
00306     return updateSize(pb, pos);
00307 }
00308 
00309 static int mov_pcm_le_gt16(enum CodecID codec_id)
00310 {
00311     return codec_id == CODEC_ID_PCM_S24LE ||
00312            codec_id == CODEC_ID_PCM_S32LE ||
00313            codec_id == CODEC_ID_PCM_F32LE ||
00314            codec_id == CODEC_ID_PCM_F64LE;
00315 }
00316 
00317 static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack *track)
00318 {
00319     int64_t pos = url_ftell(pb);
00320 
00321     put_be32(pb, 0);     /* size */
00322     put_tag(pb, "wave");
00323 
00324     put_be32(pb, 12);    /* size */
00325     put_tag(pb, "frma");
00326     put_le32(pb, track->tag);
00327 
00328     if (track->enc->codec_id == CODEC_ID_AAC) {
00329         /* useless atom needed by mplayer, ipod, not needed by quicktime */
00330         put_be32(pb, 12); /* size */
00331         put_tag(pb, "mp4a");
00332         put_be32(pb, 0);
00333         mov_write_esds_tag(pb, track);
00334     } else if (mov_pcm_le_gt16(track->enc->codec_id)) {
00335         mov_write_enda_tag(pb);
00336     } else if (track->enc->codec_id == CODEC_ID_AMR_NB) {
00337         mov_write_amr_tag(pb, track);
00338     } else if (track->enc->codec_id == CODEC_ID_AC3) {
00339         mov_write_ac3_tag(pb, track);
00340     } else if (track->enc->codec_id == CODEC_ID_ALAC) {
00341         mov_write_extradata_tag(pb, track);
00342     }
00343 
00344     put_be32(pb, 8);     /* size */
00345     put_be32(pb, 0);     /* null tag */
00346 
00347     return updateSize(pb, pos);
00348 }
00349 
00350 static int mov_write_glbl_tag(ByteIOContext *pb, MOVTrack *track)
00351 {
00352     put_be32(pb, track->vosLen+8);
00353     put_tag(pb, "glbl");
00354     put_buffer(pb, track->vosData, track->vosLen);
00355     return 8+track->vosLen;
00356 }
00357 
00362 static int mov_get_lpcm_flags(enum CodecID codec_id)
00363 {
00364     switch (codec_id) {
00365     case CODEC_ID_PCM_F32BE:
00366     case CODEC_ID_PCM_F64BE:
00367         return 11;
00368     case CODEC_ID_PCM_F32LE:
00369     case CODEC_ID_PCM_F64LE:
00370         return 9;
00371     case CODEC_ID_PCM_U8:
00372         return 10;
00373     case CODEC_ID_PCM_S16BE:
00374     case CODEC_ID_PCM_S24BE:
00375     case CODEC_ID_PCM_S32BE:
00376         return 14;
00377     case CODEC_ID_PCM_S8:
00378     case CODEC_ID_PCM_S16LE:
00379     case CODEC_ID_PCM_S24LE:
00380     case CODEC_ID_PCM_S32LE:
00381         return 12;
00382     default:
00383         return 0;
00384     }
00385 }
00386 
00387 static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack *track)
00388 {
00389     int64_t pos = url_ftell(pb);
00390     int version = 0;
00391     uint32_t tag = track->tag;
00392 
00393     if (track->mode == MODE_MOV) {
00394         if (track->timescale > UINT16_MAX) {
00395             if (mov_get_lpcm_flags(track->enc->codec_id))
00396                 tag = AV_RL32("lpcm");
00397             version = 2;
00398         } else if (track->audio_vbr || mov_pcm_le_gt16(track->enc->codec_id)) {
00399             version = 1;
00400         }
00401     }
00402 
00403     put_be32(pb, 0); /* size */
00404     put_le32(pb, tag); // store it byteswapped
00405     put_be32(pb, 0); /* Reserved */
00406     put_be16(pb, 0); /* Reserved */
00407     put_be16(pb, 1); /* Data-reference index, XXX  == 1 */
00408 
00409     /* SoundDescription */
00410     put_be16(pb, version); /* Version */
00411     put_be16(pb, 0); /* Revision level */
00412     put_be32(pb, 0); /* Reserved */
00413 
00414     if (version == 2) {
00415         put_be16(pb, 3);
00416         put_be16(pb, 16);
00417         put_be16(pb, 0xfffe);
00418         put_be16(pb, 0);
00419         put_be32(pb, 0x00010000);
00420         put_be32(pb, 72);
00421         put_be64(pb, av_dbl2int(track->timescale));
00422         put_be32(pb, track->enc->channels);
00423         put_be32(pb, 0x7F000000);
00424         put_be32(pb, av_get_bits_per_sample(track->enc->codec_id));
00425         put_be32(pb, mov_get_lpcm_flags(track->enc->codec_id));
00426         put_be32(pb, track->sampleSize);
00427         put_be32(pb, track->enc->frame_size);
00428     } else {
00429         if (track->mode == MODE_MOV) {
00430             put_be16(pb, track->enc->channels);
00431             if (track->enc->codec_id == CODEC_ID_PCM_U8 ||
00432                 track->enc->codec_id == CODEC_ID_PCM_S8)
00433                 put_be16(pb, 8); /* bits per sample */
00434             else
00435                 put_be16(pb, 16);
00436             put_be16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
00437         } else { /* reserved for mp4/3gp */
00438             put_be16(pb, 2);
00439             put_be16(pb, 16);
00440             put_be16(pb, 0);
00441         }
00442 
00443         put_be16(pb, 0); /* packet size (= 0) */
00444         put_be16(pb, track->timescale); /* Time scale */
00445         put_be16(pb, 0); /* Reserved */
00446     }
00447 
00448     if(version == 1) { /* SoundDescription V1 extended info */
00449         put_be32(pb, track->enc->frame_size); /* Samples per packet */
00450         put_be32(pb, track->sampleSize / track->enc->channels); /* Bytes per packet */
00451         put_be32(pb, track->sampleSize); /* Bytes per frame */
00452         put_be32(pb, 2); /* Bytes per sample */
00453     }
00454 
00455     if(track->mode == MODE_MOV &&
00456        (track->enc->codec_id == CODEC_ID_AAC ||
00457         track->enc->codec_id == CODEC_ID_AC3 ||
00458         track->enc->codec_id == CODEC_ID_AMR_NB ||
00459         track->enc->codec_id == CODEC_ID_ALAC ||
00460         mov_pcm_le_gt16(track->enc->codec_id)))
00461         mov_write_wave_tag(pb, track);
00462     else if(track->tag == MKTAG('m','p','4','a'))
00463         mov_write_esds_tag(pb, track);
00464     else if(track->enc->codec_id == CODEC_ID_AMR_NB)
00465         mov_write_amr_tag(pb, track);
00466     else if(track->enc->codec_id == CODEC_ID_AC3)
00467         mov_write_ac3_tag(pb, track);
00468     else if(track->enc->codec_id == CODEC_ID_ALAC)
00469         mov_write_extradata_tag(pb, track);
00470     else if(track->vosLen > 0)
00471         mov_write_glbl_tag(pb, track);
00472 
00473     return updateSize(pb, pos);
00474 }
00475 
00476 static int mov_write_d263_tag(ByteIOContext *pb)
00477 {
00478     put_be32(pb, 0xf); /* size */
00479     put_tag(pb, "d263");
00480     put_tag(pb, "FFMP");
00481     put_byte(pb, 0); /* decoder version */
00482     /* FIXME use AVCodecContext level/profile, when encoder will set values */
00483     put_byte(pb, 0xa); /* level */
00484     put_byte(pb, 0); /* profile */
00485     return 0xf;
00486 }
00487 
00488 /* TODO: No idea about these values */
00489 static int mov_write_svq3_tag(ByteIOContext *pb)
00490 {
00491     put_be32(pb, 0x15);
00492     put_tag(pb, "SMI ");
00493     put_tag(pb, "SEQH");
00494     put_be32(pb, 0x5);
00495     put_be32(pb, 0xe2c0211d);
00496     put_be32(pb, 0xc0000000);
00497     put_byte(pb, 0);
00498     return 0x15;
00499 }
00500 
00501 static int mov_write_avcc_tag(ByteIOContext *pb, MOVTrack *track)
00502 {
00503     int64_t pos = url_ftell(pb);
00504 
00505     put_be32(pb, 0);
00506     put_tag(pb, "avcC");
00507     ff_isom_write_avcc(pb, track->vosData, track->vosLen);
00508     return updateSize(pb, pos);
00509 }
00510 
00511 /* also used by all avid codecs (dv, imx, meridien) and their variants */
00512 static int mov_write_avid_tag(ByteIOContext *pb, MOVTrack *track)
00513 {
00514     int i;
00515     put_be32(pb, 24); /* size */
00516     put_tag(pb, "ACLR");
00517     put_tag(pb, "ACLR");
00518     put_tag(pb, "0001");
00519     put_be32(pb, 1); /* yuv 1 / rgb 2 ? */
00520     put_be32(pb, 0); /* unknown */
00521 
00522     put_be32(pb, 24); /* size */
00523     put_tag(pb, "APRG");
00524     put_tag(pb, "APRG");
00525     put_tag(pb, "0001");
00526     put_be32(pb, 1); /* unknown */
00527     put_be32(pb, 0); /* unknown */
00528 
00529     put_be32(pb, 120); /* size */
00530     put_tag(pb, "ARES");
00531     put_tag(pb, "ARES");
00532     put_tag(pb, "0001");
00533     put_be32(pb, AV_RB32(track->vosData + 0x28)); /* dnxhd cid, some id ? */
00534     put_be32(pb, track->enc->width);
00535     /* values below are based on samples created with quicktime and avid codecs */
00536     if (track->vosData[5] & 2) { // interlaced
00537         put_be32(pb, track->enc->height/2);
00538         put_be32(pb, 2); /* unknown */
00539         put_be32(pb, 0); /* unknown */
00540         put_be32(pb, 4); /* unknown */
00541     } else {
00542         put_be32(pb, track->enc->height);
00543         put_be32(pb, 1); /* unknown */
00544         put_be32(pb, 0); /* unknown */
00545         if (track->enc->height == 1080)
00546             put_be32(pb, 5); /* unknown */
00547         else
00548             put_be32(pb, 6); /* unknown */
00549     }
00550     /* padding */
00551     for (i = 0; i < 10; i++)
00552         put_be64(pb, 0);
00553 
00554     /* extra padding for stsd needed */
00555     put_be32(pb, 0);
00556     return 0;
00557 }
00558 
00559 static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track)
00560 {
00561     int tag = track->enc->codec_tag;
00562 
00563     if (!ff_codec_get_tag(ff_mp4_obj_type, track->enc->codec_id))
00564         return 0;
00565 
00566     if      (track->enc->codec_id == CODEC_ID_H264)      tag = MKTAG('a','v','c','1');
00567     else if (track->enc->codec_id == CODEC_ID_AC3)       tag = MKTAG('a','c','-','3');
00568     else if (track->enc->codec_id == CODEC_ID_DIRAC)     tag = MKTAG('d','r','a','c');
00569     else if (track->enc->codec_id == CODEC_ID_MOV_TEXT)  tag = MKTAG('t','x','3','g');
00570     else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) tag = MKTAG('m','p','4','v');
00571     else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) tag = MKTAG('m','p','4','a');
00572 
00573     return tag;
00574 }
00575 
00576 static const AVCodecTag codec_ipod_tags[] = {
00577     { CODEC_ID_H264,   MKTAG('a','v','c','1') },
00578     { CODEC_ID_MPEG4,  MKTAG('m','p','4','v') },
00579     { CODEC_ID_AAC,    MKTAG('m','p','4','a') },
00580     { CODEC_ID_ALAC,   MKTAG('a','l','a','c') },
00581     { CODEC_ID_AC3,    MKTAG('a','c','-','3') },
00582     { CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
00583     { CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
00584     { CODEC_ID_NONE, 0 },
00585 };
00586 
00587 static int ipod_get_codec_tag(AVFormatContext *s, MOVTrack *track)
00588 {
00589     int tag = track->enc->codec_tag;
00590 
00591     // keep original tag for subs, ipod supports both formats
00592     if (!(track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE &&
00593         (tag == MKTAG('t','x','3','g') ||
00594          tag == MKTAG('t','e','x','t'))))
00595         tag = ff_codec_get_tag(codec_ipod_tags, track->enc->codec_id);
00596 
00597     if (!av_match_ext(s->filename, "m4a") && !av_match_ext(s->filename, "m4v"))
00598         av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
00599                "Quicktime/Ipod might not play the file\n");
00600 
00601     return tag;
00602 }
00603 
00604 static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
00605 {
00606     int tag;
00607 
00608     if (track->enc->height == 480) /* NTSC */
00609         if  (track->enc->pix_fmt == PIX_FMT_YUV422P) tag = MKTAG('d','v','5','n');
00610         else                                         tag = MKTAG('d','v','c',' ');
00611     else if (track->enc->pix_fmt == PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
00612     else if (track->enc->pix_fmt == PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
00613     else                                             tag = MKTAG('d','v','p','p');
00614 
00615     return tag;
00616 }
00617 
00618 static const struct {
00619     enum PixelFormat pix_fmt;
00620     uint32_t tag;
00621     unsigned bps;
00622 } mov_pix_fmt_tags[] = {
00623     { PIX_FMT_YUYV422, MKTAG('y','u','v','s'),  0 },
00624     { PIX_FMT_UYVY422, MKTAG('2','v','u','y'),  0 },
00625     { PIX_FMT_BGR555,  MKTAG('r','a','w',' '), 16 },
00626     { PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
00627     { PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
00628     { PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
00629     { PIX_FMT_RGB24,   MKTAG('r','a','w',' '), 24 },
00630     { PIX_FMT_BGR24,   MKTAG('2','4','B','G'), 24 },
00631     { PIX_FMT_ARGB,    MKTAG('r','a','w',' '), 32 },
00632     { PIX_FMT_BGRA,    MKTAG('B','G','R','A'), 32 },
00633     { PIX_FMT_RGBA,    MKTAG('R','G','B','A'), 32 },
00634 };
00635 
00636 static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
00637 {
00638     int tag = track->enc->codec_tag;
00639     int i;
00640 
00641     for (i = 0; i < FF_ARRAY_ELEMS(mov_pix_fmt_tags); i++) {
00642         if (track->enc->pix_fmt == mov_pix_fmt_tags[i].pix_fmt) {
00643             tag = mov_pix_fmt_tags[i].tag;
00644             track->enc->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
00645             break;
00646         }
00647     }
00648 
00649     return tag;
00650 }
00651 
00652 static int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
00653 {
00654     int tag = track->enc->codec_tag;
00655 
00656     if (!tag || (track->enc->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
00657                  (tag == MKTAG('d','v','c','p') ||
00658                   track->enc->codec_id == CODEC_ID_RAWVIDEO ||
00659                   av_get_bits_per_sample(track->enc->codec_id)))) { // pcm audio
00660         if (track->enc->codec_id == CODEC_ID_DVVIDEO)
00661             tag = mov_get_dv_codec_tag(s, track);
00662         else if (track->enc->codec_id == CODEC_ID_RAWVIDEO)
00663             tag = mov_get_rawvideo_codec_tag(s, track);
00664         else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) {
00665             tag = ff_codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
00666             if (!tag) { // if no mac fcc found, try with Microsoft tags
00667                 tag = ff_codec_get_tag(ff_codec_bmp_tags, track->enc->codec_id);
00668                 if (tag)
00669                     av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, "
00670                            "the file may be unplayable!\n");
00671             }
00672         } else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) {
00673             tag = ff_codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
00674             if (!tag) { // if no mac fcc found, try with Microsoft tags
00675                 int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->enc->codec_id);
00676                 if (ms_tag) {
00677                     tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
00678                     av_log(s, AV_LOG_INFO, "Warning, using MS style audio codec tag, "
00679                            "the file may be unplayable!\n");
00680                 }
00681             }
00682         } else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)
00683             tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->enc->codec_id);
00684     }
00685 
00686     return tag;
00687 }
00688 
00689 static const AVCodecTag codec_3gp_tags[] = {
00690     { CODEC_ID_H263,   MKTAG('s','2','6','3') },
00691     { CODEC_ID_H264,   MKTAG('a','v','c','1') },
00692     { CODEC_ID_MPEG4,  MKTAG('m','p','4','v') },
00693     { CODEC_ID_AAC,    MKTAG('m','p','4','a') },
00694     { CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
00695     { CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
00696     { CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
00697     { CODEC_ID_NONE, 0 },
00698 };
00699 
00700 static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
00701 {
00702     int tag = track->enc->codec_tag;
00703 
00704     if (track->mode == MODE_MP4 || track->mode == MODE_PSP)
00705         tag = mp4_get_codec_tag(s, track);
00706     else if (track->mode == MODE_IPOD)
00707         tag = ipod_get_codec_tag(s, track);
00708     else if (track->mode & MODE_3GP)
00709         tag = ff_codec_get_tag(codec_3gp_tags, track->enc->codec_id);
00710     else
00711         tag = mov_get_codec_tag(s, track);
00712 
00713     return tag;
00714 }
00715 
00720 static int mov_write_uuid_tag_ipod(ByteIOContext *pb)
00721 {
00722     put_be32(pb, 28);
00723     put_tag(pb, "uuid");
00724     put_be32(pb, 0x6b6840f2);
00725     put_be32(pb, 0x5f244fc5);
00726     put_be32(pb, 0xba39a51b);
00727     put_be32(pb, 0xcf0323f3);
00728     put_be32(pb, 0x0);
00729     return 28;
00730 }
00731 
00732 static int mov_write_subtitle_tag(ByteIOContext *pb, MOVTrack *track)
00733 {
00734     int64_t pos = url_ftell(pb);
00735     put_be32(pb, 0);    /* size */
00736     put_le32(pb, track->tag); // store it byteswapped
00737     put_be32(pb, 0);    /* Reserved */
00738     put_be16(pb, 0);    /* Reserved */
00739     put_be16(pb, 1);    /* Data-reference index */
00740 
00741     if (track->enc->extradata_size)
00742         put_buffer(pb, track->enc->extradata, track->enc->extradata_size);
00743 
00744     return updateSize(pb, pos);
00745 }
00746 
00747 static int mov_write_video_tag(ByteIOContext *pb, MOVTrack *track)
00748 {
00749     int64_t pos = url_ftell(pb);
00750     char compressor_name[32];
00751 
00752     put_be32(pb, 0); /* size */
00753     put_le32(pb, track->tag); // store it byteswapped
00754     put_be32(pb, 0); /* Reserved */
00755     put_be16(pb, 0); /* Reserved */
00756     put_be16(pb, 1); /* Data-reference index */
00757 
00758     put_be16(pb, 0); /* Codec stream version */
00759     put_be16(pb, 0); /* Codec stream revision (=0) */
00760     if (track->mode == MODE_MOV) {
00761         put_tag(pb, "FFMP"); /* Vendor */
00762         if(track->enc->codec_id == CODEC_ID_RAWVIDEO) {
00763             put_be32(pb, 0); /* Temporal Quality */
00764             put_be32(pb, 0x400); /* Spatial Quality = lossless*/
00765         } else {
00766             put_be32(pb, 0x200); /* Temporal Quality = normal */
00767             put_be32(pb, 0x200); /* Spatial Quality = normal */
00768         }
00769     } else {
00770         put_be32(pb, 0); /* Reserved */
00771         put_be32(pb, 0); /* Reserved */
00772         put_be32(pb, 0); /* Reserved */
00773     }
00774     put_be16(pb, track->enc->width); /* Video width */
00775     put_be16(pb, track->height); /* Video height */
00776     put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */
00777     put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */
00778     put_be32(pb, 0); /* Data size (= 0) */
00779     put_be16(pb, 1); /* Frame count (= 1) */
00780 
00781     memset(compressor_name,0,32);
00782     /* FIXME not sure, ISO 14496-1 draft where it shall be set to 0 */
00783     if (track->mode == MODE_MOV && track->enc->codec && track->enc->codec->name)
00784         strncpy(compressor_name,track->enc->codec->name,31);
00785     put_byte(pb, strlen(compressor_name));
00786     put_buffer(pb, compressor_name, 31);
00787 
00788     if (track->mode == MODE_MOV && track->enc->bits_per_coded_sample)
00789         put_be16(pb, track->enc->bits_per_coded_sample);
00790     else
00791         put_be16(pb, 0x18); /* Reserved */
00792     put_be16(pb, 0xffff); /* Reserved */
00793     if(track->tag == MKTAG('m','p','4','v'))
00794         mov_write_esds_tag(pb, track);
00795     else if(track->enc->codec_id == CODEC_ID_H263)
00796         mov_write_d263_tag(pb);
00797     else if(track->enc->codec_id == CODEC_ID_SVQ3)
00798         mov_write_svq3_tag(pb);
00799     else if(track->enc->codec_id == CODEC_ID_DNXHD)
00800         mov_write_avid_tag(pb, track);
00801     else if(track->enc->codec_id == CODEC_ID_H264) {
00802         mov_write_avcc_tag(pb, track);
00803         if(track->mode == MODE_IPOD)
00804             mov_write_uuid_tag_ipod(pb);
00805     } else if(track->vosLen > 0)
00806         mov_write_glbl_tag(pb, track);
00807 
00808     return updateSize(pb, pos);
00809 }
00810 
00811 static int mov_write_rtp_tag(ByteIOContext *pb, MOVTrack *track)
00812 {
00813     int64_t pos = url_ftell(pb);
00814     put_be32(pb, 0); /* size */
00815     put_tag(pb, "rtp ");
00816     put_be32(pb, 0); /* Reserved */
00817     put_be16(pb, 0); /* Reserved */
00818     put_be16(pb, 1); /* Data-reference index */
00819 
00820     put_be16(pb, 1); /* Hint track version */
00821     put_be16(pb, 1); /* Highest compatible version */
00822     put_be32(pb, track->max_packet_size); /* Max packet size */
00823 
00824     put_be32(pb, 12); /* size */
00825     put_tag(pb, "tims");
00826     put_be32(pb, track->timescale);
00827 
00828     return updateSize(pb, pos);
00829 }
00830 
00831 static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack *track)
00832 {
00833     int64_t pos = url_ftell(pb);
00834     put_be32(pb, 0); /* size */
00835     put_tag(pb, "stsd");
00836     put_be32(pb, 0); /* version & flags */
00837     put_be32(pb, 1); /* entry count */
00838     if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO)
00839         mov_write_video_tag(pb, track);
00840     else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
00841         mov_write_audio_tag(pb, track);
00842     else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)
00843         mov_write_subtitle_tag(pb, track);
00844     else if (track->enc->codec_tag == MKTAG('r','t','p',' '))
00845         mov_write_rtp_tag(pb, track);
00846     return updateSize(pb, pos);
00847 }
00848 
00849 static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack *track)
00850 {
00851     MOVStts *ctts_entries;
00852     uint32_t entries = 0;
00853     uint32_t atom_size;
00854     int i;
00855 
00856     ctts_entries = av_malloc((track->entry + 1) * sizeof(*ctts_entries)); /* worst case */
00857     ctts_entries[0].count = 1;
00858     ctts_entries[0].duration = track->cluster[0].cts;
00859     for (i=1; i<track->entry; i++) {
00860         if (track->cluster[i].cts == ctts_entries[entries].duration) {
00861             ctts_entries[entries].count++; /* compress */
00862         } else {
00863             entries++;
00864             ctts_entries[entries].duration = track->cluster[i].cts;
00865             ctts_entries[entries].count = 1;
00866         }
00867     }
00868     entries++; /* last one */
00869     atom_size = 16 + (entries * 8);
00870     put_be32(pb, atom_size); /* size */
00871     put_tag(pb, "ctts");
00872     put_be32(pb, 0); /* version & flags */
00873     put_be32(pb, entries); /* entry count */
00874     for (i=0; i<entries; i++) {
00875         put_be32(pb, ctts_entries[i].count);
00876         put_be32(pb, ctts_entries[i].duration);
00877     }
00878     av_free(ctts_entries);
00879     return atom_size;
00880 }
00881 
00882 /* Time to sample atom */
00883 static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack *track)
00884 {
00885     MOVStts *stts_entries;
00886     uint32_t entries = -1;
00887     uint32_t atom_size;
00888     int i;
00889 
00890     if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO && !track->audio_vbr) {
00891         stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
00892         stts_entries[0].count = track->sampleCount;
00893         stts_entries[0].duration = 1;
00894         entries = 1;
00895     } else {
00896         stts_entries = av_malloc(track->entry * sizeof(*stts_entries)); /* worst case */
00897         for (i=0; i<track->entry; i++) {
00898             int64_t duration = i + 1 == track->entry ?
00899                 track->trackDuration - track->cluster[i].dts + track->cluster[0].dts : /* readjusting */
00900                 track->cluster[i+1].dts - track->cluster[i].dts;
00901             if (i && duration == stts_entries[entries].duration) {
00902                 stts_entries[entries].count++; /* compress */
00903             } else {
00904                 entries++;
00905                 stts_entries[entries].duration = duration;
00906                 stts_entries[entries].count = 1;
00907             }
00908         }
00909         entries++; /* last one */
00910     }
00911     atom_size = 16 + (entries * 8);
00912     put_be32(pb, atom_size); /* size */
00913     put_tag(pb, "stts");
00914     put_be32(pb, 0); /* version & flags */
00915     put_be32(pb, entries); /* entry count */
00916     for (i=0; i<entries; i++) {
00917         put_be32(pb, stts_entries[i].count);
00918         put_be32(pb, stts_entries[i].duration);
00919     }
00920     av_free(stts_entries);
00921     return atom_size;
00922 }
00923 
00924 static int mov_write_dref_tag(ByteIOContext *pb)
00925 {
00926     put_be32(pb, 28); /* size */
00927     put_tag(pb, "dref");
00928     put_be32(pb, 0); /* version & flags */
00929     put_be32(pb, 1); /* entry count */
00930 
00931     put_be32(pb, 0xc); /* size */
00932     put_tag(pb, "url ");
00933     put_be32(pb, 1); /* version & flags */
00934 
00935     return 28;
00936 }
00937 
00938 static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack *track)
00939 {
00940     int64_t pos = url_ftell(pb);
00941     put_be32(pb, 0); /* size */
00942     put_tag(pb, "stbl");
00943     mov_write_stsd_tag(pb, track);
00944     mov_write_stts_tag(pb, track);
00945     if ((track->enc->codec_type == AVMEDIA_TYPE_VIDEO ||
00946          track->enc->codec_tag == MKTAG('r','t','p',' ')) &&
00947         track->hasKeyframes && track->hasKeyframes < track->entry)
00948         mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE);
00949     if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS)
00950         mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
00951     if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO &&
00952         track->flags & MOV_TRACK_CTTS)
00953         mov_write_ctts_tag(pb, track);
00954     mov_write_stsc_tag(pb, track);
00955     mov_write_stsz_tag(pb, track);
00956     mov_write_stco_tag(pb, track);
00957     return updateSize(pb, pos);
00958 }
00959 
00960 static int mov_write_dinf_tag(ByteIOContext *pb)
00961 {
00962     int64_t pos = url_ftell(pb);
00963     put_be32(pb, 0); /* size */
00964     put_tag(pb, "dinf");
00965     mov_write_dref_tag(pb);
00966     return updateSize(pb, pos);
00967 }
00968 
00969 static int mov_write_nmhd_tag(ByteIOContext *pb)
00970 {
00971     put_be32(pb, 12);
00972     put_tag(pb, "nmhd");
00973     put_be32(pb, 0);
00974     return 12;
00975 }
00976 
00977 static int mov_write_gmhd_tag(ByteIOContext *pb)
00978 {
00979     put_be32(pb, 0x20);   /* size */
00980     put_tag(pb, "gmhd");
00981     put_be32(pb, 0x18);   /* gmin size */
00982     put_tag(pb, "gmin");  /* generic media info */
00983     put_be32(pb, 0);      /* version & flags */
00984     put_be16(pb, 0x40);   /* graphics mode = */
00985     put_be16(pb, 0x8000); /* opColor (r?) */
00986     put_be16(pb, 0x8000); /* opColor (g?) */
00987     put_be16(pb, 0x8000); /* opColor (b?) */
00988     put_be16(pb, 0);      /* balance */
00989     put_be16(pb, 0);      /* reserved */
00990     return 0x20;
00991 }
00992 
00993 static int mov_write_smhd_tag(ByteIOContext *pb)
00994 {
00995     put_be32(pb, 16); /* size */
00996     put_tag(pb, "smhd");
00997     put_be32(pb, 0); /* version & flags */
00998     put_be16(pb, 0); /* reserved (balance, normally = 0) */
00999     put_be16(pb, 0); /* reserved */
01000     return 16;
01001 }
01002 
01003 static int mov_write_vmhd_tag(ByteIOContext *pb)
01004 {
01005     put_be32(pb, 0x14); /* size (always 0x14) */
01006     put_tag(pb, "vmhd");
01007     put_be32(pb, 0x01); /* version & flags */
01008     put_be64(pb, 0); /* reserved (graphics mode = copy) */
01009     return 0x14;
01010 }
01011 
01012 static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack *track)
01013 {
01014     const char *hdlr, *descr = NULL, *hdlr_type = NULL;
01015     int64_t pos = url_ftell(pb);
01016 
01017     if (!track) { /* no media --> data handler */
01018         hdlr = "dhlr";
01019         hdlr_type = "url ";
01020         descr = "DataHandler";
01021     } else {
01022         hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
01023         if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) {
01024             hdlr_type = "vide";
01025             descr = "VideoHandler";
01026         } else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) {
01027             hdlr_type = "soun";
01028             descr = "SoundHandler";
01029         } else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) {
01030             if (track->tag == MKTAG('t','x','3','g')) hdlr_type = "sbtl";
01031             else                                      hdlr_type = "text";
01032             descr = "SubtitleHandler";
01033         } else if (track->enc->codec_tag == MKTAG('r','t','p',' ')) {
01034             hdlr_type = "hint";
01035             descr = "HintHandler";
01036         }
01037     }
01038 
01039     put_be32(pb, 0); /* size */
01040     put_tag(pb, "hdlr");
01041     put_be32(pb, 0); /* Version & flags */
01042     put_buffer(pb, hdlr, 4); /* handler */
01043     put_tag(pb, hdlr_type); /* handler type */
01044     put_be32(pb ,0); /* reserved */
01045     put_be32(pb ,0); /* reserved */
01046     put_be32(pb ,0); /* reserved */
01047     if (!track || track->mode == MODE_MOV)
01048         put_byte(pb, strlen(descr)); /* pascal string */
01049     put_buffer(pb, descr, strlen(descr)); /* handler description */
01050     if (track && track->mode != MODE_MOV)
01051         put_byte(pb, 0); /* c string */
01052     return updateSize(pb, pos);
01053 }
01054 
01055 static int mov_write_hmhd_tag(ByteIOContext *pb)
01056 {
01057     /* This atom must be present, but leaving the values at zero
01058      * seems harmless. */
01059     put_be32(pb, 28); /* size */
01060     put_tag(pb, "hmhd");
01061     put_be32(pb, 0); /* version, flags */
01062     put_be16(pb, 0); /* maxPDUsize */
01063     put_be16(pb, 0); /* avgPDUsize */
01064     put_be32(pb, 0); /* maxbitrate */
01065     put_be32(pb, 0); /* avgbitrate */
01066     put_be32(pb, 0); /* reserved */
01067     return 28;
01068 }
01069 
01070 static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack *track)
01071 {
01072     int64_t pos = url_ftell(pb);
01073     put_be32(pb, 0); /* size */
01074     put_tag(pb, "minf");
01075     if(track->enc->codec_type == AVMEDIA_TYPE_VIDEO)
01076         mov_write_vmhd_tag(pb);
01077     else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
01078         mov_write_smhd_tag(pb);
01079     else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) {
01080         if (track->tag == MKTAG('t','e','x','t')) mov_write_gmhd_tag(pb);
01081         else                                      mov_write_nmhd_tag(pb);
01082     } else if (track->tag == MKTAG('r','t','p',' ')) {
01083         mov_write_hmhd_tag(pb);
01084     }
01085     if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */
01086         mov_write_hdlr_tag(pb, NULL);
01087     mov_write_dinf_tag(pb);
01088     mov_write_stbl_tag(pb, track);
01089     return updateSize(pb, pos);
01090 }
01091 
01092 static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack *track)
01093 {
01094     int version = track->trackDuration < INT32_MAX ? 0 : 1;
01095 
01096     (version == 1) ? put_be32(pb, 44) : put_be32(pb, 32); /* size */
01097     put_tag(pb, "mdhd");
01098     put_byte(pb, version);
01099     put_be24(pb, 0); /* flags */
01100     if (version == 1) {
01101         put_be64(pb, track->time);
01102         put_be64(pb, track->time);
01103     } else {
01104         put_be32(pb, track->time); /* creation time */
01105         put_be32(pb, track->time); /* modification time */
01106     }
01107     put_be32(pb, track->timescale); /* time scale (sample rate for audio) */
01108     (version == 1) ? put_be64(pb, track->trackDuration) : put_be32(pb, track->trackDuration); /* duration */
01109     put_be16(pb, track->language); /* language */
01110     put_be16(pb, 0); /* reserved (quality) */
01111 
01112     if(version!=0 && track->mode == MODE_MOV){
01113         av_log(NULL, AV_LOG_ERROR,
01114             "FATAL error, file duration too long for timebase, this file will not be\n"
01115             "playable with quicktime. Choose a different timebase or a different\n"
01116             "container format\n");
01117     }
01118 
01119     return 32;
01120 }
01121 
01122 static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack *track)
01123 {
01124     int64_t pos = url_ftell(pb);
01125     put_be32(pb, 0); /* size */
01126     put_tag(pb, "mdia");
01127     mov_write_mdhd_tag(pb, track);
01128     mov_write_hdlr_tag(pb, track);
01129     mov_write_minf_tag(pb, track);
01130     return updateSize(pb, pos);
01131 }
01132 
01133 static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack *track, AVStream *st)
01134 {
01135     int64_t duration = av_rescale_rnd(track->trackDuration, MOV_TIMESCALE,
01136                                       track->timescale, AV_ROUND_UP);
01137     int version = duration < INT32_MAX ? 0 : 1;
01138 
01139     (version == 1) ? put_be32(pb, 104) : put_be32(pb, 92); /* size */
01140     put_tag(pb, "tkhd");
01141     put_byte(pb, version);
01142     put_be24(pb, 0xf); /* flags (track enabled) */
01143     if (version == 1) {
01144         put_be64(pb, track->time);
01145         put_be64(pb, track->time);
01146     } else {
01147         put_be32(pb, track->time); /* creation time */
01148         put_be32(pb, track->time); /* modification time */
01149     }
01150     put_be32(pb, track->trackID); /* track-id */
01151     put_be32(pb, 0); /* reserved */
01152     (version == 1) ? put_be64(pb, duration) : put_be32(pb, duration);
01153 
01154     put_be32(pb, 0); /* reserved */
01155     put_be32(pb, 0); /* reserved */
01156     put_be32(pb, 0x0); /* reserved (Layer & Alternate group) */
01157     /* Volume, only for audio */
01158     if(track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
01159         put_be16(pb, 0x0100);
01160     else
01161         put_be16(pb, 0);
01162     put_be16(pb, 0); /* reserved */
01163 
01164     /* Matrix structure */
01165     put_be32(pb, 0x00010000); /* reserved */
01166     put_be32(pb, 0x0); /* reserved */
01167     put_be32(pb, 0x0); /* reserved */
01168     put_be32(pb, 0x0); /* reserved */
01169     put_be32(pb, 0x00010000); /* reserved */
01170     put_be32(pb, 0x0); /* reserved */
01171     put_be32(pb, 0x0); /* reserved */
01172     put_be32(pb, 0x0); /* reserved */
01173     put_be32(pb, 0x40000000); /* reserved */
01174 
01175     /* Track width and height, for visual only */
01176     if(st && (track->enc->codec_type == AVMEDIA_TYPE_VIDEO ||
01177               track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
01178         double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
01179         if(!sample_aspect_ratio || track->height != track->enc->height)
01180             sample_aspect_ratio = 1;
01181         put_be32(pb, sample_aspect_ratio * track->enc->width*0x10000);
01182         put_be32(pb, track->height*0x10000);
01183     }
01184     else {
01185         put_be32(pb, 0);
01186         put_be32(pb, 0);
01187     }
01188     return 0x5c;
01189 }
01190 
01191 // This box seems important for the psp playback ... without it the movie seems to hang
01192 static int mov_write_edts_tag(ByteIOContext *pb, MOVTrack *track)
01193 {
01194     put_be32(pb, 0x24); /* size  */
01195     put_tag(pb, "edts");
01196     put_be32(pb, 0x1c); /* size  */
01197     put_tag(pb, "elst");
01198     put_be32(pb, 0x0);
01199     put_be32(pb, 0x1);
01200 
01201     /* duration   ... doesn't seem to effect psp */
01202     put_be32(pb, av_rescale_rnd(track->trackDuration, MOV_TIMESCALE,
01203                                 track->timescale, AV_ROUND_UP));
01204 
01205     put_be32(pb, track->cluster[0].cts); /* first pts is cts since dts is 0 */
01206     put_be32(pb, 0x00010000);
01207     return 0x24;
01208 }
01209 
01210 static int mov_write_tref_tag(ByteIOContext *pb, MOVTrack *track)
01211 {
01212     put_be32(pb, 20);   // size
01213     put_tag(pb, "tref");
01214     put_be32(pb, 12);   // size (subatom)
01215     put_le32(pb, track->tref_tag);
01216     put_be32(pb, track->tref_id);
01217     return 20;
01218 }
01219 
01220 // goes at the end of each track!  ... Critical for PSP playback ("Incompatible data" without it)
01221 static int mov_write_uuid_tag_psp(ByteIOContext *pb, MOVTrack *mov)
01222 {
01223     put_be32(pb, 0x34); /* size ... reports as 28 in mp4box! */
01224     put_tag(pb, "uuid");
01225     put_tag(pb, "USMT");
01226     put_be32(pb, 0x21d24fce);
01227     put_be32(pb, 0xbb88695c);
01228     put_be32(pb, 0xfac9c740);
01229     put_be32(pb, 0x1c);     // another size here!
01230     put_tag(pb, "MTDT");
01231     put_be32(pb, 0x00010012);
01232     put_be32(pb, 0x0a);
01233     put_be32(pb, 0x55c40000);
01234     put_be32(pb, 0x1);
01235     put_be32(pb, 0x0);
01236     return 0x34;
01237 }
01238 
01239 static int mov_write_udta_sdp(ByteIOContext *pb, AVCodecContext *ctx, int index)
01240 {
01241     char buf[1000] = "";
01242     int len;
01243 
01244     ff_sdp_write_media(buf, sizeof(buf), ctx, NULL, 0, 0);
01245     av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", index);
01246     len = strlen(buf);
01247 
01248     put_be32(pb, len + 24);
01249     put_tag (pb, "udta");
01250     put_be32(pb, len + 16);
01251     put_tag (pb, "hnti");
01252     put_be32(pb, len + 8);
01253     put_tag (pb, "sdp ");
01254     put_buffer(pb, buf, len);
01255     return len + 24;
01256 }
01257 
01258 static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack *track, AVStream *st)
01259 {
01260     int64_t pos = url_ftell(pb);
01261     put_be32(pb, 0); /* size */
01262     put_tag(pb, "trak");
01263     mov_write_tkhd_tag(pb, track, st);
01264     if (track->mode == MODE_PSP || track->flags & MOV_TRACK_CTTS)
01265         mov_write_edts_tag(pb, track);  // PSP Movies require edts box
01266     if (track->tref_tag)
01267         mov_write_tref_tag(pb, track);
01268     mov_write_mdia_tag(pb, track);
01269     if (track->mode == MODE_PSP)
01270         mov_write_uuid_tag_psp(pb,track);  // PSP Movies require this uuid box
01271     if (track->tag == MKTAG('r','t','p',' '))
01272         mov_write_udta_sdp(pb, track->rtp_ctx->streams[0]->codec, track->trackID);
01273     return updateSize(pb, pos);
01274 }
01275 
01276 #if 0
01277 /* TODO: Not sorted out, but not necessary either */
01278 static int mov_write_iods_tag(ByteIOContext *pb, MOVMuxContext *mov)
01279 {
01280     put_be32(pb, 0x15); /* size */
01281     put_tag(pb, "iods");
01282     put_be32(pb, 0);    /* version & flags */
01283     put_be16(pb, 0x1007);
01284     put_byte(pb, 0);
01285     put_be16(pb, 0x4fff);
01286     put_be16(pb, 0xfffe);
01287     put_be16(pb, 0x01ff);
01288     return 0x15;
01289 }
01290 #endif
01291 
01292 static int mov_write_mvhd_tag(ByteIOContext *pb, MOVMuxContext *mov)
01293 {
01294     int maxTrackID = 1, i;
01295     int64_t maxTrackLenTemp, maxTrackLen = 0;
01296     int version;
01297 
01298     for (i=0; i<mov->nb_streams; i++) {
01299         if(mov->tracks[i].entry > 0) {
01300             maxTrackLenTemp = av_rescale_rnd(mov->tracks[i].trackDuration,
01301                                              MOV_TIMESCALE,
01302                                              mov->tracks[i].timescale,
01303                                              AV_ROUND_UP);
01304             if(maxTrackLen < maxTrackLenTemp)
01305                 maxTrackLen = maxTrackLenTemp;
01306             if(maxTrackID < mov->tracks[i].trackID)
01307                 maxTrackID = mov->tracks[i].trackID;
01308         }
01309     }
01310 
01311     version = maxTrackLen < UINT32_MAX ? 0 : 1;
01312     (version == 1) ? put_be32(pb, 120) : put_be32(pb, 108); /* size */
01313     put_tag(pb, "mvhd");
01314     put_byte(pb, version);
01315     put_be24(pb, 0); /* flags */
01316     if (version == 1) {
01317         put_be64(pb, mov->time);
01318         put_be64(pb, mov->time);
01319     } else {
01320         put_be32(pb, mov->time); /* creation time */
01321         put_be32(pb, mov->time); /* modification time */
01322     }
01323     put_be32(pb, MOV_TIMESCALE);
01324     (version == 1) ? put_be64(pb, maxTrackLen) : put_be32(pb, maxTrackLen); /* duration of longest track */
01325 
01326     put_be32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
01327     put_be16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
01328     put_be16(pb, 0); /* reserved */
01329     put_be32(pb, 0); /* reserved */
01330     put_be32(pb, 0); /* reserved */
01331 
01332     /* Matrix structure */
01333     put_be32(pb, 0x00010000); /* reserved */
01334     put_be32(pb, 0x0); /* reserved */
01335     put_be32(pb, 0x0); /* reserved */
01336     put_be32(pb, 0x0); /* reserved */
01337     put_be32(pb, 0x00010000); /* reserved */
01338     put_be32(pb, 0x0); /* reserved */
01339     put_be32(pb, 0x0); /* reserved */
01340     put_be32(pb, 0x0); /* reserved */
01341     put_be32(pb, 0x40000000); /* reserved */
01342 
01343     put_be32(pb, 0); /* reserved (preview time) */
01344     put_be32(pb, 0); /* reserved (preview duration) */
01345     put_be32(pb, 0); /* reserved (poster time) */
01346     put_be32(pb, 0); /* reserved (selection time) */
01347     put_be32(pb, 0); /* reserved (selection duration) */
01348     put_be32(pb, 0); /* reserved (current time) */
01349     put_be32(pb, maxTrackID+1); /* Next track id */
01350     return 0x6c;
01351 }
01352 
01353 static int mov_write_itunes_hdlr_tag(ByteIOContext *pb, MOVMuxContext *mov,
01354                                      AVFormatContext *s)
01355 {
01356     put_be32(pb, 33); /* size */
01357     put_tag(pb, "hdlr");
01358     put_be32(pb, 0);
01359     put_be32(pb, 0);
01360     put_tag(pb, "mdir");
01361     put_tag(pb, "appl");
01362     put_be32(pb, 0);
01363     put_be32(pb, 0);
01364     put_byte(pb, 0);
01365     return 33;
01366 }
01367 
01368 /* helper function to write a data tag with the specified string as data */
01369 static int mov_write_string_data_tag(ByteIOContext *pb, const char *data, int lang, int long_style)
01370 {
01371     if(long_style){
01372         int size = 16 + strlen(data);
01373         put_be32(pb, size); /* size */
01374         put_tag(pb, "data");
01375         put_be32(pb, 1);
01376         put_be32(pb, 0);
01377         put_buffer(pb, data, strlen(data));
01378         return size;
01379     }else{
01380         if (!lang)
01381             lang = ff_mov_iso639_to_lang("und", 1);
01382         put_be16(pb, strlen(data)); /* string length */
01383         put_be16(pb, lang);
01384         put_buffer(pb, data, strlen(data));
01385         return strlen(data) + 4;
01386     }
01387 }
01388 
01389 static int mov_write_string_tag(ByteIOContext *pb, const char *name, const char *value, int lang, int long_style){
01390     int size = 0;
01391     if (value && value[0]) {
01392         int64_t pos = url_ftell(pb);
01393         put_be32(pb, 0); /* size */
01394         put_tag(pb, name);
01395         mov_write_string_data_tag(pb, value, lang, long_style);
01396         size= updateSize(pb, pos);
01397     }
01398     return size;
01399 }
01400 
01401 static int mov_write_string_metadata(AVFormatContext *s, ByteIOContext *pb,
01402                                      const char *name, const char *tag,
01403                                      int long_style)
01404 {
01405     int l, lang = 0, len, len2;
01406     AVMetadataTag *t, *t2 = NULL;
01407     char tag2[16];
01408 
01409     if (!(t = av_metadata_get(s->metadata, tag, NULL, 0)))
01410         return 0;
01411 
01412     len = strlen(t->key);
01413     snprintf(tag2, sizeof(tag2), "%s-", tag);
01414     while ((t2 = av_metadata_get(s->metadata, tag2, t2, AV_METADATA_IGNORE_SUFFIX))) {
01415         len2 = strlen(t2->key);
01416         if (len2 == len+4 && !strcmp(t->value, t2->value)
01417             && (l=ff_mov_iso639_to_lang(&t2->key[len2-3], 1)) >= 0) {
01418             lang = l;
01419             break;
01420         }
01421     }
01422     return mov_write_string_tag(pb, name, t->value, lang, long_style);
01423 }
01424 
01425 /* iTunes track number */
01426 static int mov_write_trkn_tag(ByteIOContext *pb, MOVMuxContext *mov,
01427                               AVFormatContext *s)
01428 {
01429     AVMetadataTag *t = av_metadata_get(s->metadata, "track", NULL, 0);
01430     int size = 0, track = t ? atoi(t->value) : 0;
01431     if (track) {
01432         put_be32(pb, 32); /* size */
01433         put_tag(pb, "trkn");
01434             put_be32(pb, 24); /* size */
01435             put_tag(pb, "data");
01436             put_be32(pb, 0);        // 8 bytes empty
01437             put_be32(pb, 0);
01438             put_be16(pb, 0);        // empty
01439             put_be16(pb, track);    // track number
01440             put_be16(pb, 0);        // total track number
01441             put_be16(pb, 0);        // empty
01442         size = 32;
01443     }
01444     return size;
01445 }
01446 
01447 /* iTunes meta data list */
01448 static int mov_write_ilst_tag(ByteIOContext *pb, MOVMuxContext *mov,
01449                               AVFormatContext *s)
01450 {
01451     int64_t pos = url_ftell(pb);
01452     put_be32(pb, 0); /* size */
01453     put_tag(pb, "ilst");
01454     mov_write_string_metadata(s, pb, "\251nam", "title"    , 1);
01455     mov_write_string_metadata(s, pb, "\251ART", "artist"   , 1);
01456     mov_write_string_metadata(s, pb, "aART", "album_artist", 1);
01457     mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1);
01458     mov_write_string_metadata(s, pb, "\251alb", "album"    , 1);
01459     mov_write_string_metadata(s, pb, "\251day", "date"     , 1);
01460     mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1);
01461     mov_write_string_metadata(s, pb, "\251cmt", "comment"  , 1);
01462     mov_write_string_metadata(s, pb, "\251gen", "genre"    , 1);
01463     mov_write_string_metadata(s, pb, "\251cpy", "copyright", 1);
01464     mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
01465     mov_write_string_metadata(s, pb, "\251lyr", "lyrics"   , 1);
01466     mov_write_string_metadata(s, pb, "desc",    "description",1);
01467     mov_write_string_metadata(s, pb, "ldes",    "synopsis" , 1);
01468     mov_write_string_metadata(s, pb, "tvsh",    "show"     , 1);
01469     mov_write_string_metadata(s, pb, "tven",    "episode_id",1);
01470     mov_write_string_metadata(s, pb, "tvnn",    "network"  , 1);
01471     mov_write_trkn_tag(pb, mov, s);
01472     return updateSize(pb, pos);
01473 }
01474 
01475 /* iTunes meta data tag */
01476 static int mov_write_meta_tag(ByteIOContext *pb, MOVMuxContext *mov,
01477                               AVFormatContext *s)
01478 {
01479     int size = 0;
01480     int64_t pos = url_ftell(pb);
01481     put_be32(pb, 0); /* size */
01482     put_tag(pb, "meta");
01483     put_be32(pb, 0);
01484     mov_write_itunes_hdlr_tag(pb, mov, s);
01485     mov_write_ilst_tag(pb, mov, s);
01486     size = updateSize(pb, pos);
01487     return size;
01488 }
01489 
01490 static int utf8len(const uint8_t *b)
01491 {
01492     int len=0;
01493     int val;
01494     while(*b){
01495         GET_UTF8(val, *b++, return -1;)
01496         len++;
01497     }
01498     return len;
01499 }
01500 
01501 static int ascii_to_wc(ByteIOContext *pb, const uint8_t *b)
01502 {
01503     int val;
01504     while(*b){
01505         GET_UTF8(val, *b++, return -1;)
01506         put_be16(pb, val);
01507     }
01508     put_be16(pb, 0x00);
01509     return 0;
01510 }
01511 
01512 static uint16_t language_code(const char *str)
01513 {
01514     return (((str[0]-0x60) & 0x1F) << 10) + (((str[1]-0x60) & 0x1F) << 5) + ((str[2]-0x60) & 0x1F);
01515 }
01516 
01517 static int mov_write_3gp_udta_tag(ByteIOContext *pb, AVFormatContext *s,
01518                                   const char *tag, const char *str)
01519 {
01520     int64_t pos = url_ftell(pb);
01521     AVMetadataTag *t = av_metadata_get(s->metadata, str, NULL, 0);
01522     if (!t || !utf8len(t->value))
01523         return 0;
01524     put_be32(pb, 0);   /* size */
01525     put_tag (pb, tag); /* type */
01526     put_be32(pb, 0);   /* version + flags */
01527     if (!strcmp(tag, "yrrc"))
01528         put_be16(pb, atoi(t->value));
01529     else {
01530         put_be16(pb, language_code("eng")); /* language */
01531         put_buffer(pb, t->value, strlen(t->value)+1); /* UTF8 string value */
01532         if (!strcmp(tag, "albm") &&
01533             (t = av_metadata_get(s->metadata, "date", NULL, 0)))
01534             put_byte(pb, atoi(t->value));
01535     }
01536     return updateSize(pb, pos);
01537 }
01538 
01539 static int mov_write_chpl_tag(ByteIOContext *pb, AVFormatContext *s)
01540 {
01541     int64_t pos = url_ftell(pb);
01542     int i, nb_chapters = FFMIN(s->nb_chapters, 255);
01543 
01544     put_be32(pb, 0);            // size
01545     put_tag (pb, "chpl");
01546     put_be32(pb, 0x01000000);   // version + flags
01547     put_be32(pb, 0);            // unknown
01548     put_byte(pb, nb_chapters);
01549 
01550     for (i = 0; i < nb_chapters; i++) {
01551         AVChapter *c = s->chapters[i];
01552         AVMetadataTag *t;
01553         put_be64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
01554 
01555         if ((t = av_metadata_get(c->metadata, "title", NULL, 0))) {
01556             int len = FFMIN(strlen(t->value), 255);
01557             put_byte(pb, len);
01558             put_buffer(pb, t->value, len);
01559         } else
01560             put_byte(pb, 0);
01561     }
01562     return updateSize(pb, pos);
01563 }
01564 
01565 static int mov_write_udta_tag(ByteIOContext *pb, MOVMuxContext *mov,
01566                               AVFormatContext *s)
01567 {
01568     ByteIOContext *pb_buf;
01569     int i, ret, size;
01570     uint8_t *buf;
01571 
01572     for (i = 0; i < s->nb_streams; i++)
01573         if (mov->tracks[i].enc->flags & CODEC_FLAG_BITEXACT) {
01574             return 0;
01575         }
01576 
01577     ret = url_open_dyn_buf(&pb_buf);
01578     if(ret < 0)
01579         return ret;
01580 
01581         if (mov->mode & MODE_3GP) {
01582             mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
01583             mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
01584             mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
01585             mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
01586             mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
01587             mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
01588             mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
01589             mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
01590         } else if (mov->mode == MODE_MOV) { // the title field breaks gtkpod with mp4 and my suspicion is that stuff is not valid in mp4
01591             mov_write_string_metadata(s, pb_buf, "\251nam", "title"      , 0);
01592             mov_write_string_metadata(s, pb_buf, "\251aut", "author"     , 0);
01593             mov_write_string_metadata(s, pb_buf, "\251alb", "album"      , 0);
01594             mov_write_string_metadata(s, pb_buf, "\251day", "date"       , 0);
01595             mov_write_string_tag(pb_buf, "\251enc", LIBAVFORMAT_IDENT, 0, 0);
01596             mov_write_string_metadata(s, pb_buf, "\251des", "comment"    , 0);
01597             mov_write_string_metadata(s, pb_buf, "\251gen", "genre"      , 0);
01598             mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright"  , 0);
01599         } else {
01600             /* iTunes meta data */
01601             mov_write_meta_tag(pb_buf, mov, s);
01602         }
01603 
01604         if (s->nb_chapters)
01605             mov_write_chpl_tag(pb_buf, s);
01606 
01607     if ((size = url_close_dyn_buf(pb_buf, &buf)) > 0) {
01608         put_be32(pb, size+8);
01609         put_tag(pb, "udta");
01610         put_buffer(pb, buf, size);
01611         av_free(buf);
01612     }
01613 
01614     return 0;
01615 }
01616 
01617 static void mov_write_psp_udta_tag(ByteIOContext *pb,
01618                                   const char *str, const char *lang, int type)
01619 {
01620     int len = utf8len(str)+1;
01621     if(len<=0)
01622         return;
01623     put_be16(pb, len*2+10);            /* size */
01624     put_be32(pb, type);                /* type */
01625     put_be16(pb, language_code(lang)); /* language */
01626     put_be16(pb, 0x01);                /* ? */
01627     ascii_to_wc(pb, str);
01628 }
01629 
01630 static int mov_write_uuidusmt_tag(ByteIOContext *pb, AVFormatContext *s)
01631 {
01632     AVMetadataTag *title = av_metadata_get(s->metadata, "title", NULL, 0);
01633     int64_t pos, pos2;
01634 
01635     if (title) {
01636         pos = url_ftell(pb);
01637         put_be32(pb, 0); /* size placeholder*/
01638         put_tag(pb, "uuid");
01639         put_tag(pb, "USMT");
01640         put_be32(pb, 0x21d24fce); /* 96 bit UUID */
01641         put_be32(pb, 0xbb88695c);
01642         put_be32(pb, 0xfac9c740);
01643 
01644         pos2 = url_ftell(pb);
01645         put_be32(pb, 0); /* size placeholder*/
01646         put_tag(pb, "MTDT");
01647         put_be16(pb, 4);
01648 
01649         // ?
01650         put_be16(pb, 0x0C);                 /* size */
01651         put_be32(pb, 0x0B);                 /* type */
01652         put_be16(pb, language_code("und")); /* language */
01653         put_be16(pb, 0x0);                  /* ? */
01654         put_be16(pb, 0x021C);               /* data */
01655 
01656         mov_write_psp_udta_tag(pb, LIBAVCODEC_IDENT,      "eng", 0x04);
01657         mov_write_psp_udta_tag(pb, title->value,          "eng", 0x01);
01658 //        snprintf(dt,32,"%04d/%02d/%02d %02d:%02d:%02d",t_st->tm_year+1900,t_st->tm_mon+1,t_st->tm_mday,t_st->tm_hour,t_st->tm_min,t_st->tm_sec);
01659         mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03);
01660 
01661         updateSize(pb, pos2);
01662         return updateSize(pb, pos);
01663     }
01664 
01665     return 0;
01666 }
01667 
01668 static int mov_write_moov_tag(ByteIOContext *pb, MOVMuxContext *mov,
01669                               AVFormatContext *s)
01670 {
01671     int i;
01672     int64_t pos = url_ftell(pb);
01673     put_be32(pb, 0); /* size placeholder*/
01674     put_tag(pb, "moov");
01675 
01676     for (i=0; i<mov->nb_streams; i++) {
01677         if(mov->tracks[i].entry <= 0) continue;
01678 
01679         mov->tracks[i].time = mov->time;
01680         mov->tracks[i].trackID = i+1;
01681     }
01682 
01683     if (mov->chapter_track)
01684         for (i=0; i<s->nb_streams; i++) {
01685             mov->tracks[i].tref_tag = MKTAG('c','h','a','p');
01686             mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].trackID;
01687         }
01688     for (i = 0; i < mov->nb_streams; i++) {
01689         if (mov->tracks[i].tag == MKTAG('r','t','p',' ')) {
01690             mov->tracks[i].tref_tag = MKTAG('h','i','n','t');
01691             mov->tracks[i].tref_id =
01692                 mov->tracks[mov->tracks[i].src_track].trackID;
01693         }
01694     }
01695 
01696     mov_write_mvhd_tag(pb, mov);
01697     //mov_write_iods_tag(pb, mov);
01698     for (i=0; i<mov->nb_streams; i++) {
01699         if(mov->tracks[i].entry > 0) {
01700             mov_write_trak_tag(pb, &(mov->tracks[i]), i < s->nb_streams ? s->streams[i] : NULL);
01701         }
01702     }
01703 
01704     if (mov->mode == MODE_PSP)
01705         mov_write_uuidusmt_tag(pb, s);
01706     else
01707         mov_write_udta_tag(pb, mov, s);
01708 
01709     return updateSize(pb, pos);
01710 }
01711 
01712 static int mov_write_mdat_tag(ByteIOContext *pb, MOVMuxContext *mov)
01713 {
01714     put_be32(pb, 8);    // placeholder for extended size field (64 bit)
01715     put_tag(pb, mov->mode == MODE_MOV ? "wide" : "free");
01716 
01717     mov->mdat_pos = url_ftell(pb);
01718     put_be32(pb, 0); /* size placeholder*/
01719     put_tag(pb, "mdat");
01720     return 0;
01721 }
01722 
01723 /* TODO: This needs to be more general */
01724 static int mov_write_ftyp_tag(ByteIOContext *pb, AVFormatContext *s)
01725 {
01726     MOVMuxContext *mov = s->priv_data;
01727     int64_t pos = url_ftell(pb);
01728     int has_h264 = 0, has_video = 0;
01729     int minor = 0x200;
01730     int i;
01731 
01732     for (i = 0; i < s->nb_streams; i++) {
01733         AVStream *st = s->streams[i];
01734         if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
01735             has_video = 1;
01736         if (st->codec->codec_id == CODEC_ID_H264)
01737             has_h264 = 1;
01738     }
01739 
01740     put_be32(pb, 0); /* size */
01741     put_tag(pb, "ftyp");
01742 
01743     if (mov->mode == MODE_3GP) {
01744         put_tag(pb, has_h264 ? "3gp6"  : "3gp4");
01745         minor =     has_h264 ?   0x100 :   0x200;
01746     } else if (mov->mode & MODE_3G2) {
01747         put_tag(pb, has_h264 ? "3g2b"  : "3g2a");
01748         minor =     has_h264 ? 0x20000 : 0x10000;
01749     }else if (mov->mode == MODE_PSP)
01750         put_tag(pb, "MSNV");
01751     else if (mov->mode == MODE_MP4)
01752         put_tag(pb, "isom");
01753     else if (mov->mode == MODE_IPOD)
01754         put_tag(pb, has_video ? "M4V ":"M4A ");
01755     else
01756         put_tag(pb, "qt  ");
01757 
01758     put_be32(pb, minor);
01759 
01760     if(mov->mode == MODE_MOV)
01761         put_tag(pb, "qt  ");
01762     else{
01763         put_tag(pb, "isom");
01764         put_tag(pb, "iso2");
01765         if(has_h264)
01766             put_tag(pb, "avc1");
01767     }
01768 
01769     if (mov->mode == MODE_3GP)
01770         put_tag(pb, has_h264 ? "3gp6":"3gp4");
01771     else if (mov->mode & MODE_3G2)
01772         put_tag(pb, has_h264 ? "3g2b":"3g2a");
01773     else if (mov->mode == MODE_PSP)
01774         put_tag(pb, "MSNV");
01775     else if (mov->mode == MODE_MP4)
01776         put_tag(pb, "mp41");
01777     return updateSize(pb, pos);
01778 }
01779 
01780 static void mov_write_uuidprof_tag(ByteIOContext *pb, AVFormatContext *s)
01781 {
01782     AVCodecContext *VideoCodec = s->streams[0]->codec;
01783     AVCodecContext *AudioCodec = s->streams[1]->codec;
01784     int AudioRate = AudioCodec->sample_rate;
01785     int FrameRate = ((VideoCodec->time_base.den) * (0x10000))/ (VideoCodec->time_base.num);
01786     int audio_kbitrate= AudioCodec->bit_rate / 1000;
01787     int video_kbitrate= FFMIN(VideoCodec->bit_rate / 1000, 800 - audio_kbitrate);
01788 
01789     put_be32(pb, 0x94); /* size */
01790     put_tag(pb, "uuid");
01791     put_tag(pb, "PROF");
01792 
01793     put_be32(pb, 0x21d24fce); /* 96 bit UUID */
01794     put_be32(pb, 0xbb88695c);
01795     put_be32(pb, 0xfac9c740);
01796 
01797     put_be32(pb, 0x0);  /* ? */
01798     put_be32(pb, 0x3);  /* 3 sections ? */
01799 
01800     put_be32(pb, 0x14); /* size */
01801     put_tag(pb, "FPRF");
01802     put_be32(pb, 0x0);  /* ? */
01803     put_be32(pb, 0x0);  /* ? */
01804     put_be32(pb, 0x0);  /* ? */
01805 
01806     put_be32(pb, 0x2c);  /* size */
01807     put_tag(pb, "APRF");   /* audio */
01808     put_be32(pb, 0x0);
01809     put_be32(pb, 0x2);   /* TrackID */
01810     put_tag(pb, "mp4a");
01811     put_be32(pb, 0x20f);
01812     put_be32(pb, 0x0);
01813     put_be32(pb, audio_kbitrate);
01814     put_be32(pb, audio_kbitrate);
01815     put_be32(pb, AudioRate);
01816     put_be32(pb, AudioCodec->channels);
01817 
01818     put_be32(pb, 0x34);  /* size */
01819     put_tag(pb, "VPRF");   /* video */
01820     put_be32(pb, 0x0);
01821     put_be32(pb, 0x1);    /* TrackID */
01822     if (VideoCodec->codec_id == CODEC_ID_H264) {
01823         put_tag(pb, "avc1");
01824         put_be16(pb, 0x014D);
01825         put_be16(pb, 0x0015);
01826     } else {
01827         put_tag(pb, "mp4v");
01828         put_be16(pb, 0x0000);
01829         put_be16(pb, 0x0103);
01830     }
01831     put_be32(pb, 0x0);
01832     put_be32(pb, video_kbitrate);
01833     put_be32(pb, video_kbitrate);
01834     put_be32(pb, FrameRate);
01835     put_be32(pb, FrameRate);
01836     put_be16(pb, VideoCodec->width);
01837     put_be16(pb, VideoCodec->height);
01838     put_be32(pb, 0x010001); /* ? */
01839 }
01840 
01841 static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
01842 {
01843     uint32_t c = -1;
01844     int i, closed_gop = 0;
01845 
01846     for (i = 0; i < pkt->size - 4; i++) {
01847         c = (c<<8) + pkt->data[i];
01848         if (c == 0x1b8) { // gop
01849             closed_gop = pkt->data[i+4]>>6 & 0x01;
01850         } else if (c == 0x100) { // pic
01851             int temp_ref = (pkt->data[i+1]<<2) | (pkt->data[i+2]>>6);
01852             if (!temp_ref || closed_gop) // I picture is not reordered
01853                 *flags = MOV_SYNC_SAMPLE;
01854             else
01855                 *flags = MOV_PARTIAL_SYNC_SAMPLE;
01856             break;
01857         }
01858     }
01859     return 0;
01860 }
01861 
01862 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
01863 {
01864     MOVMuxContext *mov = s->priv_data;
01865     ByteIOContext *pb = s->pb;
01866     MOVTrack *trk = &mov->tracks[pkt->stream_index];
01867     AVCodecContext *enc = trk->enc;
01868     unsigned int samplesInChunk = 0;
01869     int size= pkt->size;
01870 
01871     if (url_is_streamed(s->pb)) return 0; /* Can't handle that */
01872     if (!size) return 0; /* Discard 0 sized packets */
01873 
01874     if (enc->codec_id == CODEC_ID_AMR_NB) {
01875         /* We must find out how many AMR blocks there are in one packet */
01876         static uint16_t packed_size[16] =
01877             {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0};
01878         int len = 0;
01879 
01880         while (len < size && samplesInChunk < 100) {
01881             len += packed_size[(pkt->data[len] >> 3) & 0x0F];
01882             samplesInChunk++;
01883         }
01884         if(samplesInChunk > 1){
01885             av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
01886             return -1;
01887         }
01888     } else if (trk->sampleSize)
01889         samplesInChunk = size/trk->sampleSize;
01890     else
01891         samplesInChunk = 1;
01892 
01893     /* copy extradata if it exists */
01894     if (trk->vosLen == 0 && enc->extradata_size > 0) {
01895         trk->vosLen = enc->extradata_size;
01896         trk->vosData = av_malloc(trk->vosLen);
01897         memcpy(trk->vosData, enc->extradata, trk->vosLen);
01898     }
01899 
01900     if (enc->codec_id == CODEC_ID_H264 && trk->vosLen > 0 && *(uint8_t *)trk->vosData != 1) {
01901         /* from x264 or from bytestream h264 */
01902         /* nal reformating needed */
01903         size = ff_avc_parse_nal_units(pb, pkt->data, pkt->size);
01904     } else {
01905         put_buffer(pb, pkt->data, size);
01906     }
01907 
01908     if ((enc->codec_id == CODEC_ID_DNXHD ||
01909          enc->codec_id == CODEC_ID_AC3) && !trk->vosLen) {
01910         /* copy frame to create needed atoms */
01911         trk->vosLen = size;
01912         trk->vosData = av_malloc(size);
01913         if (!trk->vosData)
01914             return AVERROR(ENOMEM);
01915         memcpy(trk->vosData, pkt->data, size);
01916     }
01917 
01918     if (!(trk->entry % MOV_INDEX_CLUSTER_SIZE)) {
01919         trk->cluster = av_realloc(trk->cluster, (trk->entry + MOV_INDEX_CLUSTER_SIZE) * sizeof(*trk->cluster));
01920         if (!trk->cluster)
01921             return -1;
01922     }
01923 
01924     trk->cluster[trk->entry].pos = url_ftell(pb) - size;
01925     trk->cluster[trk->entry].samplesInChunk = samplesInChunk;
01926     trk->cluster[trk->entry].size = size;
01927     trk->cluster[trk->entry].entries = samplesInChunk;
01928     trk->cluster[trk->entry].dts = pkt->dts;
01929     trk->trackDuration = pkt->dts - trk->cluster[0].dts + pkt->duration;
01930 
01931     if (pkt->pts == AV_NOPTS_VALUE) {
01932         av_log(s, AV_LOG_WARNING, "pts has no value\n");
01933         pkt->pts = pkt->dts;
01934     }
01935     if (pkt->dts != pkt->pts)
01936         trk->flags |= MOV_TRACK_CTTS;
01937     trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
01938     trk->cluster[trk->entry].flags = 0;
01939     if (pkt->flags & AV_PKT_FLAG_KEY) {
01940         if (mov->mode == MODE_MOV && enc->codec_id == CODEC_ID_MPEG2VIDEO) {
01941             mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags);
01942             if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
01943                 trk->flags |= MOV_TRACK_STPS;
01944         } else {
01945             trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
01946         }
01947         if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
01948             trk->hasKeyframes++;
01949     }
01950     trk->entry++;
01951     trk->sampleCount += samplesInChunk;
01952     mov->mdat_size += size;
01953 
01954     put_flush_packet(pb);
01955 
01956     if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams)
01957         ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry);
01958     return 0;
01959 }
01960 
01961 // QuickTime chapters involve an additional text track with the chapter names
01962 // as samples, and a tref pointing from the other tracks to the chapter one.
01963 static void mov_create_chapter_track(AVFormatContext *s, int tracknum)
01964 {
01965     MOVMuxContext *mov = s->priv_data;
01966     MOVTrack *track = &mov->tracks[tracknum];
01967     AVPacket pkt = { .stream_index = tracknum, .flags = AV_PKT_FLAG_KEY };
01968     int i, len;
01969 
01970     track->mode = mov->mode;
01971     track->tag = MKTAG('t','e','x','t');
01972     track->timescale = MOV_TIMESCALE;
01973     track->enc = avcodec_alloc_context();
01974     track->enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
01975 
01976     for (i = 0; i < s->nb_chapters; i++) {
01977         AVChapter *c = s->chapters[i];
01978         AVMetadataTag *t;
01979 
01980         int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,MOV_TIMESCALE});
01981         pkt.pts = pkt.dts = av_rescale_q(c->start, c->time_base, (AVRational){1,MOV_TIMESCALE});
01982         pkt.duration = end - pkt.dts;
01983 
01984         if ((t = av_metadata_get(c->metadata, "title", NULL, 0))) {
01985             len = strlen(t->value);
01986             pkt.size = len+2;
01987             pkt.data = av_malloc(pkt.size);
01988             AV_WB16(pkt.data, len);
01989             memcpy(pkt.data+2, t->value, len);
01990             ff_mov_write_packet(s, &pkt);
01991             av_freep(&pkt.data);
01992         }
01993     }
01994 }
01995 
01996 static int mov_write_header(AVFormatContext *s)
01997 {
01998     ByteIOContext *pb = s->pb;
01999     MOVMuxContext *mov = s->priv_data;
02000     int i, hint_track = 0;
02001 
02002     if (url_is_streamed(s->pb)) {
02003         av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
02004         return -1;
02005     }
02006 
02007     /* Default mode == MP4 */
02008     mov->mode = MODE_MP4;
02009 
02010     if (s->oformat != NULL) {
02011         if (!strcmp("3gp", s->oformat->name)) mov->mode = MODE_3GP;
02012         else if (!strcmp("3g2", s->oformat->name)) mov->mode = MODE_3GP|MODE_3G2;
02013         else if (!strcmp("mov", s->oformat->name)) mov->mode = MODE_MOV;
02014         else if (!strcmp("psp", s->oformat->name)) mov->mode = MODE_PSP;
02015         else if (!strcmp("ipod",s->oformat->name)) mov->mode = MODE_IPOD;
02016 
02017         mov_write_ftyp_tag(pb,s);
02018         if (mov->mode == MODE_PSP) {
02019             if (s->nb_streams != 2) {
02020                 av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
02021                 return -1;
02022             }
02023             mov_write_uuidprof_tag(pb,s);
02024         }
02025     }
02026 
02027     mov->nb_streams = s->nb_streams;
02028     if (mov->mode & (MODE_MOV|MODE_IPOD) && s->nb_chapters)
02029         mov->chapter_track = mov->nb_streams++;
02030 
02031     if (s->flags & AVFMT_FLAG_RTP_HINT) {
02032         /* Add hint tracks for each audio and video stream */
02033         hint_track = mov->nb_streams;
02034         for (i = 0; i < s->nb_streams; i++) {
02035             AVStream *st = s->streams[i];
02036             if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
02037                 st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
02038                 mov->nb_streams++;
02039             }
02040         }
02041     }
02042 
02043     mov->tracks = av_mallocz(mov->nb_streams*sizeof(*mov->tracks));
02044     if (!mov->tracks)
02045         return AVERROR(ENOMEM);
02046 
02047     for(i=0; i<s->nb_streams; i++){
02048         AVStream *st= s->streams[i];
02049         MOVTrack *track= &mov->tracks[i];
02050         AVMetadataTag *lang = av_metadata_get(st->metadata, "language", NULL,0);
02051 
02052         track->enc = st->codec;
02053         track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
02054         if (track->language < 0)
02055             track->language = 0;
02056         track->mode = mov->mode;
02057         track->tag = mov_find_codec_tag(s, track);
02058         if (!track->tag) {
02059             av_log(s, AV_LOG_ERROR, "track %d: could not find tag, "
02060                    "codec not currently supported in container\n", i);
02061             goto error;
02062         }
02063         /* If hinting of this track is enabled by a later hint track,
02064          * this is updated. */
02065         track->hint_track = -1;
02066         if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO){
02067             if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') ||
02068                 track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') ||
02069                 track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) {
02070                 if (st->codec->width != 720 || (st->codec->height != 608 && st->codec->height != 512)) {
02071                     av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
02072                     goto error;
02073                 }
02074                 track->height = track->tag>>24 == 'n' ? 486 : 576;
02075             }
02076             track->timescale = st->codec->time_base.den;
02077             if (track->mode == MODE_MOV && track->timescale > 100000)
02078                 av_log(s, AV_LOG_WARNING,
02079                        "WARNING codec timebase is very high. If duration is too long,\n"
02080                        "file may not be playable by quicktime. Specify a shorter timebase\n"
02081                        "or choose different container.\n");
02082         }else if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO){
02083             track->timescale = st->codec->sample_rate;
02084             if(!st->codec->frame_size && !av_get_bits_per_sample(st->codec->codec_id)) {
02085                 av_log(s, AV_LOG_ERROR, "track %d: codec frame size is not set\n", i);
02086                 goto error;
02087             }else if(st->codec->frame_size > 1){ /* assume compressed audio */
02088                 track->audio_vbr = 1;
02089             }else{
02090                 st->codec->frame_size = 1;
02091                 track->sampleSize = (av_get_bits_per_sample(st->codec->codec_id) >> 3) * st->codec->channels;
02092             }
02093             if (track->mode != MODE_MOV) {
02094                 if (track->timescale > UINT16_MAX) {
02095                     av_log(s, AV_LOG_ERROR, "track %d: output format does not support "
02096                            "sample rate %dhz\n", i, track->timescale);
02097                     goto error;
02098                 }
02099                 if (track->enc->codec_id == CODEC_ID_MP3 && track->timescale < 16000) {
02100                     av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not supported\n",
02101                            i, track->enc->sample_rate);
02102                     goto error;
02103                 }
02104             }
02105         }else if(st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE){
02106             track->timescale = st->codec->time_base.den;
02107         }
02108         if (!track->height)
02109             track->height = st->codec->height;
02110 
02111         av_set_pts_info(st, 64, 1, track->timescale);
02112     }
02113 
02114     mov_write_mdat_tag(pb, mov);
02115     mov->time = s->timestamp + 0x7C25B080; //1970 based -> 1904 based
02116 
02117     if (mov->chapter_track)
02118         mov_create_chapter_track(s, mov->chapter_track);
02119 
02120     if (s->flags & AVFMT_FLAG_RTP_HINT) {
02121         /* Initialize the hint tracks for each audio and video stream */
02122         for (i = 0; i < s->nb_streams; i++) {
02123             AVStream *st = s->streams[i];
02124             if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
02125                 st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
02126                 ff_mov_init_hinting(s, hint_track, i);
02127                 hint_track++;
02128             }
02129         }
02130     }
02131 
02132     put_flush_packet(pb);
02133 
02134     return 0;
02135  error:
02136     av_freep(&mov->tracks);
02137     return -1;
02138 }
02139 
02140 static int mov_write_trailer(AVFormatContext *s)
02141 {
02142     MOVMuxContext *mov = s->priv_data;
02143     ByteIOContext *pb = s->pb;
02144     int res = 0;
02145     int i;
02146 
02147     int64_t moov_pos = url_ftell(pb);
02148 
02149     /* Write size of mdat tag */
02150     if (mov->mdat_size+8 <= UINT32_MAX) {
02151         url_fseek(pb, mov->mdat_pos, SEEK_SET);
02152         put_be32(pb, mov->mdat_size+8);
02153     } else {
02154         /* overwrite 'wide' placeholder atom */
02155         url_fseek(pb, mov->mdat_pos - 8, SEEK_SET);
02156         put_be32(pb, 1); /* special value: real atom size will be 64 bit value after tag field */
02157         put_tag(pb, "mdat");
02158         put_be64(pb, mov->mdat_size+16);
02159     }
02160     url_fseek(pb, moov_pos, SEEK_SET);
02161 
02162     mov_write_moov_tag(pb, mov, s);
02163 
02164     if (mov->chapter_track)
02165         av_freep(&mov->tracks[mov->chapter_track].enc);
02166 
02167     for (i=0; i<mov->nb_streams; i++) {
02168         if (mov->tracks[i].tag == MKTAG('r','t','p',' '))
02169             ff_mov_close_hinting(&mov->tracks[i]);
02170         av_freep(&mov->tracks[i].cluster);
02171 
02172         if(mov->tracks[i].vosLen) av_free(mov->tracks[i].vosData);
02173 
02174     }
02175 
02176     put_flush_packet(pb);
02177 
02178     av_freep(&mov->tracks);
02179 
02180     return res;
02181 }
02182 
02183 #if CONFIG_MOV_MUXER
02184 AVOutputFormat mov_muxer = {
02185     "mov",
02186     NULL_IF_CONFIG_SMALL("MOV format"),
02187     NULL,
02188     "mov",
02189     sizeof(MOVMuxContext),
02190     CODEC_ID_AAC,
02191     CODEC_ID_MPEG4,
02192     mov_write_header,
02193     ff_mov_write_packet,
02194     mov_write_trailer,
02195     .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS,
02196     .codec_tag = (const AVCodecTag* const []){codec_movvideo_tags, codec_movaudio_tags, 0},
02197 };
02198 #endif
02199 #if CONFIG_TGP_MUXER
02200 AVOutputFormat tgp_muxer = {
02201     "3gp",
02202     NULL_IF_CONFIG_SMALL("3GP format"),
02203     NULL,
02204     "3gp",
02205     sizeof(MOVMuxContext),
02206     CODEC_ID_AMR_NB,
02207     CODEC_ID_H263,
02208     mov_write_header,
02209     ff_mov_write_packet,
02210     mov_write_trailer,
02211     .flags = AVFMT_GLOBALHEADER,
02212     .codec_tag = (const AVCodecTag* const []){codec_3gp_tags, 0},
02213 };
02214 #endif
02215 #if CONFIG_MP4_MUXER
02216 AVOutputFormat mp4_muxer = {
02217     "mp4",
02218     NULL_IF_CONFIG_SMALL("MP4 format"),
02219     "application/mp4",
02220     "mp4",
02221     sizeof(MOVMuxContext),
02222     CODEC_ID_AAC,
02223     CODEC_ID_MPEG4,
02224     mov_write_header,
02225     ff_mov_write_packet,
02226     mov_write_trailer,
02227     .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS,
02228     .codec_tag = (const AVCodecTag* const []){ff_mp4_obj_type, 0},
02229 };
02230 #endif
02231 #if CONFIG_PSP_MUXER
02232 AVOutputFormat psp_muxer = {
02233     "psp",
02234     NULL_IF_CONFIG_SMALL("PSP MP4 format"),
02235     NULL,
02236     "mp4,psp",
02237     sizeof(MOVMuxContext),
02238     CODEC_ID_AAC,
02239     CODEC_ID_MPEG4,
02240     mov_write_header,
02241     ff_mov_write_packet,
02242     mov_write_trailer,
02243     .flags = AVFMT_GLOBALHEADER,
02244     .codec_tag = (const AVCodecTag* const []){ff_mp4_obj_type, 0},
02245 };
02246 #endif
02247 #if CONFIG_TG2_MUXER
02248 AVOutputFormat tg2_muxer = {
02249     "3g2",
02250     NULL_IF_CONFIG_SMALL("3GP2 format"),
02251     NULL,
02252     "3g2",
02253     sizeof(MOVMuxContext),
02254     CODEC_ID_AMR_NB,
02255     CODEC_ID_H263,
02256     mov_write_header,
02257     ff_mov_write_packet,
02258     mov_write_trailer,
02259     .flags = AVFMT_GLOBALHEADER,
02260     .codec_tag = (const AVCodecTag* const []){codec_3gp_tags, 0},
02261 };
02262 #endif
02263 #if CONFIG_IPOD_MUXER
02264 AVOutputFormat ipod_muxer = {
02265     "ipod",
02266     NULL_IF_CONFIG_SMALL("iPod H.264 MP4 format"),
02267     "application/mp4",
02268     "m4v,m4a",
02269     sizeof(MOVMuxContext),
02270     CODEC_ID_AAC,
02271     CODEC_ID_H264,
02272     mov_write_header,
02273     ff_mov_write_packet,
02274     mov_write_trailer,
02275     .flags = AVFMT_GLOBALHEADER,
02276     .codec_tag = (const AVCodecTag* const []){codec_ipod_tags, 0},
02277 };
02278 #endif

Generated on Fri Sep 16 2011 17:17:49 for FFmpeg by  doxygen 1.7.1