📄 movenc.c.svn-base
字号:
url_fseek(pb, pos, SEEK_SET); put_be32(pb, size); url_fseek(pb, pos+24, SEEK_SET); put_be32(pb, size-24); url_fseek(pb, curpos, SEEK_SET); } return size;not_utf8: av_log(s, AV_LOG_ERROR, "not utf8\n"); return -1;}static int mov_write_moov_tag(ByteIOContext *pb, MOVContext *mov, AVFormatContext *s){ int i; offset_t pos = url_ftell(pb); put_be32(pb, 0); /* size placeholder*/ put_tag(pb, "moov"); mov->timescale = globalTimescale; for (i=0; i<mov->nb_streams; i++) { if(mov->tracks[i].entry <= 0) continue; 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<mov->nb_streams; i++) { if(mov->tracks[i].entry > 0) { mov_write_trak_tag(pb, &(mov->tracks[i])); } } if (mov->mode == MODE_PSP) mov_write_uuidusmt_tag(pb, s); else if (mov->mode != MODE_3GP && mov->mode != MODE_3G2) mov_write_udta_tag(pb, mov, s); return updateSize(pb, pos);}static int mov_write_mdat_tag(ByteIOContext *pb, MOVContext* mov){ put_be32(pb, 8); // placeholder for extended size field (64 bit) put_tag(pb, mov->mode == MODE_MOV ? "wide" : "free"); 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 */static void 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 if (mov->mode == MODE_MP4) put_tag(pb, "isom"); else put_tag(pb, "qt "); 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 if (mov->mode == MODE_MP4) put_tag(pb, "mp41"); else put_tag(pb, "qt ");}static void mov_write_uuidprof_tag(ByteIOContext *pb, AVFormatContext *s){ AVCodecContext *VideoCodec = s->streams[0]->codec; AVCodecContext *AudioCodec = s->streams[1]->codec; int AudioRate = AudioCodec->sample_rate; int FrameRate = ((VideoCodec->time_base.den) * (0x10000))/ (VideoCodec->time_base.num); int audio_kbitrate= AudioCodec->bit_rate / 1000; int video_kbitrate= FFMIN(VideoCodec->bit_rate / 1000, 800 - audio_kbitrate); 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); /* TrackID */ put_tag(pb, "mp4a"); put_be32(pb, 0x20f); put_be32(pb, 0x0); put_be32(pb, audio_kbitrate); put_be32(pb, audio_kbitrate); put_be32(pb, AudioRate); put_be32(pb, AudioCodec->channels); put_be32(pb, 0x34); /* size */ put_tag(pb, "VPRF"); /* video */ put_be32(pb, 0x0); put_be32(pb, 0x1); /* TrackID */ if (VideoCodec->codec_id == CODEC_ID_H264) { put_tag(pb, "avc1"); put_be16(pb, 0x014D); put_be16(pb, 0x0015); } else { put_tag(pb, "mp4v"); put_be16(pb, 0x0000); put_be16(pb, 0x0103); } put_be32(pb, 0x0); put_be32(pb, video_kbitrate); put_be32(pb, video_kbitrate); put_be32(pb, FrameRate); put_be32(pb, FrameRate); put_be16(pb, VideoCodec->width); put_be16(pb, VideoCodec->height); put_be32(pb, 0x010001); /* ? */}static int mov_write_header(AVFormatContext *s){ ByteIOContext *pb = s->pb; MOVContext *mov = s->priv_data; int i; if (url_is_streamed(s->pb)) { av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n"); return -1; } /* 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; 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<s->nb_streams; i++){ AVStream *st= s->streams[i]; MOVTrack *track= &mov->tracks[i]; track->enc = st->codec; track->language = ff_mov_iso639_to_lang(st->language, mov->mode != MODE_MOV); track->mode = mov->mode; track->tag = mov_find_codec_tag(s, track); if (!track->tag) { av_log(s, AV_LOG_ERROR, "track %d: could not find tag for codec\n", i); return -1; } if(st->codec->codec_type == CODEC_TYPE_VIDEO){ track->timescale = st->codec->time_base.den; av_set_pts_info(st, 64, 1, st->codec->time_base.den); if (track->mode == MODE_MOV && track->timescale > 100000) av_log(s, AV_LOG_WARNING, "WARNING codec timebase is very high. If duration is too long,\n" "file may not be playable by quicktime. Specify a shorter timebase\n" "or choose different container.\n"); }else if(st->codec->codec_type == CODEC_TYPE_AUDIO){ track->timescale = st->codec->sample_rate; av_set_pts_info(st, 64, 1, st->codec->sample_rate); if(!st->codec->frame_size){ av_log(s, AV_LOG_ERROR, "track %d: codec frame size is not set\n", i); return -1; }else if(st->codec->frame_size > 1){ /* assume compressed audio */ track->audio_vbr = 1; }else{ track->sampleSize = (av_get_bits_per_sample(st->codec->codec_id) >> 3) * st->codec->channels; } } } mov_write_mdat_tag(pb, mov); mov->time = s->timestamp + 0x7C25B080; //1970 based -> 1904 based mov->nb_streams = s->nb_streams; put_flush_packet(pb); return 0;}static int mov_write_packet(AVFormatContext *s, AVPacket *pkt){ MOVContext *mov = s->priv_data; ByteIOContext *pb = s->pb; MOVTrack *trk = &mov->tracks[pkt->stream_index]; AVCodecContext *enc = trk->enc; 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_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++; } if(samplesInChunk > 1){ av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n"); return -1; } } else if (trk->sampleSize) samplesInChunk = size/trk->sampleSize; else samplesInChunk = 1; /* copy extradata if it exists */ if (trk->vosLen == 0 && enc->extradata_size > 0) { trk->vosLen = enc->extradata_size; trk->vosData = av_malloc(trk->vosLen); memcpy(trk->vosData, enc->extradata, trk->vosLen); } if (enc->codec_id == CODEC_ID_H264 && trk->vosLen > 0 && *(uint8_t *)trk->vosData != 1) { /* from x264 or from bytestream h264 */ /* nal reformating needed */ int ret = ff_avc_parse_nal_units(pkt->data, &pkt->data, &pkt->size); if (ret < 0) return ret; assert(pkt->size); size = pkt->size; } else if (enc->codec_id == CODEC_ID_DNXHD && !trk->vosLen) { /* copy frame header to create needed atoms */ if (size < 640) return -1; trk->vosLen = 640; trk->vosData = av_malloc(trk->vosLen); memcpy(trk->vosData, pkt->data, 640); } if (!(trk->entry % MOV_INDEX_CLUSTER_SIZE)) { trk->cluster = av_realloc(trk->cluster, (trk->entry + MOV_INDEX_CLUSTER_SIZE) * sizeof(*trk->cluster)); if (!trk->cluster) return -1; } trk->cluster[trk->entry].pos = url_ftell(pb); trk->cluster[trk->entry].samplesInChunk = samplesInChunk; trk->cluster[trk->entry].size = size; trk->cluster[trk->entry].entries = samplesInChunk; trk->cluster[trk->entry].dts = pkt->dts; trk->trackDuration = pkt->dts - trk->cluster[0].dts + pkt->duration; if(enc->codec_type == CODEC_TYPE_VIDEO) { if (pkt->dts != pkt->pts) trk->hasBframes = 1; trk->cluster[trk->entry].cts = pkt->pts - pkt->dts; trk->cluster[trk->entry].key_frame = !!(pkt->flags & PKT_FLAG_KEY); if(trk->cluster[trk->entry].key_frame) trk->hasKeyframes++; } trk->entry++; trk->sampleCount += samplesInChunk; mov->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; offset_t moov_pos = url_ftell(pb); /* Write size of mdat tag */ if (mov->mdat_size+8 <= UINT32_MAX) { url_fseek(pb, mov->mdat_pos, SEEK_SET); put_be32(pb, mov->mdat_size+8); } else { /* overwrite 'wide' placeholder atom */ url_fseek(pb, mov->mdat_pos - 8, SEEK_SET); put_be32(pb, 1); /* special value: real atom size will be 64 bit value after tag field */ put_tag(pb, "mdat"); put_be64(pb, mov->mdat_size+16); } url_fseek(pb, moov_pos, SEEK_SET); mov_write_moov_tag(pb, mov, s); for (i=0; i<mov->nb_streams; i++) { av_freep(&mov->tracks[i].cluster); if(mov->tracks[i].vosLen) av_free(mov->tracks[i].vosData); } put_flush_packet(pb); return res;}#ifdef CONFIG_MOV_MUXERAVOutputFormat mov_muxer = { "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, .codec_tag = (const AVCodecTag*[]){codec_movvideo_tags, codec_movaudio_tags, 0},};#endif#ifdef CONFIG_TGP_MUXERAVOutputFormat tgp_muxer = { "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, .codec_tag = (const AVCodecTag*[]){codec_3gp_tags, 0},};#endif#ifdef CONFIG_MP4_MUXERAVOutputFormat mp4_muxer = { "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, .codec_tag = (const AVCodecTag*[]){ff_mp4_obj_type, 0},};#endif#ifdef CONFIG_PSP_MUXERAVOutputFormat psp_muxer = { "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, .codec_tag = (const AVCodecTag*[]){ff_mp4_obj_type, 0},};#endif#ifdef CONFIG_TG2_MUXERAVOutputFormat tg2_muxer = { "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, .codec_tag = (const AVCodecTag*[]){codec_3gp_tags, 0},};#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -