} else if (track->enc->codec_id == CODEC_ID_AMR_NB) {
mov_write_amr_tag(pb, track);
} else if (track->enc->codec_id == CODEC_ID_AC3) {
- mov_write_chan_tag(pb, track);
mov_write_ac3_tag(pb, track);
} else if (track->enc->codec_id == CODEC_ID_ALAC) {
mov_write_extradata_tag(pb, track);
}
avio_wb16(pb, 0); /* packet size (= 0) */
- avio_wb16(pb, track->enc->sample_rate);
+ avio_wb16(pb, track->enc->sample_rate <= UINT16_MAX ?
+ track->enc->sample_rate : 0);
avio_wb16(pb, 0); /* Reserved */
}
track->enc->codec_id == CODEC_ID_ALAC ||
track->enc->codec_id == CODEC_ID_ADPCM_MS ||
track->enc->codec_id == CODEC_ID_ADPCM_IMA_WAV ||
- mov_pcm_le_gt16(track->enc->codec_id)))
+ (mov_pcm_le_gt16(track->enc->codec_id) && version==1)))
mov_write_wave_tag(pb, track);
else if(track->tag == MKTAG('m','p','4','a'))
mov_write_esds_tag(pb, track);
else if (track->vos_len > 0)
mov_write_glbl_tag(pb, track);
+ if (track->mode == MODE_MOV && track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
+ mov_write_chan_tag(pb, track);
+
return update_size(pb, pos);
}
static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
{
- int tag = track->enc->codec_tag;
+ int tag;
if (track->mode == MODE_MP4 || track->mode == MODE_PSP)
tag = mp4_get_codec_tag(s, track);
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_AVUI)
+ mov_write_extradata_tag(pb, track);
else if(track->enc->codec_id == CODEC_ID_DNXHD)
mov_write_avid_tag(pb, track);
else if(track->enc->codec_id == CODEC_ID_H264) {
static int mov_write_gmhd_tag(AVIOContext *pb)
{
- avio_wb32(pb, 0x20); /* size */
+ avio_wb32(pb, 0x4C); /* size */
ffio_wfourcc(pb, "gmhd");
avio_wb32(pb, 0x18); /* gmin size */
ffio_wfourcc(pb, "gmin");/* generic media info */
avio_wb16(pb, 0x8000); /* opColor (b?) */
avio_wb16(pb, 0); /* balance */
avio_wb16(pb, 0); /* reserved */
- return 0x20;
+
+ /*
+ * This special text atom is required for
+ * Apple Quicktime chapters. The contents
+ * don't appear to be documented, so the
+ * bytes are copied verbatim.
+ */
+ avio_wb32(pb, 0x2C); /* size */
+ ffio_wfourcc(pb, "text");
+ avio_wb16(pb, 0x01);
+ avio_wb32(pb, 0x00);
+ avio_wb32(pb, 0x00);
+ avio_wb32(pb, 0x00);
+ avio_wb32(pb, 0x01);
+ avio_wb32(pb, 0x00);
+ avio_wb32(pb, 0x00);
+ avio_wb32(pb, 0x00);
+ avio_wb32(pb, 0x00004000);
+ avio_wb16(pb, 0x0000);
+
+ return 0x4C;
}
static int mov_write_smhd_tag(AVIOContext *pb)
return 0;
}
-static int mov_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
+int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
{
MOVMuxContext *mov = s->priv_data;
AVIOContext *pb = s->pb;
unsigned int samples_in_chunk = 0;
int size= pkt->size;
uint8_t *reformatted_data = NULL;
- int64_t frag_duration = 0;
-
- if (!s->pb->seekable && !(mov->flags & FF_MOV_FLAG_EMPTY_MOOV))
- return 0; /* Can't handle that */
-
- if (!size) return 0; /* Discard 0 sized packets */
-
- if (trk->entry)
- frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
- s->streams[pkt->stream_index]->time_base,
- AV_TIME_BASE_Q);
- if ((mov->max_fragment_duration &&
- frag_duration >= mov->max_fragment_duration) ||
- (mov->max_fragment_size && mov->mdat_size + size >= mov->max_fragment_size) ||
- (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
- enc->codec_type == AVMEDIA_TYPE_VIDEO &&
- trk->entry && pkt->flags & AV_PKT_FLAG_KEY)) {
- if (frag_duration >= mov->min_fragment_duration)
- mov_flush_fragment(s);
- }
if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
int ret;
return 0;
}
-int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
+static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
{
if (!pkt) {
mov_flush_fragment(s);
return 1;
} else {
- return mov_write_packet_internal(s, pkt);
+ MOVMuxContext *mov = s->priv_data;
+ MOVTrack *trk = &mov->tracks[pkt->stream_index];
+ AVCodecContext *enc = trk->enc;
+ int64_t frag_duration = 0;
+ int size = pkt->size;
+
+ if (!pkt->size) return 0; /* Discard 0 sized packets */
+
+ if (trk->entry && pkt->stream_index < s->nb_streams)
+ frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
+ s->streams[pkt->stream_index]->time_base,
+ AV_TIME_BASE_Q);
+ if ((mov->max_fragment_duration &&
+ frag_duration >= mov->max_fragment_duration) ||
+ (mov->max_fragment_size && mov->mdat_size + size >= mov->max_fragment_size) ||
+ (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
+ enc->codec_type == AVMEDIA_TYPE_VIDEO &&
+ trk->entry && pkt->flags & AV_PKT_FLAG_KEY)) {
+ if (frag_duration >= mov->min_fragment_duration)
+ mov_flush_fragment(s);
+ }
+
+ return ff_mov_write_packet(s, pkt);
}
}
// as samples, and a tref pointing from the other tracks to the chapter one.
static void mov_create_chapter_track(AVFormatContext *s, int tracknum)
{
+ AVIOContext *pb;
+
MOVMuxContext *mov = s->priv_data;
MOVTrack *track = &mov->tracks[tracknum];
AVPacket pkt = { .stream_index = tracknum, .flags = AV_PKT_FLAG_KEY };
track->enc = avcodec_alloc_context3(NULL);
track->enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ if (avio_open_dyn_buf(&pb) >= 0) {
+ int size;
+ uint8_t *buf;
+
+ /* Stub header (usually for Quicktime chapter track) */
+ // TextSampleEntry
+ avio_wb32(pb, 0x01); // displayFlags
+ avio_w8(pb, 0x00); // horizontal justification
+ avio_w8(pb, 0x00); // vertical justification
+ avio_w8(pb, 0x00); // bgColourRed
+ avio_w8(pb, 0x00); // bgColourGreen
+ avio_w8(pb, 0x00); // bgColourBlue
+ avio_w8(pb, 0x00); // bgColourAlpha
+ // BoxRecord
+ avio_wb16(pb, 0x00); // defTextBoxTop
+ avio_wb16(pb, 0x00); // defTextBoxLeft
+ avio_wb16(pb, 0x00); // defTextBoxBottom
+ avio_wb16(pb, 0x00); // defTextBoxRight
+ // StyleRecord
+ avio_wb16(pb, 0x00); // startChar
+ avio_wb16(pb, 0x00); // endChar
+ avio_wb16(pb, 0x01); // fontID
+ avio_w8(pb, 0x00); // fontStyleFlags
+ avio_w8(pb, 0x00); // fontSize
+ avio_w8(pb, 0x00); // fgColourRed
+ avio_w8(pb, 0x00); // fgColourGreen
+ avio_w8(pb, 0x00); // fgColourBlue
+ avio_w8(pb, 0x00); // fgColourAlpha
+ // FontTableBox
+ avio_wb32(pb, 0x0D); // box size
+ ffio_wfourcc(pb, "ftab"); // box atom name
+ avio_wb16(pb, 0x01); // entry count
+ // FontRecord
+ avio_wb16(pb, 0x01); // font ID
+ avio_w8(pb, 0x00); // font name length
+
+ if ((size = avio_close_dyn_buf(pb, &buf)) > 0) {
+ track->enc->extradata = buf;
+ track->enc->extradata_size = size;
+ } else {
+ av_free(&buf);
+ }
+ }
+
for (i = 0; i < s->nb_chapters; i++) {
AVChapter *c = s->chapters[i];
AVDictionaryEntry *t;
}else if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO){
track->timescale = st->codec->sample_rate;
if(!st->codec->frame_size && !av_get_bits_per_sample(st->codec->codec_id)) {
- av_log(s, AV_LOG_ERROR, "track %d: codec frame size is not set\n", i);
- goto error;
+ av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
+ track->audio_vbr = 1;
}else if(st->codec->codec_id == CODEC_ID_ADPCM_MS ||
st->codec->codec_id == CODEC_ID_ADPCM_IMA_WAV){
if (!st->codec->block_align) {
}else{
track->sample_size = (av_get_bits_per_sample(st->codec->codec_id) >> 3) * st->codec->channels;
}
- if (track->mode != MODE_MOV) {
- if (track->timescale > UINT16_MAX) {
- av_log(s, AV_LOG_ERROR, "track %d: output format does not support "
- "sample rate %dhz\n", i, track->timescale);
- goto error;
- }
- if (track->enc->codec_id == CODEC_ID_MP3 && track->timescale < 16000) {
- av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not supported\n",
- i, track->enc->sample_rate);
- goto error;
- }
+ if (track->mode != MODE_MOV &&
+ track->enc->codec_id == CODEC_ID_MP3 && track->timescale < 16000) {
+ av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not supported\n",
+ i, track->enc->sample_rate);
+ goto error;
}
}else if(st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE){
track->timescale = st->codec->time_base.den;
.video_codec = CODEC_ID_MPEG4,
#endif
.write_header = mov_write_header,
- .write_packet = ff_mov_write_packet,
+ .write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
- .codec_tag = (const AVCodecTag* const []){ff_codec_movvideo_tags, ff_codec_movaudio_tags, 0},
- .priv_class = &mov_muxer_class,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .codec_tag = (const AVCodecTag* const []){
+ ff_codec_movvideo_tags, ff_codec_movaudio_tags, 0
+ },
+ .priv_class = &mov_muxer_class,
};
#endif
#if CONFIG_TGP_MUXER
.audio_codec = CODEC_ID_AMR_NB,
.video_codec = CODEC_ID_H263,
.write_header = mov_write_header,
- .write_packet = ff_mov_write_packet,
+ .write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
- .codec_tag = (const AVCodecTag* const []){codec_3gp_tags, 0},
- .priv_class = &tgp_muxer_class,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .codec_tag = (const AVCodecTag* const []){ codec_3gp_tags, 0 },
+ .priv_class = &tgp_muxer_class,
};
#endif
#if CONFIG_MP4_MUXER
.video_codec = CODEC_ID_MPEG4,
#endif
.write_header = mov_write_header,
- .write_packet = ff_mov_write_packet,
+ .write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
- .codec_tag = (const AVCodecTag* const []){ff_mp4_obj_type, 0},
- .priv_class = &mp4_muxer_class,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .codec_tag = (const AVCodecTag* const []){ ff_mp4_obj_type, 0 },
+ .priv_class = &mp4_muxer_class,
};
#endif
#if CONFIG_PSP_MUXER
.video_codec = CODEC_ID_MPEG4,
#endif
.write_header = mov_write_header,
- .write_packet = ff_mov_write_packet,
+ .write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
- .codec_tag = (const AVCodecTag* const []){ff_mp4_obj_type, 0},
- .priv_class = &psp_muxer_class,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .codec_tag = (const AVCodecTag* const []){ ff_mp4_obj_type, 0 },
+ .priv_class = &psp_muxer_class,
};
#endif
#if CONFIG_TG2_MUXER
.audio_codec = CODEC_ID_AMR_NB,
.video_codec = CODEC_ID_H263,
.write_header = mov_write_header,
- .write_packet = ff_mov_write_packet,
+ .write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
- .codec_tag = (const AVCodecTag* const []){codec_3gp_tags, 0},
- .priv_class = &tg2_muxer_class,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .codec_tag = (const AVCodecTag* const []){ codec_3gp_tags, 0 },
+ .priv_class = &tg2_muxer_class,
};
#endif
#if CONFIG_IPOD_MUXER
.audio_codec = CODEC_ID_AAC,
.video_codec = CODEC_ID_H264,
.write_header = mov_write_header,
- .write_packet = ff_mov_write_packet,
+ .write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
- .codec_tag = (const AVCodecTag* const []){codec_ipod_tags, 0},
- .priv_class = &ipod_muxer_class,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 },
+ .priv_class = &ipod_muxer_class,
};
#endif
#if CONFIG_ISMV_MUXER
.audio_codec = CODEC_ID_AAC,
.video_codec = CODEC_ID_H264,
.write_header = mov_write_header,
- .write_packet = ff_mov_write_packet,
+ .write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
- .codec_tag = (const AVCodecTag* const []){ff_mp4_obj_type, 0},
+ .codec_tag = (const AVCodecTag* const []){ ff_mp4_obj_type, 0 },
.priv_class = &ismv_muxer_class,
};
#endif