⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 movenc.c

📁 mediastreamer2是开源的网络传输媒体流的库
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * MOV, 3GP, MP4 muxer * Copyright (c) 2003 Thomas Raivio. * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>. * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */#include "avformat.h"#include "riff.h"#include "avio.h"#include "isom.h"#include "avc.h"#undef NDEBUG#include <assert.h>#define MOV_INDEX_CLUSTER_SIZE 16384#define globalTimescale 1000#define MODE_MP4 0#define MODE_MOV 1#define MODE_3GP 2#define MODE_PSP 3 // example working PSP command line:// ffmpeg -i testinput.avi  -f psp -r 14.985 -s 320x240 -b 768 -ar 24000 -ab 32 M4V00001.MP4#define MODE_3G2 4typedef struct MOVIentry {    unsigned int flags, size;    uint64_t     pos;    unsigned int samplesInChunk;    char         key_frame;    unsigned int entries;    int64_t      cts;    int64_t      dts;} MOVIentry;typedef struct MOVIndex {    int         mode;    int         entry;    long        timescale;    long        time;    int64_t     trackDuration;    long        sampleCount;    long        sampleSize;    int         hasKeyframes;    int         hasBframes;    int         language;    int         trackID;    int         tag; ///< stsd fourcc    AVCodecContext *enc;    int         vosLen;    uint8_t     *vosData;    MOVIentry   *cluster;    int         audio_vbr;} MOVTrack;typedef struct MOVContext {    int     mode;    int64_t time;    int     nb_streams;    offset_t mdat_pos;    uint64_t mdat_size;    long    timescale;    MOVTrack tracks[MAX_STREAMS];} MOVContext;//FIXME support 64 bit variant with wide placeholdersstatic offset_t updateSize (ByteIOContext *pb, offset_t pos){    offset_t curpos = url_ftell(pb);    url_fseek(pb, pos, SEEK_SET);    put_be32(pb, curpos - pos); /* rewrite size */    url_fseek(pb, curpos, SEEK_SET);    return curpos - pos;}/* Chunk offset atom */static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack* track){    int i;    int mode64 = 0; //   use 32 bit size variant if possible    offset_t pos = url_ftell(pb);    put_be32(pb, 0); /* size */    if (pos > UINT32_MAX) {        mode64 = 1;        put_tag(pb, "co64");    } else        put_tag(pb, "stco");    put_be32(pb, 0); /* version & flags */    put_be32(pb, track->entry); /* entry count */    for (i=0; i<track->entry; i++) {        if(mode64 == 1)            put_be64(pb, track->cluster[i].pos);        else            put_be32(pb, track->cluster[i].pos);    }    return updateSize (pb, pos);}/* Sample size atom */static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track){    int equalChunks = 1;    int i, j, entries = 0, tst = -1, oldtst = -1;    offset_t pos = url_ftell(pb);    put_be32(pb, 0); /* size */    put_tag(pb, "stsz");    put_be32(pb, 0); /* version & flags */    for (i=0; i<track->entry; i++) {        tst = track->cluster[i].size/track->cluster[i].entries;        if(oldtst != -1 && tst != oldtst) {            equalChunks = 0;        }        oldtst = tst;        entries += track->cluster[i].entries;    }    if (equalChunks) {        int sSize = track->cluster[0].size/track->cluster[0].entries;        put_be32(pb, sSize); // sample size        put_be32(pb, entries); // sample count    }    else {        put_be32(pb, 0); // sample size        put_be32(pb, entries); // sample count        for (i=0; i<track->entry; i++) {            for (j=0; j<track->cluster[i].entries; j++) {                put_be32(pb, track->cluster[i].size /                         track->cluster[i].entries);            }        }    }    return updateSize (pb, pos);}/* Sample to chunk atom */static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track){    int index = 0, oldval = -1, i;    offset_t entryPos, curpos;    offset_t pos = url_ftell(pb);    put_be32(pb, 0); /* size */    put_tag(pb, "stsc");    put_be32(pb, 0); // version & flags    entryPos = url_ftell(pb);    put_be32(pb, track->entry); // entry count    for (i=0; i<track->entry; i++) {        if(oldval != track->cluster[i].samplesInChunk)        {            put_be32(pb, i+1); // first chunk            put_be32(pb, track->cluster[i].samplesInChunk); // samples per chunk            put_be32(pb, 0x1); // sample description index            oldval = track->cluster[i].samplesInChunk;            index++;        }    }    curpos = url_ftell(pb);    url_fseek(pb, entryPos, SEEK_SET);    put_be32(pb, index); // rewrite size    url_fseek(pb, curpos, SEEK_SET);    return updateSize (pb, pos);}/* Sync sample atom */static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack* track){    offset_t curpos, entryPos;    int i, index = 0;    offset_t pos = url_ftell(pb);    put_be32(pb, 0); // size    put_tag(pb, "stss");    put_be32(pb, 0); // version & flags    entryPos = url_ftell(pb);    put_be32(pb, track->entry); // entry count    for (i=0; i<track->entry; i++) {        if(track->cluster[i].key_frame == 1) {            put_be32(pb, i+1);            index++;        }    }    curpos = url_ftell(pb);    url_fseek(pb, entryPos, SEEK_SET);    put_be32(pb, index); // rewrite size    url_fseek(pb, curpos, SEEK_SET);    return updateSize (pb, pos);}static int mov_write_amr_tag(ByteIOContext *pb, MOVTrack *track){    put_be32(pb, 0x11); /* size */    if (track->mode == MODE_MOV) put_tag(pb, "samr");    else                         put_tag(pb, "damr");    put_tag(pb, "FFMP");    put_byte(pb, 0); /* decoder version */    put_be16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */    put_byte(pb, 0x00); /* Mode change period (no restriction) */    put_byte(pb, 0x01); /* Frames per sample */    return 0x11;}static int mov_write_enda_tag(ByteIOContext *pb){    put_be32(pb, 10);    put_tag(pb, "enda");    put_be16(pb, 1); /* little endian */    return 10;}static unsigned int descrLength(unsigned int len){    int i;    for(i=1; len>>(7*i); i++);    return len + 1 + i;}static void putDescr(ByteIOContext *pb, int tag, unsigned int size){    int i= descrLength(size) - size - 2;    put_byte(pb, tag);    for(; i>0; i--)        put_byte(pb, (size>>(7*i)) | 0x80);    put_byte(pb, size & 0x7F);}static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic{    offset_t pos = url_ftell(pb);    int decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0;    put_be32(pb, 0);               // size    put_tag(pb, "esds");    put_be32(pb, 0);               // Version    // ES descriptor    putDescr(pb, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) +             descrLength(1));    put_be16(pb, track->trackID);    put_byte(pb, 0x00);            // flags (= no flags)    // DecoderConfig descriptor    putDescr(pb, 0x04, 13 + decoderSpecificInfoLen);    // Object type indication    put_byte(pb, codec_get_tag(ff_mp4_obj_type, track->enc->codec_id));    // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)    // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)    if(track->enc->codec_type == CODEC_TYPE_AUDIO)        put_byte(pb, 0x15);            // flags (= Audiostream)    else        put_byte(pb, 0x11);            // flags (= Visualstream)    put_byte(pb,  track->enc->rc_buffer_size>>(3+16));             // Buffersize DB (24 bits)    put_be16(pb, (track->enc->rc_buffer_size>>3)&0xFFFF);          // Buffersize DB    put_be32(pb, FFMAX(track->enc->bit_rate, track->enc->rc_max_rate));     // maxbitrate  (FIXME should be max rate in any 1 sec window)    if(track->enc->rc_max_rate != track->enc->rc_min_rate || track->enc->rc_min_rate==0)        put_be32(pb, 0);     // vbr    else        put_be32(pb, track->enc->rc_max_rate);     // avg bitrate    if (track->vosLen)    {        // DecoderSpecific info descriptor        putDescr(pb, 0x05, track->vosLen);        put_buffer(pb, track->vosData, track->vosLen);    }    // SL descriptor    putDescr(pb, 0x06, 1);    put_byte(pb, 0x02);    return updateSize (pb, pos);}static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack* track){    offset_t pos = url_ftell(pb);    put_be32(pb, 0);     /* size */    put_tag(pb, "wave");    put_be32(pb, 12);    /* size */    put_tag(pb, "frma");    put_le32(pb, track->tag);    if (track->enc->codec_id == CODEC_ID_AAC) {        /* useless atom needed by mplayer, ipod, not needed by quicktime */        put_be32(pb, 12); /* size */        put_tag(pb, "mp4a");        put_be32(pb, 0);        mov_write_esds_tag(pb, track);    } else if (track->enc->codec_id == CODEC_ID_PCM_S24LE ||               track->enc->codec_id == CODEC_ID_PCM_S32LE) {        mov_write_enda_tag(pb);    } else if (track->enc->codec_id == CODEC_ID_AMR_NB) {        mov_write_amr_tag(pb, track);    }    put_be32(pb, 8);     /* size */    put_be32(pb, 0);     /* null tag */    return updateSize (pb, pos);}static int mov_write_glbl_tag(ByteIOContext *pb, MOVTrack* track){    put_be32(pb, track->vosLen+8);    put_tag(pb, "glbl");    put_buffer(pb, track->vosData, track->vosLen);    return 8+track->vosLen;}static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track){    offset_t pos = url_ftell(pb);    int version = track->mode == MODE_MOV &&        (track->audio_vbr ||         track->enc->codec_id == CODEC_ID_PCM_S32LE ||         track->enc->codec_id == CODEC_ID_PCM_S24LE);    put_be32(pb, 0); /* size */    put_le32(pb, track->tag); // store it byteswapped    put_be32(pb, 0); /* Reserved */    put_be16(pb, 0); /* Reserved */    put_be16(pb, 1); /* Data-reference index, XXX  == 1 */    /* SoundDescription */    put_be16(pb, version); /* Version */    put_be16(pb, 0); /* Revision level */    put_be32(pb, 0); /* Reserved */    if (track->mode == MODE_MOV) {        put_be16(pb, track->enc->channels);        if (track->enc->codec_id == CODEC_ID_PCM_U8 ||            track->enc->codec_id == CODEC_ID_PCM_S8)            put_be16(pb, 8); /* bits per sample */        else            put_be16(pb, 16);        put_be16(pb, track->audio_vbr ? -2 : 0); /* compression ID */    } else { /* reserved for mp4/3gp */        put_be16(pb, 2);        put_be16(pb, 16);        put_be16(pb, 0);    }    put_be16(pb, 0); /* packet size (= 0) */    put_be16(pb, track->timescale); /* Time scale */    put_be16(pb, 0); /* Reserved */    if(version == 1) { /* SoundDescription V1 extended info */        put_be32(pb, track->enc->frame_size); /* Samples per packet */        put_be32(pb, track->sampleSize / track->enc->channels); /* Bytes per packet */        put_be32(pb, track->sampleSize); /* Bytes per frame */        put_be32(pb, 2); /* Bytes per sample */    }    if(track->mode == MODE_MOV &&       (track->enc->codec_id == CODEC_ID_AAC ||        track->enc->codec_id == CODEC_ID_AMR_NB ||        track->enc->codec_id == CODEC_ID_PCM_S24LE ||        track->enc->codec_id == CODEC_ID_PCM_S32LE))        mov_write_wave_tag(pb, track);    else if(track->tag == MKTAG('m','p','4','a'))        mov_write_esds_tag(pb, track);    else if(track->enc->codec_id == CODEC_ID_AMR_NB)        mov_write_amr_tag(pb, track);    else if(track->vosLen > 0)        mov_write_glbl_tag(pb, track);    return updateSize (pb, pos);}static int mov_write_d263_tag(ByteIOContext *pb){    put_be32(pb, 0xf); /* size */    put_tag(pb, "d263");    put_tag(pb, "FFMP");    put_byte(pb, 0); /* decoder version */    /* FIXME use AVCodecContext level/profile, when encoder will set values */    put_byte(pb, 0xa); /* level */    put_byte(pb, 0); /* profile */    return 0xf;}/* TODO: No idea about these values */static int mov_write_svq3_tag(ByteIOContext *pb){    put_be32(pb, 0x15);    put_tag(pb, "SMI ");    put_tag(pb, "SEQH");    put_be32(pb, 0x5);    put_be32(pb, 0xe2c0211d);    put_be32(pb, 0xc0000000);    put_byte(pb, 0);    return 0x15;}static int mov_write_avcc_tag(ByteIOContext *pb, MOVTrack *track){    offset_t pos = url_ftell(pb);    put_be32(pb, 0);    put_tag(pb, "avcC");    ff_isom_write_avcc(pb, track->vosData, track->vosLen);    return updateSize(pb, pos);}/* also used by all avid codecs (dv, imx, meridien) and their variants */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -