📄 movenc.c
字号:
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->time_base.den; mov->tracks[i].sampleDuration = mov->tracks[i].enc->time_base.num; } 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])); } } mov_write_udta_tag(pb, mov, s); 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){ MOVContext *mov = s->priv_data; put_be32(pb, 0x14 ); /* size */ put_tag(pb, "ftyp"); if ( mov->mode == MODE_3GP ) put_tag(pb, "3gp4"); else if ( mov->mode == MODE_3G2 ) put_tag(pb, "3g2a"); else if ( mov->mode == MODE_PSP ) put_tag(pb, "MSNV"); else put_tag(pb, "isom"); put_be32(pb, 0x200 ); if ( mov->mode == MODE_3GP ) put_tag(pb, "3gp4"); else if ( mov->mode == MODE_3G2 ) put_tag(pb, "3g2a"); else if ( mov->mode == MODE_PSP ) put_tag(pb, "MSNV"); else put_tag(pb, "mp41"); return 0x14;}static void mov_write_uuidprof_tag(ByteIOContext *pb, AVFormatContext *s){ int AudioRate = s->streams[1]->codec->sample_rate; int FrameRate = ((s->streams[0]->codec->time_base.den) * (0x10000))/ (s->streams[0]->codec->time_base.num); //printf("audiorate = %d\n",AudioRate); //printf("framerate = %d / %d = 0x%x\n",s->streams[0]->codec->time_base.den,s->streams[0]->codec->time_base.num,FrameRate); put_be32(pb, 0x94 ); /* size */ put_tag(pb, "uuid"); put_tag(pb, "PROF"); put_be32(pb, 0x21d24fce ); /* 96 bit UUID */ put_be32(pb, 0xbb88695c ); put_be32(pb, 0xfac9c740 ); put_be32(pb, 0x0 ); /* ? */ put_be32(pb, 0x3 ); /* 3 sections ? */ put_be32(pb, 0x14 ); /* size */ put_tag(pb, "FPRF"); put_be32(pb, 0x0 ); /* ? */ put_be32(pb, 0x0 ); /* ? */ put_be32(pb, 0x0 ); /* ? */ put_be32(pb, 0x2c ); /* size */ put_tag(pb, "APRF"); /* audio */ put_be32(pb, 0x0 ); put_be32(pb, 0x2 ); put_tag(pb, "mp4a"); put_be32(pb, 0x20f ); put_be32(pb, 0x0 ); put_be32(pb, 0x40 ); put_be32(pb, 0x40 ); put_be32(pb, AudioRate ); //24000 ... audio rate? put_be32(pb, 0x2 ); put_be32(pb, 0x34 ); /* size */ put_tag(pb, "VPRF"); /* video */ put_be32(pb, 0x0 ); put_be32(pb, 0x1 ); put_tag(pb, "mp4v"); put_be32(pb, 0x103 ); put_be32(pb, 0x0 ); put_be32(pb, 0xc0 ); put_be32(pb, 0xc0 ); put_be32(pb, FrameRate); // was 0xefc29 put_be32(pb, FrameRate ); // was 0xefc29 put_be16(pb, s->streams[0]->codec->width); put_be16(pb, s->streams[0]->codec->height); put_be32(pb, 0x010001 );}static int mov_write_header(AVFormatContext *s){ ByteIOContext *pb = &s->pb; MOVContext *mov = s->priv_data; int i; for(i=0; i<s->nb_streams; i++){ AVCodecContext *c= s->streams[i]->codec; if (c->codec_type == CODEC_TYPE_VIDEO){ if (!codec_get_tag(codec_movvideo_tags, c->codec_id)){ if(!codec_get_tag(codec_bmp_tags, c->codec_id)) return -1; else av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, the file may be unplayable!\n"); } }else if(c->codec_type == CODEC_TYPE_AUDIO){ if (!codec_get_tag(codec_movaudio_tags, c->codec_id)){ if(!codec_get_tag(codec_wav_tags, c->codec_id)) return -1; else av_log(s, AV_LOG_INFO, "Warning, using MS style audio codec tag, the file may be unplayable!\n"); } } } /* Default mode == MP4 */ mov->mode = MODE_MP4; if (s->oformat != NULL) { if (!strcmp("3gp", s->oformat->name)) mov->mode = MODE_3GP; else if (!strcmp("3g2", s->oformat->name)) mov->mode = MODE_3G2; else if (!strcmp("mov", s->oformat->name)) mov->mode = MODE_MOV; else if (!strcmp("psp", s->oformat->name)) mov->mode = MODE_PSP; if ( mov->mode == MODE_3GP || mov->mode == MODE_3G2 || mov->mode == MODE_MP4 || mov->mode == MODE_PSP ) mov_write_ftyp_tag(pb,s); if ( mov->mode == MODE_PSP ) { if ( s->nb_streams != 2 ) { av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n"); return -1; } mov_write_uuidprof_tag(pb,s); } } for (i=0; i<MAX_STREAMS; i++) { mov->tracks[i].mode = mov->mode; } put_flush_packet(pb); return 0;}static int mov_write_packet(AVFormatContext *s, AVPacket *pkt){ MOVContext *mov = s->priv_data; ByteIOContext *pb = &s->pb; AVCodecContext *enc = s->streams[pkt->stream_index]->codec; MOVTrack* trk = &mov->tracks[pkt->stream_index]; int cl, id; unsigned int samplesInChunk = 0; int size= pkt->size; 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[(pkt->data[len] >> 3) & 0x0F]; samplesInChunk++; } } else if(enc->codec_id == CODEC_ID_PCM_ALAW) { samplesInChunk = size/enc->channels; } else if(enc->codec_id == CODEC_ID_PCM_S16BE || enc->codec_id == CODEC_ID_PCM_S16LE) { samplesInChunk = size/(2*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 = s->timestamp + 0x7C25B080; //1970 based -> 1904 based } trk->cluster[cl][id].pos = url_ftell(pb); 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 = !!(pkt->flags & PKT_FLAG_KEY); if(trk->cluster[cl][id].key_frame) trk->hasKeyframes = 1; } trk->enc = enc; trk->entry++; trk->sampleCount += samplesInChunk; trk->mdat_size += size; put_buffer(pb, pkt->data, 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 moov_pos = url_ftell(pb); /* Write size of mdat tag */ for (i=0, j=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, moov_pos, SEEK_SET); mov_write_moov_tag(pb, mov, s); 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); if( mov->tracks[i].vosLen ) av_free( mov->tracks[i].vosData ); 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_AAC, CODEC_ID_MPEG4, mov_write_header, mov_write_packet, mov_write_trailer, .flags = AVFMT_GLOBALHEADER,};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, .flags = AVFMT_GLOBALHEADER,};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, .flags = AVFMT_GLOBALHEADER,};static AVOutputFormat psp_oformat = { "psp", "psp mp4 format", NULL, "mp4,psp", sizeof(MOVContext), CODEC_ID_AAC, CODEC_ID_MPEG4, mov_write_header, mov_write_packet, mov_write_trailer,// .flags = AVFMT_GLOBALHEADER,};static AVOutputFormat _3g2_oformat = { "3g2", "3gp2 format", NULL, "3g2", sizeof(MOVContext), CODEC_ID_AMR_NB, CODEC_ID_H263, mov_write_header, mov_write_packet, mov_write_trailer, .flags = AVFMT_GLOBALHEADER,};int movenc_init(void){ av_register_output_format(&mov_oformat); av_register_output_format(&_3gp_oformat); av_register_output_format(&mp4_oformat); av_register_output_format(&psp_oformat); av_register_output_format(&_3g2_oformat); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -