MOVTrack tracks[MAX_STREAMS];
} MOVContext;
-//FIXME supprt 64bit varaint with wide placeholders
+//FIXME support 64 bit variant with wide placeholders
static offset_t updateSize (ByteIOContext *pb, offset_t pos)
{
offset_t curpos = url_ftell(pb);
putDescr(pb, 0x04, 13 + decoderSpecificInfoLen);
// Object type indication
- put_byte(pb, codec_get_tag(ff_mov_obj_type, track->enc->codec_id));
+ put_byte(pb, codec_get_tag(ff_mp4_obj_type, track->enc->codec_id));
// the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
// plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
put_be16(pb, 0); /* Revision level */
put_be32(pb, 0); /* Reserved */
- put_be16(pb, track->mode == MODE_MOV ? track->enc->channels : 2); /* Number of channels */
- /* FIXME 8 bit for 'raw ' in mov */
- put_be16(pb, 16); /* Reserved */
+ if (track->mode == MODE_MOV) {
+ put_be16(pb, track->enc->channels);
+ if (track->enc->codec_id == CODEC_ID_PCM_U8 ||
+ track->enc->codec_id == CODEC_ID_PCM_S8)
+ put_be16(pb, 8); /* bits per sample */
+ else
+ put_be16(pb, 16);
+ put_be16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
+ } else { /* reserved for mp4/3gp */
+ put_be16(pb, 2);
+ put_be16(pb, 16);
+ put_be16(pb, 0);
+ }
- put_be16(pb, track->mode == MODE_MOV && track->audio_vbr ? -2 : 0); /* compression ID */
put_be16(pb, 0); /* packet size (= 0) */
put_be16(pb, track->timescale); /* Time scale */
put_be16(pb, 0); /* Reserved */
static uint8_t *avc_find_startcode( uint8_t *p, uint8_t *end )
{
- uint8_t *a = p + 4 - ((int)p & 3);
+ uint8_t *a = p + 4 - ((long)p & 3);
for( end -= 3; p < a && p < end; p++ ) {
if( p[0] == 0 && p[1] == 0 && p[2] == 1 )
return updateSize(pb, pos);
}
+/* also used by all avid codecs (dv, imx, meridien) and their variants */
+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 */
+ put_be32(pb, 5); /* unknown */
+ }
+ /* padding */
+ for (i = 0; i < 10; i++)
+ put_be64(pb, 0);
+
+ /* extra padding for stsd needed */
+ put_be32(pb, 0);
+ return 0;
+}
+
static int mov_find_video_codec_tag(AVFormatContext *s, MOVTrack *track)
{
int tag = track->enc->codec_tag;
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);
return updateSize (pb, pos);
}
static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack* track)
{
- Time2Sample *ctts_entries;
+ MOV_stts_t *ctts_entries;
uint32_t entries = 0;
uint32_t atom_size;
int i;
/* Time to sample atom */
static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
{
- Time2Sample *stts_entries;
+ MOV_stts_t *stts_entries;
uint32_t entries = -1;
uint32_t atom_size;
int i;
(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;
}
/* iTunes meta data */
mov_write_meta_tag(pb, mov, s);
- if(mov->mode == MODE_MOV){ // the title field breaks gtkpod with mp4 and my suspicion is that stuff isnt valid in mp4
+ if(mov->mode == MODE_MOV){ // the title field breaks gtkpod with mp4 and my suspicion is that stuff is not valid in mp4
/* Requirements */
for (i=0; i<mov->nb_streams; i++) {
if(mov->tracks[i].entry <= 0) continue;
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;
track->tag = mov_find_video_codec_tag(s, track);
track->timescale = st->codec->time_base.den;
av_set_pts_info(st, 64, 1, st->codec->time_base.den);
+ if (track->timescale > 100000)
+ av_log(NULL, 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->tag = mov_find_audio_codec_tag(s, track);
track->timescale = st->codec->sample_rate;
av_set_pts_info(st, 64, 1, st->codec->sample_rate);
- switch(track->enc->codec_id){
- case CODEC_ID_MP3:
- case CODEC_ID_AAC:
- case CODEC_ID_AMR_NB:
- case CODEC_ID_AMR_WB:
- track->audio_vbr = 1;
- break;
- default:
- track->sampleSize = (av_get_bits_per_sample(st->codec->codec_id) >> 3) * st->codec->channels;
- }
- if (!st->codec->frame_size) {
+ 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;
}
}
}
samplesInChunk++;
}
if(samplesInChunk > 1){
- av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, inplement a AVParser for it\n");
+ 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)
avc_parse_nal_units(&pkt->data, &pkt->size);
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)) {