📄 movenc.c
字号:
/* * MOV, 3GP, MP4 encoder. * Copyright (c) 2003 Thomas Raivio. * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>. * * This library 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 of the License, or (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "avformat.h"#include "avi.h"#include "avio.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 2typedef struct MOVIentry { unsigned int flags, pos, size; unsigned int samplesInChunk; char key_frame; unsigned int entries;} MOVIentry;typedef struct MOVIndex { int mode; int entry; int mdat_size; int ents_allocated; long timescale; long time; long trackDuration; long sampleCount; long sampleDuration; int hasKeyframes; int trackID; AVCodecContext *enc; int vosLen; uint8_t *vosData; MOVIentry** cluster;} MOVTrack;typedef struct { int mode; long time; int nb_streams; int mdat_written; offset_t mdat_pos; long timescale; MOVTrack tracks[MAX_STREAMS];} MOVContext;static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track);//FIXME supprt 64bit varaint with wide placeholdersstatic int updateSize (ByteIOContext *pb, int pos){ long 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 pos = url_ftell(pb); put_be32(pb, 0); /* size */ put_tag(pb, "stco"); put_be32(pb, 0); /* version & flags */ put_be32(pb, track->entry); /* entry count */ for (i=0; i<track->entry; i++) { int cl = i / MOV_INDEX_CLUSTER_SIZE; int id = i % MOV_INDEX_CLUSTER_SIZE; put_be32(pb, track->cluster[cl][id].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; int 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++) { int cl = i / MOV_INDEX_CLUSTER_SIZE; int id = i % MOV_INDEX_CLUSTER_SIZE; tst = track->cluster[cl][id].size/track->cluster[cl][id].entries; if(oldtst != -1 && tst != oldtst) { equalChunks = 0; } oldtst = tst; entries += track->cluster[cl][id].entries; } if (equalChunks) { int sSize = track->cluster[0][0].size/track->cluster[0][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++) { int cl = i / MOV_INDEX_CLUSTER_SIZE; int id = i % MOV_INDEX_CLUSTER_SIZE; for ( j=0; j<track->cluster[cl][id].entries; j++) { put_be32(pb, track->cluster[cl][id].size / track->cluster[cl][id].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, entryPos, curpos; int 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++) { int cl = i / MOV_INDEX_CLUSTER_SIZE; int id = i % MOV_INDEX_CLUSTER_SIZE; if(oldval != track->cluster[cl][id].samplesInChunk) { put_be32(pb, i+1); // first chunk put_be32(pb, track->cluster[cl][id].samplesInChunk); // samples per chunk put_be32(pb, 0x1); // sample description index oldval = track->cluster[cl][id].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){ long curpos; int i, index = 0, entryPos; int 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++) { int cl = i / MOV_INDEX_CLUSTER_SIZE; int id = i % MOV_INDEX_CLUSTER_SIZE; if(track->cluster[cl][id].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_damr_tag(ByteIOContext *pb){ put_be32(pb, 0x11); /* size */ put_tag(pb, "damr"); put_tag(pb, "FFMP"); put_byte(pb, 0); put_be16(pb, 0x80); /* Mode set (all modes for AMR_NB) */ put_be16(pb, 0xa); /* Mode change period (no restriction) */ //put_be16(pb, 0x81ff); /* Mode set (all modes for AMR_NB) */ //put_be16(pb, 1); /* Mode change period (no restriction) */ return 0x11;}static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack* track){ int pos = url_ftell(pb); put_be32(pb, 0); /* size */ put_tag(pb, "wave"); put_be32(pb, 12); /* size */ put_tag(pb, "frma"); put_tag(pb, "mp4a"); put_be32(pb, 12); /* size */ put_tag(pb, "mp4a"); put_be32(pb, 0); mov_write_esds_tag(pb, track); put_be32(pb, 12); /* size */ put_tag(pb, "srcq"); put_be32(pb, 0x40); put_be32(pb, 8); /* size */ put_be32(pb, 0); /* null tag */ return updateSize (pb, pos);}const CodecTag codec_movaudio_tags[] = { { CODEC_ID_PCM_MULAW, MKTAG('u', 'l', 'a', 'w') }, { CODEC_ID_PCM_ALAW, MKTAG('a', 'l', 'a', 'w') }, { CODEC_ID_ADPCM_IMA_QT, MKTAG('i', 'm', 'a', '4') }, { CODEC_ID_MACE3, MKTAG('M', 'A', 'C', '3') }, { CODEC_ID_MACE6, MKTAG('M', 'A', 'C', '6') }, { CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') }, { CODEC_ID_AMR_NB, MKTAG('s', 'a', 'm', 'r') }, { CODEC_ID_PCM_S16BE, MKTAG('t', 'w', 'o', 's') }, { CODEC_ID_PCM_S16LE, MKTAG('s', 'o', 'w', 't') }, { CODEC_ID_MP3, MKTAG('.', 'm', 'p', '3') }, { 0, 0 },};static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track){ int pos = url_ftell(pb), tag; put_be32(pb, 0); /* size */ tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id); // if no mac fcc found, try with Microsoft tags if (!tag) { int tmp = codec_get_tag(codec_wav_tags, track->enc->codec_id); if (tmp) tag = MKTAG('m', 's', ((tmp >> 8) & 0xff), (tmp & 0xff)); } if (!tag) put_tag(pb, " "); else put_le32(pb, tag); // store it byteswapped put_be32(pb, 0); /* Reserved */ put_be16(pb, 0); /* Reserved */ put_be16(pb, 1); /* Data-reference index, XXX == 1 */ /* SoundDescription */ if(track->mode == MODE_MOV && track->enc->codec_id == CODEC_ID_AAC) put_be16(pb, 1); /* Version 1 */ else put_be16(pb, 0); /* Version 0 */ put_be16(pb, 0); /* Revision level */ put_be32(pb, 0); /* Reserved */ put_be16(pb, track->enc->channels); /* Number of channels */ /* TODO: Currently hard-coded to 16-bit, there doesn't seem to be a good way to get number of bits of audio */ put_be16(pb, 0x10); /* Reserved */ put_be16(pb, 0); /* compression ID (= 0) */ put_be16(pb, 0); /* packet size (= 0) */ put_be16(pb, track->timescale); /* Time scale */ put_be16(pb, 0); /* Reserved */ if(track->mode == MODE_MOV && track->enc->codec_id == CODEC_ID_AAC) { /* SoundDescription V1 extended info */ put_be32(pb, track->enc->frame_size); /* Samples per packet */ put_be32(pb, 1536); /* Bytes per packet */ put_be32(pb, 2); /* Bytes per frame */ put_be32(pb, 2); /* Bytes per sample */ } if(track->enc->codec_id == CODEC_ID_AAC) { if( track->mode == MODE_MOV ) mov_write_wave_tag(pb, track); else mov_write_esds_tag(pb, track); } if(track->enc->codec_id == CODEC_ID_AMR_NB) mov_write_damr_tag(pb); 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_be16(pb, 0x0a); put_byte(pb, 0); 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 unsigned int descrLength(unsigned int len){ if (len < 0x00000080) return 2 + len; else if (len < 0x00004000) return 3 + len; else if(len < 0x00200000) return 4 + len; else return 5 + len;}static void putDescr(ByteIOContext *pb, int tag, int size){ uint32_t len; uint8_t vals[4]; len = size; vals[3] = (uint8_t)(len & 0x7f); len >>= 7; vals[2] = (uint8_t)((len & 0x7f) | 0x80); len >>= 7; vals[1] = (uint8_t)((len & 0x7f) | 0x80); len >>= 7; vals[0] = (uint8_t)((len & 0x7f) | 0x80); put_byte(pb, tag); // DescriptorTag if (size < 0x00000080) { put_byte(pb, vals[3]); } else if (size < 0x00004000) { put_byte(pb, vals[2]); put_byte(pb, vals[3]); } else if (size < 0x00200000) { put_byte(pb, vals[1]); put_byte(pb, vals[2]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -