movenc.c

来自「ffmpeg的完整源代码和作者自己写的文档。不但有在Linux的工程哦」· C语言 代码 · 共 1,708 行 · 第 1/4 页

C
1,708
字号

    return 32;
}

static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track)
{
    offset_t pos = url_ftell(pb);
    put_be32(pb, 0); /* size */
    put_tag(pb, "mdia");
    mov_write_mdhd_tag(pb, track);
    mov_write_hdlr_tag(pb, track);
    mov_write_minf_tag(pb, track);
    return updateSize(pb, pos);
}

static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track)
{
    int64_t duration = av_rescale_rnd(track->trackDuration, globalTimescale, track->timescale, AV_ROUND_UP);
    int version = duration < INT32_MAX ? 0 : 1;

    (version == 1) ? put_be32(pb, 104) : put_be32(pb, 92); /* size */
    put_tag(pb, "tkhd");
    put_byte(pb, version);
    put_be24(pb, 0xf); /* flags (track enabled) */
    if (version == 1) {
        put_be64(pb, track->time);
        put_be64(pb, track->time);
    } else {
        put_be32(pb, track->time); /* creation time */
        put_be32(pb, track->time); /* modification time */
    }
    put_be32(pb, track->trackID); /* track-id */
    put_be32(pb, 0); /* reserved */
    (version == 1) ? put_be64(pb, duration) : put_be32(pb, duration);

    put_be32(pb, 0); /* reserved */
    put_be32(pb, 0); /* reserved */
    put_be32(pb, 0x0); /* reserved (Layer & Alternate group) */
    /* Volume, only for audio */
    if(track->enc->codec_type == CODEC_TYPE_AUDIO)
        put_be16(pb, 0x0100);
    else
        put_be16(pb, 0);
    put_be16(pb, 0); /* reserved */

    /* Matrix structure */
    put_be32(pb, 0x00010000); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x00010000); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x40000000); /* reserved */

    /* Track width and height, for visual only */
    if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
        double sample_aspect_ratio = av_q2d(track->enc->sample_aspect_ratio);
        if( !sample_aspect_ratio ) sample_aspect_ratio = 1;
        put_be32(pb, sample_aspect_ratio * track->enc->width*0x10000);
        put_be32(pb, track->enc->height*0x10000);
    }
    else {
        put_be32(pb, 0);
        put_be32(pb, 0);
    }
    return 0x5c;
}

// This box seems important for the psp playback ... without it the movie seems to hang
static int mov_write_edts_tag(ByteIOContext *pb, MOVTrack *track)
{
    put_be32(pb, 0x24); /* size  */
    put_tag(pb, "edts");
    put_be32(pb, 0x1c); /* size  */
    put_tag(pb, "elst");
    put_be32(pb, 0x0);
    put_be32(pb, 0x1);

    put_be32(pb, av_rescale_rnd(track->trackDuration, globalTimescale, track->timescale, AV_ROUND_UP)); /* duration   ... doesn't seem to effect psp */

    put_be32(pb, track->cluster[0].cts); /* first pts is cts since dts is 0 */
    put_be32(pb, 0x00010000);
    return 0x24;
}

// goes at the end of each track!  ... Critical for PSP playback ("Incompatible data" without it)
static int mov_write_uuid_tag_psp(ByteIOContext *pb, MOVTrack *mov)
{
    put_be32(pb, 0x34); /* size ... reports as 28 in mp4box! */
    put_tag(pb, "uuid");
    put_tag(pb, "USMT");
    put_be32(pb, 0x21d24fce);
    put_be32(pb, 0xbb88695c);
    put_be32(pb, 0xfac9c740);
    put_be32(pb, 0x1c);     // another size here!
    put_tag(pb, "MTDT");
    put_be32(pb, 0x00010012);
    put_be32(pb, 0x0a);
    put_be32(pb, 0x55c40000);
    put_be32(pb, 0x1);
    put_be32(pb, 0x0);
    return 0x34;
}

static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track)
{
    offset_t pos = url_ftell(pb);
    put_be32(pb, 0); /* size */
    put_tag(pb, "trak");
    mov_write_tkhd_tag(pb, track);
    if (track->mode == MODE_PSP || track->hasBframes)
        mov_write_edts_tag(pb, track);  // PSP Movies require edts box
    mov_write_mdia_tag(pb, track);
    if (track->mode == MODE_PSP)
        mov_write_uuid_tag_psp(pb,track);  // PSP Movies require this uuid box
    return updateSize(pb, pos);
}

#if 0
/* TODO: Not sorted out, but not necessary either */
static int mov_write_iods_tag(ByteIOContext *pb, MOVContext *mov)
{
    put_be32(pb, 0x15); /* size */
    put_tag(pb, "iods");
    put_be32(pb, 0);    /* version & flags */
    put_be16(pb, 0x1007);
    put_byte(pb, 0);
    put_be16(pb, 0x4fff);
    put_be16(pb, 0xfffe);
    put_be16(pb, 0x01ff);
    return 0x15;
}
#endif

static int mov_write_mvhd_tag(ByteIOContext *pb, MOVContext *mov)
{
    int maxTrackID = 1, i;
    int64_t maxTrackLenTemp, maxTrackLen = 0;
    int version;

    for (i=0; i<mov->nb_streams; i++) {
        if(mov->tracks[i].entry > 0) {
            maxTrackLenTemp = av_rescale_rnd(mov->tracks[i].trackDuration, globalTimescale, mov->tracks[i].timescale, AV_ROUND_UP);
            if(maxTrackLen < maxTrackLenTemp)
                maxTrackLen = maxTrackLenTemp;
            if(maxTrackID < mov->tracks[i].trackID)
                maxTrackID = mov->tracks[i].trackID;
        }
    }

    version = maxTrackLen < UINT32_MAX ? 0 : 1;
    (version == 1) ? put_be32(pb, 120) : put_be32(pb, 108); /* size */
    put_tag(pb, "mvhd");
    put_byte(pb, version);
    put_be24(pb, 0); /* flags */
    if (version == 1) {
        put_be64(pb, mov->time);
        put_be64(pb, mov->time);
    } else {
        put_be32(pb, mov->time); /* creation time */
        put_be32(pb, mov->time); /* modification time */
    }
    put_be32(pb, mov->timescale); /* timescale */
    (version == 1) ? put_be64(pb, maxTrackLen) : put_be32(pb, maxTrackLen); /* duration of longest track */

    put_be32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
    put_be16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
    put_be16(pb, 0); /* reserved */
    put_be32(pb, 0); /* reserved */
    put_be32(pb, 0); /* reserved */

    /* Matrix structure */
    put_be32(pb, 0x00010000); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x00010000); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x40000000); /* reserved */

    put_be32(pb, 0); /* reserved (preview time) */
    put_be32(pb, 0); /* reserved (preview duration) */
    put_be32(pb, 0); /* reserved (poster time) */
    put_be32(pb, 0); /* reserved (selection time) */
    put_be32(pb, 0); /* reserved (selection duration) */
    put_be32(pb, 0); /* reserved (current time) */
    put_be32(pb, maxTrackID+1); /* Next track id */
    return 0x6c;
}

static int mov_write_itunes_hdlr_tag(ByteIOContext *pb, MOVContext* mov,
                                     AVFormatContext *s)
{
    offset_t pos = url_ftell(pb);
    put_be32(pb, 0); /* size */
    put_tag(pb, "hdlr");
    put_be32(pb, 0);
    put_be32(pb, 0);
    put_tag(pb, "mdir");
    put_tag(pb, "appl");
    put_be32(pb, 0);
    put_be32(pb, 0);
    put_be16(pb, 0);
    return updateSize(pb, pos);
}

/* helper function to write a data tag with the specified string as data */
static int mov_write_string_data_tag(ByteIOContext *pb, const char *data, int long_style)
{
    if(long_style){
        offset_t pos = url_ftell(pb);
        put_be32(pb, 0); /* size */
        put_tag(pb, "data");
        put_be32(pb, 1);
        put_be32(pb, 0);
        put_buffer(pb, data, strlen(data));
        return updateSize(pb, pos);
    }else{
        put_be16(pb, strlen(data)); /* string length */
        put_be16(pb, 0);
        put_buffer(pb, data, strlen(data));
        return strlen(data) + 4;
    }
}

static int mov_write_string_tag(ByteIOContext *pb, const char *name, const char *value, int long_style){
    int size = 0;
    if ( value && value[0] ) {
        offset_t pos = url_ftell(pb);
        put_be32(pb, 0); /* size */
        put_tag(pb, name);
        mov_write_string_data_tag(pb, value, long_style);
        size= updateSize(pb, pos);
    }
    return size;
}

/* iTunes year */
static int mov_write_day_tag(ByteIOContext *pb, int year, int long_style)
{
    if(year){
        char year_str[5];
        snprintf(year_str, sizeof(year_str), "%04d", year);
        return mov_write_string_tag(pb, "\251day", year_str, long_style);
    }else
        return 0;
}

/* iTunes track number */
static int mov_write_trkn_tag(ByteIOContext *pb, MOVContext* mov,
                              AVFormatContext *s)
{
    int size = 0;
    if ( s->track ) {
        offset_t pos = url_ftell(pb);
        put_be32(pb, 0); /* size */
        put_tag(pb, "trkn");
        {
            offset_t pos = url_ftell(pb);
            put_be32(pb, 0); /* size */
            put_tag(pb, "data");
            put_be32(pb, 0);        // 8 bytes empty
            put_be32(pb, 0);
            put_be16(pb, 0);        // empty
            put_be16(pb, s->track); // track number
            put_be16(pb, 0);        // total track number
            put_be16(pb, 0);        // empty
            updateSize(pb, pos);
        }
        size = updateSize(pb, pos);
    }
    return size;
}

/* iTunes meta data list */
static int mov_write_ilst_tag(ByteIOContext *pb, MOVContext* mov,
                              AVFormatContext *s)
{
    offset_t pos = url_ftell(pb);
    put_be32(pb, 0); /* size */
    put_tag(pb, "ilst");
    mov_write_string_tag(pb, "\251nam", s->title         , 1);
    mov_write_string_tag(pb, "\251ART", s->author        , 1);
    mov_write_string_tag(pb, "\251wrt", s->author        , 1);
    mov_write_string_tag(pb, "\251alb", s->album         , 1);
    mov_write_day_tag(pb, s->year ,1);
    if(mov->tracks[0].enc && !(mov->tracks[0].enc->flags & CODEC_FLAG_BITEXACT))
        mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 1);
    mov_write_string_tag(pb, "\251cmt", s->comment       , 1);
    mov_write_string_tag(pb, "\251gen", s->genre         , 1);
    mov_write_trkn_tag(pb, mov, s);
    return updateSize(pb, pos);
}

/* iTunes meta data tag */
static int mov_write_meta_tag(ByteIOContext *pb, MOVContext* mov,
                              AVFormatContext *s)
{
    int size = 0;

    // only save meta tag if required
    if ( s->title[0] || s->author[0] || s->album[0] || s->year ||
         s->comment[0] || s->genre[0] || s->track ) {
        offset_t pos = url_ftell(pb);
        put_be32(pb, 0); /* size */
        put_tag(pb, "meta");
        put_be32(pb, 0);
        mov_write_itunes_hdlr_tag(pb, mov, s);
        mov_write_ilst_tag(pb, mov, s);
        size = updateSize(pb, pos);
    }
    return size;
}

static int mov_write_udta_tag(ByteIOContext *pb, MOVContext* mov,
                              AVFormatContext *s)
{
    offset_t pos = url_ftell(pb);
    int i;

    put_be32(pb, 0); /* size */
    put_tag(pb, "udta");

    /* iTunes meta data */
    mov_write_meta_tag(pb, mov, s);

  if(mov->mode == MODE_MOV){ // the title field breaks gtkpod with mp4 and my suspicion is that stuff is not valid in mp4
    /* Requirements */
    for (i=0; i<mov->nb_streams; i++) {
        if(mov->tracks[i].entry <= 0) continue;
        if (mov->tracks[i].enc->codec_id == CODEC_ID_AAC ||
            mov->tracks[i].enc->codec_id == CODEC_ID_MPEG4) {
            mov_write_string_tag(pb, "\251req", "QuickTime 6.0 or greater", 0);
            break;
        }
    }

    mov_write_string_tag(pb, "\251nam", s->title         , 0);
    mov_write_string_tag(pb, "\251aut", s->author        , 0);
    mov_write_string_tag(pb, "\251alb", s->album         , 0);
    mov_write_day_tag(pb, s->year, 0);
    if(mov->tracks[0].enc && !(mov->tracks[0].enc->flags & CODEC_FLAG_BITEXACT))
        mov_write_string_tag(pb, "\251enc", LIBAVFORMAT_IDENT, 0);
    mov_write_string_tag(pb, "\251des", s->comment       , 0);
    mov_write_string_tag(pb, "\251gen", s->genre         , 0);
  }

    return updateSize(pb, pos);
}

static int utf8len(uint8_t *b){
    int len=0;
    int val;
    while(*b){
        GET_UTF8(val, *b++, return -1;)
        len++;
    }
    return len;
}

static int ascii_to_wc (ByteIOContext *pb, uint8_t *b)
{
    int val;
    while(*b){
        GET_UTF8(val, *b++, return -1;)
        put_be16(pb, val);
    }
    put_be16(pb, 0x00);
    return 0;
}

static uint16_t language_code (const char *str)
{
    return ((((str[0]-0x60) & 0x1F)<<10) + (((str[1]-0x60) & 0x1F)<<5) + ((str[2]-0x60) & 0x1F));
}

static int mov_write_uuidusmt_tag (ByteIOContext *pb, AVFormatContext *s)
{
    size_t len, size;
    offset_t pos, curpos;

    size = 0;
    if (s->title[0]) {
        pos = url_ftell(pb);
        put_be32(pb, 0); /* size placeholder*/
        put_tag(pb, "uuid");
        put_tag(pb, "USMT");
        put_be32(pb, 0x21d24fce ); /* 96 bit UUID */
        put_be32(pb, 0xbb88695c );
        put_be32(pb, 0xfac9c740 );
        size += 24;

        put_be32(pb, 0); /* size placeholder*/
        put_tag(pb, "MTDT");
        put_be16(pb, 4);
        size += 10;

        // ?
        put_be16(pb, 0x0C);                 /* size */
        put_be32(pb, 0x0B);                 /* type */
        put_be16(pb, language_code("und")); /* language */
        put_be16(pb, 0x0);                  /* ? */
        put_be16(pb, 0x021C);               /* data */
        size += 12;

        // Encoder
        len = utf8len(LIBAVCODEC_IDENT)+1;
        if(len<=0)
            goto not_utf8;
        put_be16(pb, len*2+10);             /* size */
        put_be32(pb, 0x04);                 /* type */
        put_be16(pb, language_code("eng")); /* language */
        put_be16(pb, 0x01);                 /* ? */
        ascii_to_wc(pb, LIBAVCODEC_IDENT);
        size += len*2+10;

        // Title
        len = utf8len(s->title)+1;
        if(len<=0)
            goto not_utf8;
        put_be16(pb, len*2+10);             /* size */
        put_be32(pb, 0x01);                 /* type */
        put_be16(pb, language_code("eng")); /* language */

⌨️ 快捷键说明

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