📄 movenc.c
字号:
static int mov_write_avid_tag(ByteIOContext *pb, MOVTrack *track){ int i; put_be32(pb, 24); /* size */ put_tag(pb, "ACLR"); put_tag(pb, "ACLR"); put_tag(pb, "0001"); put_be32(pb, 1); /* yuv 1 / rgb 2 ? */ put_be32(pb, 0); /* unknown */ put_be32(pb, 24); /* size */ put_tag(pb, "APRG"); put_tag(pb, "APRG"); put_tag(pb, "0001"); put_be32(pb, 1); /* unknown */ put_be32(pb, 0); /* unknown */ put_be32(pb, 120); /* size */ put_tag(pb, "ARES"); put_tag(pb, "ARES"); put_tag(pb, "0001"); put_be32(pb, AV_RB32(track->vosData + 0x28)); /* dnxhd cid, some id ? */ put_be32(pb, track->enc->width); /* values below are based on samples created with quicktime and avid codecs */ if (track->vosData[5] & 2) { // interlaced put_be32(pb, track->enc->height/2); put_be32(pb, 2); /* unknown */ put_be32(pb, 0); /* unknown */ put_be32(pb, 4); /* unknown */ } else { put_be32(pb, track->enc->height); put_be32(pb, 1); /* unknown */ put_be32(pb, 0); /* unknown */ if (track->enc->height == 1080) put_be32(pb, 5); /* unknown */ else put_be32(pb, 6); /* unknown */ } /* padding */ for (i = 0; i < 10; i++) put_be64(pb, 0); /* extra padding for stsd needed */ put_be32(pb, 0); return 0;}static const AVCodecTag codec_3gp_tags[] = { { CODEC_ID_H263, MKTAG('s','2','6','3') }, { CODEC_ID_H264, MKTAG('a','v','c','1') }, { CODEC_ID_MPEG4, MKTAG('m','p','4','v') }, { CODEC_ID_AAC, MKTAG('m','p','4','a') }, { CODEC_ID_AMR_NB, MKTAG('s','a','m','r') }, { CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },};static const AVCodecTag mov_pix_fmt_tags[] = { { PIX_FMT_YUYV422, MKTAG('y','u','v','s') }, { PIX_FMT_UYVY422, MKTAG('2','v','u','y') }, { PIX_FMT_BGR555, MKTAG('r','a','w',' ') }, { PIX_FMT_RGB24, MKTAG('r','a','w',' ') }, { PIX_FMT_BGR32_1, MKTAG('r','a','w',' ') },};static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track){ int tag = track->enc->codec_tag; if (track->mode == MODE_MP4 || track->mode == MODE_PSP) { if (!codec_get_tag(ff_mp4_obj_type, track->enc->codec_id)) return 0; if (track->enc->codec_id == CODEC_ID_H264) tag = MKTAG('a','v','c','1'); else if (track->enc->codec_type == CODEC_TYPE_VIDEO) tag = MKTAG('m','p','4','v'); else if (track->enc->codec_type == CODEC_TYPE_AUDIO) tag = MKTAG('m','p','4','a'); } else if (track->mode == MODE_3GP || track->mode == MODE_3G2) { tag = codec_get_tag(codec_3gp_tags, track->enc->codec_id); } else if (!tag || (track->enc->strict_std_compliance >= FF_COMPLIANCE_NORMAL && (tag == MKTAG('d','v','c','p') || track->enc->codec_id == CODEC_ID_RAWVIDEO))) { 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 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_RAWVIDEO) { tag = codec_get_tag(mov_pix_fmt_tags, track->enc->pix_fmt); if (!tag) // restore tag tag = track->enc->codec_tag; } else { if (track->enc->codec_type == CODEC_TYPE_VIDEO) { tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id); if (!tag) { // if no mac fcc found, try with Microsoft tags 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"); } } else if (track->enc->codec_type == CODEC_TYPE_AUDIO) { tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id); if (!tag) { // if no mac fcc found, try with Microsoft tags 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"); } } } } } 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); if (track->mode == MODE_MOV && track->enc->bits_per_sample) put_be16(pb, track->enc->bits_per_sample); else put_be16(pb, 0x18); /* Reserved */ put_be16(pb, 0xffff); /* Reserved */ if(track->tag == MKTAG('m','p','4','v')) 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); else if(track->enc->codec_id == CODEC_ID_DNXHD) mov_write_avid_tag(pb, track); else if(track->vosLen > 0) mov_write_glbl_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"); } 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 {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -