📄 movenc.c
字号:
track->hasKeyframes) mov_write_stss_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){ int 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_minf_tag(ByteIOContext *pb, MOVTrack* track){ int 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); mov_write_dinf_tag(pb); mov_write_stbl_tag(pb, track); return updateSize(pb, pos);}static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track){ char *str; int pos = url_ftell(pb); put_be32(pb, 0); /* size */ put_tag(pb, "hdlr"); put_be32(pb, 0); /* Version & flags */ put_be32(pb, 0); /* reserved */ if(track->enc->codec_type == CODEC_TYPE_VIDEO) put_tag(pb, "vide"); /* handler type */ else put_tag(pb, "soun"); /* handler type */ put_be32(pb ,0); /* reserved */ put_be32(pb ,0); /* reserved */ put_be32(pb ,0); /* reserved */ if(track->enc->codec_type == CODEC_TYPE_VIDEO) str = "VideoHandler"; else str = "SoundHandler"; put_byte(pb, strlen(str)); /* string counter */ put_buffer(pb, str, strlen(str)); return updateSize(pb, pos);}static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track){ put_be32(pb, 32); /* size */ put_tag(pb, "mdhd"); put_be32(pb, 0); /* Version & flags */ 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) */ put_be32(pb, track->trackDuration); /* duration */ put_be16(pb, 0); /* language, 0 = english */ put_be16(pb, 0); /* reserved (quality) */ return 32;}static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track){ int 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 maxTrackLenTemp; put_be32(pb, 0x5c); /* size (always 0x5c) */ put_tag(pb, "tkhd"); put_be32(pb, 0xf); /* version & flags (track enabled) */ 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 */ maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)track->trackDuration)/(int64_t)track->timescale; put_be32(pb, (long)maxTrackLenTemp); /* 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) { put_be32(pb, track->enc->width*0x10000); put_be32(pb, track->enc->height*0x10000); } else { put_be32(pb, 0); put_be32(pb, 0); } return 0x5c;}static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track){ int pos = url_ftell(pb); put_be32(pb, 0); /* size */ put_tag(pb, "trak"); mov_write_tkhd_tag(pb, track); mov_write_mdia_tag(pb, track); return updateSize(pb, pos);}/* 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;}static int mov_write_mvhd_tag(ByteIOContext *pb, MOVContext *mov){ int maxTrackID = 1, maxTrackLen = 0, i; int64_t maxTrackLenTemp; put_be32(pb, 0x6c); /* size (always 0x6c) */ put_tag(pb, "mvhd"); put_be32(pb, 0); /* version & flags */ put_be32(pb, mov->time); /* creation time */ put_be32(pb, mov->time); /* modification time */ put_be32(pb, mov->timescale); /* timescale */ for (i=0; i<MAX_STREAMS; i++) { if(mov->tracks[i].entry > 0) { maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)mov->tracks[i].trackDuration)/(int64_t)mov->tracks[i].timescale; if(maxTrackLen < maxTrackLenTemp) maxTrackLen = maxTrackLenTemp; if(maxTrackID < mov->tracks[i].trackID) maxTrackID = mov->tracks[i].trackID; } } 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_moov_tag(ByteIOContext *pb, MOVContext *mov){ int pos, i; pos = url_ftell(pb); put_be32(pb, 0); /* size placeholder*/ put_tag(pb, "moov"); mov->timescale = globalTimescale; for (i=0; i<MAX_STREAMS; i++) { if(mov->tracks[i].entry <= 0) continue; if(mov->tracks[i].enc->codec_type == CODEC_TYPE_VIDEO) { mov->tracks[i].timescale = mov->tracks[i].enc->frame_rate; mov->tracks[i].sampleDuration = mov->tracks[i].enc->frame_rate_base; } else if(mov->tracks[i].enc->codec_type == CODEC_TYPE_AUDIO) { /* If AMR, track timescale = 8000, AMR_WB = 16000 */ if(mov->tracks[i].enc->codec_id == CODEC_ID_AMR_NB) { mov->tracks[i].sampleDuration = 160; // Bytes per chunk mov->tracks[i].timescale = 8000; } else { mov->tracks[i].timescale = mov->tracks[i].enc->sample_rate; mov->tracks[i].sampleDuration = mov->tracks[i].enc->frame_size; } } mov->tracks[i].trackDuration = mov->tracks[i].sampleCount * mov->tracks[i].sampleDuration; mov->tracks[i].time = mov->time; mov->tracks[i].trackID = i+1; } mov_write_mvhd_tag(pb, mov); //mov_write_iods_tag(pb, mov); for (i=0; i<MAX_STREAMS; i++) { if(mov->tracks[i].entry > 0) { mov_write_trak_tag(pb, &(mov->tracks[i])); } } return updateSize(pb, pos);}int mov_write_mdat_tag(ByteIOContext *pb, MOVContext* mov){ mov->mdat_pos = url_ftell(pb); put_be32(pb, 0); /* size placeholder*/ put_tag(pb, "mdat"); return 0;}/* TODO: This needs to be more general */int mov_write_ftyp_tag(ByteIOContext *pb, AVFormatContext *s){ put_be32(pb, 0x14 ); /* size */ put_tag(pb, "ftyp"); if (!strcmp("3gp", s->oformat->name)) put_tag(pb, "3gp4"); else put_tag(pb, "isom"); put_be32(pb, 0x200 ); if (!strcmp("3gp", s->oformat->name)) put_tag(pb, "3gp4"); else put_tag(pb, "mp41"); return 0x14;}static int mov_write_header(AVFormatContext *s){ ByteIOContext *pb = &s->pb; if(s->oformat != NULL) { if(!strcmp("3gp", s->oformat->name) || !strcmp("mp4", s->oformat->name)) mov_write_ftyp_tag(pb,s); } put_flush_packet(pb); return 0;}static int Timestamp() { return 1067949799U+(24107*86400); //its the modification time of this line :)}static int mov_write_packet(AVFormatContext *s, int stream_index, const uint8_t *buf, int size, int64_t pts){ MOVContext *mov = s->priv_data; ByteIOContext *pb = &s->pb; AVCodecContext *enc = &s->streams[stream_index]->codec; MOVTrack* trk = &mov->tracks[stream_index]; int cl, id; unsigned int samplesInChunk = 0; if (url_is_streamed(&s->pb)) return 0; /* Can't handle that */ if (!size) return 0; /* Discard 0 sized packets */ if (enc->codec_type == CODEC_TYPE_VIDEO ) { samplesInChunk = 1; } else if (enc->codec_type == CODEC_TYPE_AUDIO ) { if( enc->codec_id == CODEC_ID_AMR_NB) { /* We must find out how many AMR blocks there are in one packet */ static uint16_t packed_size[16] = {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0}; int len = 0; while (len < size && samplesInChunk < 100) { len += packed_size[(buf[len] >> 3) & 0x0F]; samplesInChunk++; } } else if(enc->codec_id == CODEC_ID_PCM_ALAW) { samplesInChunk = size/enc->channels; } else { samplesInChunk = 1; } } if ((enc->codec_id == CODEC_ID_MPEG4 || enc->codec_id == CODEC_ID_AAC) && trk->vosLen == 0) { assert(enc->extradata_size); trk->vosLen = enc->extradata_size; trk->vosData = av_malloc(trk->vosLen); memcpy(trk->vosData, enc->extradata, trk->vosLen); } cl = trk->entry / MOV_INDEX_CLUSTER_SIZE; id = trk->entry % MOV_INDEX_CLUSTER_SIZE; if (trk->ents_allocated <= trk->entry) { trk->cluster = av_realloc(trk->cluster, (cl+1)*sizeof(void*)); if (!trk->cluster) return -1; trk->cluster[cl] = av_malloc(MOV_INDEX_CLUSTER_SIZE*sizeof(MOVIentry)); if (!trk->cluster[cl]) return -1; trk->ents_allocated += MOV_INDEX_CLUSTER_SIZE; } if (mov->mdat_written == 0) { mov_write_mdat_tag(pb, mov); mov->mdat_written = 1; mov->time = Timestamp(); } trk->cluster[cl][id].pos = url_ftell(pb) - mov->movi_list; trk->cluster[cl][id].samplesInChunk = samplesInChunk; trk->cluster[cl][id].size = size; trk->cluster[cl][id].entries = samplesInChunk; if(enc->codec_type == CODEC_TYPE_VIDEO) { trk->cluster[cl][id].key_frame = enc->coded_frame->key_frame; if(enc->coded_frame->pict_type == FF_I_TYPE) trk->hasKeyframes = 1; } trk->enc = enc; trk->entry++; trk->sampleCount += samplesInChunk; trk->mdat_size += size; put_buffer(pb, buf, size); put_flush_packet(pb); return 0;}static int mov_write_trailer(AVFormatContext *s){ MOVContext *mov = s->priv_data; ByteIOContext *pb = &s->pb; int res = 0; int i, j; offset_t file_size; file_size = url_ftell(pb); j = 0; /* Write size of mdat tag */ for (i=0; i<MAX_STREAMS; i++) { if(mov->tracks[i].ents_allocated > 0) { j += mov->tracks[i].mdat_size; } } url_fseek(pb, mov->mdat_pos, SEEK_SET); put_be32(pb, j+8); url_fseek(pb, file_size, SEEK_SET); mov_write_moov_tag(pb, mov); for (i=0; i<MAX_STREAMS; i++) { for (j=0; j<mov->tracks[i].ents_allocated/MOV_INDEX_CLUSTER_SIZE; j++) { av_free(mov->tracks[i].cluster[j]); } av_free(mov->tracks[i].cluster); mov->tracks[i].cluster = NULL; mov->tracks[i].ents_allocated = mov->tracks[i].entry = 0; } put_flush_packet(pb); return res;}static AVOutputFormat mov_oformat = { "mov", "mov format", NULL, "mov", sizeof(MOVContext), CODEC_ID_PCM_ALAW, CODEC_ID_MPEG4, mov_write_header, mov_write_packet, mov_write_trailer,};static AVOutputFormat _3gp_oformat = { "3gp", "3gp format", NULL, "3gp", sizeof(MOVContext), CODEC_ID_AMR_NB, CODEC_ID_H263, mov_write_header, mov_write_packet, mov_write_trailer,};static AVOutputFormat mp4_oformat = { "mp4", "mp4 format", "application/mp4", "mp4,m4a", sizeof(MOVContext), CODEC_ID_AAC, CODEC_ID_MPEG4, mov_write_header, mov_write_packet, mov_write_trailer,};int movenc_init(void){ av_register_output_format(&mov_oformat); av_register_output_format(&_3gp_oformat); av_register_output_format(&mp4_oformat); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -