movenc.c
来自「ffmpeg的完整源代码和作者自己写的文档。不但有在Linux的工程哦」· C语言 代码 · 共 1,708 行 · 第 1/4 页
C
1,708 行
if( p[3] == 0 ) {
if( p[2] == 0 && p[4] == 1 )
return p+1;
if( p[4] == 0 && p[5] == 1 )
return p+2;
}
}
}
for( end += 3; p < end; p++ ) {
if( p[0] == 0 && p[1] == 0 && p[2] == 1 )
return p;
}
return end + 3;
}
static void avc_parse_nal_units(uint8_t **buf, int *size)
{
ByteIOContext pb;
uint8_t *p = *buf;
uint8_t *end = p + *size;
uint8_t *nal_start, *nal_end;
url_open_dyn_buf(&pb);
nal_start = avc_find_startcode(p, end);
while (nal_start < end) {
while(!*(nal_start++));
nal_end = avc_find_startcode(nal_start, end);
put_be32(&pb, nal_end - nal_start);
put_buffer(&pb, nal_start, nal_end - nal_start);
nal_start = nal_end;
}
av_freep(buf);
*size = url_close_dyn_buf(&pb, buf);
}
static int mov_write_avcc_tag(ByteIOContext *pb, MOVTrack *track)
{
offset_t pos = url_ftell(pb);
put_be32(pb, 0);
put_tag(pb, "avcC");
if (track->vosLen > 6) {
/* check for h264 start code */
if (AV_RB32(track->vosData) == 0x00000001) {
uint8_t *buf, *end;
uint32_t sps_size=0, pps_size=0;
uint8_t *sps=0, *pps=0;
avc_parse_nal_units(&track->vosData, &track->vosLen);
buf = track->vosData;
end = track->vosData + track->vosLen;
/* look for sps and pps */
while (buf < end) {
unsigned int size;
uint8_t nal_type;
size = AV_RB32(buf);
nal_type = buf[4] & 0x1f;
if (nal_type == 7) { /* SPS */
sps = buf + 4;
sps_size = size;
} else if (nal_type == 8) { /* PPS */
pps = buf + 4;
pps_size = size;
}
buf += size + 4;
}
assert(sps);
assert(pps);
put_byte(pb, 1); /* version */
put_byte(pb, sps[1]); /* profile */
put_byte(pb, sps[2]); /* profile compat */
put_byte(pb, sps[3]); /* level */
put_byte(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */
put_byte(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */
put_be16(pb, sps_size);
put_buffer(pb, sps, sps_size);
put_byte(pb, 1); /* number of pps */
put_be16(pb, pps_size);
put_buffer(pb, pps, pps_size);
} else {
put_buffer(pb, track->vosData, track->vosLen);
}
}
return updateSize(pb, pos);
}
static int mov_find_video_codec_tag(AVFormatContext *s, MOVTrack *track)
{
int tag = track->enc->codec_tag;
if (!tag) {
if (track->enc->codec_id == CODEC_ID_DVVIDEO) {
if (track->enc->height == 480) { /* NTSC */
if (track->enc->pix_fmt == PIX_FMT_YUV422P)
tag = MKTAG('d', 'v', '5', 'n');
else
tag = MKTAG('d', 'v', 'c', ' ');
} else { /* assume PAL */
if (track->enc->pix_fmt == PIX_FMT_YUV422P)
tag = MKTAG('d', 'v', '5', 'p');
else if (track->enc->pix_fmt == PIX_FMT_YUV420P)
tag = MKTAG('d', 'v', 'c', 'p');
else
tag = MKTAG('d', 'v', 'p', 'p');
}
} else if (track->enc->codec_id == CODEC_ID_H263) {
if (track->mode == MODE_MOV)
tag = MKTAG('h', '2', '6', '3');
else
tag = MKTAG('s', '2', '6', '3');
} else {
tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
}
}
// if no mac fcc found, try with Microsoft tags
if (!tag) {
tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id);
if (tag) {
av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, the file may be unplayable!\n");
}
}
assert(tag);
return tag;
}
static int mov_find_audio_codec_tag(AVFormatContext *s, MOVTrack *track)
{
int tag = track->enc->codec_tag;
if (!tag) {
tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
}
// if no mac fcc found, try with Microsoft tags
if (!tag) {
int ms_tag = codec_get_tag(codec_wav_tags, track->enc->codec_id);
if (ms_tag) {
tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
av_log(s, AV_LOG_INFO, "Warning, using MS style audio codec tag, the file may be unplayable!\n");
}
}
assert(tag);
return tag;
}
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track)
{
offset_t pos = url_ftell(pb);
char compressor_name[32];
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 */
put_be16(pb, 0); /* Codec stream version */
put_be16(pb, 0); /* Codec stream revision (=0) */
if (track->mode == MODE_MOV) {
put_tag(pb, "FFMP"); /* Vendor */
if(track->enc->codec_id == CODEC_ID_RAWVIDEO) {
put_be32(pb, 0); /* Temporal Quality */
put_be32(pb, 0x400); /* Spatial Quality = lossless*/
} else {
put_be32(pb, 0x200); /* Temporal Quality = normal */
put_be32(pb, 0x200); /* Spatial Quality = normal */
}
} else {
put_be32(pb, 0); /* Reserved */
put_be32(pb, 0); /* Reserved */
put_be32(pb, 0); /* Reserved */
}
put_be16(pb, track->enc->width); /* Video width */
put_be16(pb, track->enc->height); /* Video height */
put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */
put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */
put_be32(pb, 0); /* Data size (= 0) */
put_be16(pb, 1); /* Frame count (= 1) */
memset(compressor_name,0,32);
/* FIXME not sure, ISO 14496-1 draft where it shall be set to 0 */
if (track->mode == MODE_MOV && track->enc->codec && track->enc->codec->name)
strncpy(compressor_name,track->enc->codec->name,31);
put_byte(pb, strlen(compressor_name));
put_buffer(pb, compressor_name, 31);
put_be16(pb, 0x18); /* Reserved */
put_be16(pb, 0xffff); /* Reserved */
if(track->enc->codec_id == CODEC_ID_MPEG4)
mov_write_esds_tag(pb, track);
else if(track->enc->codec_id == CODEC_ID_H263)
mov_write_d263_tag(pb);
else if(track->enc->codec_id == CODEC_ID_SVQ3)
mov_write_svq3_tag(pb);
else if(track->enc->codec_id == CODEC_ID_H264)
mov_write_avcc_tag(pb, track);
return updateSize (pb, pos);
}
static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track)
{
offset_t pos = url_ftell(pb);
put_be32(pb, 0); /* size */
put_tag(pb, "stsd");
put_be32(pb, 0); /* version & flags */
put_be32(pb, 1); /* entry count */
if (track->enc->codec_type == CODEC_TYPE_VIDEO)
mov_write_video_tag(pb, track);
else if (track->enc->codec_type == CODEC_TYPE_AUDIO)
mov_write_audio_tag(pb, track);
return updateSize(pb, pos);
}
static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack* track)
{
MOV_stts_t *ctts_entries;
uint32_t entries = 0;
uint32_t atom_size;
int i;
ctts_entries = av_malloc((track->entry + 1) * sizeof(*ctts_entries)); /* worst case */
ctts_entries[0].count = 1;
ctts_entries[0].duration = track->cluster[0].cts;
for (i=1; i<track->entry; i++) {
if (track->cluster[i].cts == ctts_entries[entries].duration) {
ctts_entries[entries].count++; /* compress */
} else {
entries++;
ctts_entries[entries].duration = track->cluster[i].cts;
ctts_entries[entries].count = 1;
}
}
entries++; /* last one */
atom_size = 16 + (entries * 8);
put_be32(pb, atom_size); /* size */
put_tag(pb, "ctts");
put_be32(pb, 0); /* version & flags */
put_be32(pb, entries); /* entry count */
for (i=0; i<entries; i++) {
put_be32(pb, ctts_entries[i].count);
put_be32(pb, ctts_entries[i].duration);
}
av_free(ctts_entries);
return atom_size;
}
/* Time to sample atom */
static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
{
MOV_stts_t *stts_entries;
uint32_t entries = -1;
uint32_t atom_size;
int i;
if (track->enc->codec_type == CODEC_TYPE_AUDIO && !track->audio_vbr) {
stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
stts_entries[0].count = track->sampleCount;
stts_entries[0].duration = 1;
entries = 1;
} else {
stts_entries = av_malloc(track->entry * sizeof(*stts_entries)); /* worst case */
for (i=0; i<track->entry; i++) {
int64_t duration = i + 1 == track->entry ?
track->trackDuration - track->cluster[i].dts + track->cluster[0].dts : /* readjusting */
track->cluster[i+1].dts - track->cluster[i].dts;
if (i && duration == stts_entries[entries].duration) {
stts_entries[entries].count++; /* compress */
} else {
entries++;
stts_entries[entries].duration = duration;
stts_entries[entries].count = 1;
}
}
entries++; /* last one */
}
atom_size = 16 + (entries * 8);
put_be32(pb, atom_size); /* size */
put_tag(pb, "stts");
put_be32(pb, 0); /* version & flags */
put_be32(pb, entries); /* entry count */
for (i=0; i<entries; i++) {
put_be32(pb, stts_entries[i].count);
put_be32(pb, stts_entries[i].duration);
}
av_free(stts_entries);
return atom_size;
}
static int mov_write_dref_tag(ByteIOContext *pb)
{
put_be32(pb, 28); /* size */
put_tag(pb, "dref");
put_be32(pb, 0); /* version & flags */
put_be32(pb, 1); /* entry count */
put_be32(pb, 0xc); /* size */
put_tag(pb, "url ");
put_be32(pb, 1); /* version & flags */
return 28;
}
static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track)
{
offset_t pos = url_ftell(pb);
put_be32(pb, 0); /* size */
put_tag(pb, "stbl");
mov_write_stsd_tag(pb, track);
mov_write_stts_tag(pb, track);
if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
track->hasKeyframes < track->entry)
mov_write_stss_tag(pb, track);
if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
track->hasBframes)
mov_write_ctts_tag(pb, track);
mov_write_stsc_tag(pb, track);
mov_write_stsz_tag(pb, track);
mov_write_stco_tag(pb, track);
return updateSize(pb, pos);
}
static int mov_write_dinf_tag(ByteIOContext *pb)
{
offset_t pos = url_ftell(pb);
put_be32(pb, 0); /* size */
put_tag(pb, "dinf");
mov_write_dref_tag(pb);
return updateSize(pb, pos);
}
static int mov_write_smhd_tag(ByteIOContext *pb)
{
put_be32(pb, 16); /* size */
put_tag(pb, "smhd");
put_be32(pb, 0); /* version & flags */
put_be16(pb, 0); /* reserved (balance, normally = 0) */
put_be16(pb, 0); /* reserved */
return 16;
}
static int mov_write_vmhd_tag(ByteIOContext *pb)
{
put_be32(pb, 0x14); /* size (always 0x14) */
put_tag(pb, "vmhd");
put_be32(pb, 0x01); /* version & flags */
put_be64(pb, 0); /* reserved (graphics mode = copy) */
return 0x14;
}
static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track)
{
const char *descr, *hdlr, *hdlr_type;
offset_t pos = url_ftell(pb);
if (!track) { /* no media --> data handler */
hdlr = "dhlr";
hdlr_type = "url ";
descr = "DataHandler";
} else {
hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
hdlr_type = "vide";
descr = "VideoHandler";
} else {
hdlr_type = "soun";
descr = "SoundHandler";
}
}
put_be32(pb, 0); /* size */
put_tag(pb, "hdlr");
put_be32(pb, 0); /* Version & flags */
put_buffer(pb, hdlr, 4); /* handler */
put_tag(pb, hdlr_type); /* handler type */
put_be32(pb ,0); /* reserved */
put_be32(pb ,0); /* reserved */
put_be32(pb ,0); /* reserved */
put_byte(pb, strlen(descr)); /* string counter */
put_buffer(pb, descr, strlen(descr)); /* handler description */
return updateSize(pb, pos);
}
static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack* track)
{
offset_t pos = url_ftell(pb);
put_be32(pb, 0); /* size */
put_tag(pb, "minf");
if(track->enc->codec_type == CODEC_TYPE_VIDEO)
mov_write_vmhd_tag(pb);
else
mov_write_smhd_tag(pb);
if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */
mov_write_hdlr_tag(pb, NULL);
mov_write_dinf_tag(pb);
mov_write_stbl_tag(pb, track);
return updateSize(pb, pos);
}
static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track)
{
int version = track->trackDuration < INT32_MAX ? 0 : 1;
(version == 1) ? put_be32(pb, 44) : put_be32(pb, 32); /* size */
put_tag(pb, "mdhd");
put_byte(pb, version);
put_be24(pb, 0); /* flags */
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->timescale); /* time scale (sample rate for audio) */
(version == 1) ? put_be64(pb, track->trackDuration) : put_be32(pb, track->trackDuration); /* duration */
put_be16(pb, track->language); /* language */
put_be16(pb, 0); /* reserved (quality) */
if(version!=0 && track->mode == MODE_MOV){
av_log(NULL, AV_LOG_ERROR,
"FATAL error, file duration too long for timebase, this file will not be\n"
"playable with quicktime. Choose a different timebase or a different\n"
"container format\n");
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?