]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/movenc.c
h263dec: restore error concealment functionality after merge
[ffmpeg] / libavformat / movenc.c
index 8aac2a32e009855befdbc2489f09b76e4ecd978d..610a1fcff3fa450cc457ec93efeb199aaeb716d0 100644 (file)
 #include "libavcodec/put_bits.h"
 #include "internal.h"
 #include "libavutil/avstring.h"
-#include "libavutil/intfloat_readwrite.h"
+#include "libavutil/intfloat.h"
 #include "libavutil/mathematics.h"
 #include "libavutil/opt.h"
 #include "libavutil/dict.h"
 #include "rtpenc.h"
+#include "mov_chan.h"
 
 #undef NDEBUG
 #include <assert.h>
@@ -45,6 +46,8 @@ static const AVOption options[] = {
     { "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags), AV_OPT_TYPE_FLAGS, {.dbl = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
     { "rtphint", "Add RTP hint tracks", 0, AV_OPT_TYPE_CONST, {.dbl = FF_MOV_FLAG_RTP_HINT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
     { "moov_size", "maximum moov size so it can be placed at the begin", offsetof(MOVMuxContext, reserved_moov_size), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, 0 },
+    { "frag_size", "maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, 0 },
+    { "frag_duration", "maximum fragment duration", offsetof(MOVMuxContext, max_fragment_duration), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, 0 },
     FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
     { NULL },
 };
@@ -57,6 +60,8 @@ static const AVClass flavor ## _muxer_class = {\
     .version    = LIBAVUTIL_VERSION_INT,\
 };
 
+static int update_first_fragment(AVFormatContext *s);
+
 //FIXME support 64 bit variant with wide placeholders
 static int64_t updateSize(AVIOContext *pb, int64_t pos)
 {
@@ -245,7 +250,7 @@ static int mov_write_ac3_tag(AVIOContext *pb, MOVTrack *track)
 
 /**
  * This function writes extradata "as is".
- * Extradata must be formated like a valid atom (with size and tag)
+ * Extradata must be formatted like a valid atom (with size and tag).
  */
 static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
 {
@@ -350,6 +355,31 @@ static int mov_write_ms_tag(AVIOContext *pb, MOVTrack *track)
     return updateSize(pb, pos);
 }
 
+static int mov_write_chan_tag(AVIOContext *pb, MOVTrack *track)
+{
+    uint32_t layout_tag, bitmap;
+    int64_t pos = avio_tell(pb);
+
+    layout_tag = ff_mov_get_channel_layout_tag(track->enc->codec_id,
+                                               track->enc->channel_layout,
+                                               &bitmap);
+    if (!layout_tag) {
+        av_log(track->enc, AV_LOG_WARNING, "not writing 'chan' tag due to "
+               "lack of channel information\n");
+        return 0;
+    }
+
+    avio_wb32(pb, 0);           // Size
+    ffio_wfourcc(pb, "chan");   // Type
+    avio_w8(pb, 0);             // Version
+    avio_wb24(pb, 0);           // Flags
+    avio_wb32(pb, layout_tag);  // mChannelLayoutTag
+    avio_wb32(pb, bitmap);      // mChannelBitmap
+    avio_wb32(pb, 0);           // mNumberChannelDescriptions
+
+    return updateSize(pb, pos);
+}
+
 static int mov_write_wave_tag(AVIOContext *pb, MOVTrack *track)
 {
     int64_t pos = avio_tell(pb);
@@ -372,6 +402,7 @@ static int mov_write_wave_tag(AVIOContext *pb, MOVTrack *track)
     } 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);
@@ -430,15 +461,9 @@ static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track)
     uint32_t tag = track->tag;
 
     if (track->mode == MODE_MOV) {
-        if (track->timescale > UINT16_MAX) {
-            if (mov_get_lpcm_flags(track->enc->codec_id))
-                tag = AV_RL32("lpcm");
-            version = 2;
-        } else if (track->audio_vbr || mov_pcm_le_gt16(track->enc->codec_id) ||
-                   track->enc->codec_id == CODEC_ID_ADPCM_MS ||
-                   track->enc->codec_id == CODEC_ID_ADPCM_IMA_WAV) {
-            version = 1;
-        }
+        if (mov_get_lpcm_flags(track->enc->codec_id))
+            tag = AV_RL32("lpcm");
+        version = 2;
     }
 
     avio_wb32(pb, 0); /* size */
@@ -459,40 +484,24 @@ static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track)
         avio_wb16(pb, 0);
         avio_wb32(pb, 0x00010000);
         avio_wb32(pb, 72);
-        avio_wb64(pb, av_dbl2int(track->timescale));
+        avio_wb64(pb, av_double2int(track->timescale));
         avio_wb32(pb, track->enc->channels);
         avio_wb32(pb, 0x7F000000);
         avio_wb32(pb, av_get_bits_per_sample(track->enc->codec_id));
         avio_wb32(pb, mov_get_lpcm_flags(track->enc->codec_id));
         avio_wb32(pb, track->sampleSize);
-        avio_wb32(pb, track->enc->frame_size);
+        avio_wb32(pb, track->audio_vbr ? track->enc->frame_size : 1);
     } else {
-        if (track->mode == MODE_MOV) {
-            avio_wb16(pb, track->enc->channels);
-            if (track->enc->codec_id == CODEC_ID_PCM_U8 ||
-                track->enc->codec_id == CODEC_ID_PCM_S8)
-                avio_wb16(pb, 8); /* bits per sample */
-            else
-                avio_wb16(pb, 16);
-            avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
-        } else { /* reserved for mp4/3gp */
-            avio_wb16(pb, 2);
-            avio_wb16(pb, 16);
-            avio_wb16(pb, 0);
-        }
+        /* reserved for mp4/3gp */
+        avio_wb16(pb, 2);
+        avio_wb16(pb, 16);
+        avio_wb16(pb, 0);
 
         avio_wb16(pb, 0); /* packet size (= 0) */
         avio_wb16(pb, track->timescale); /* Time scale */
         avio_wb16(pb, 0); /* Reserved */
     }
 
-    if(version == 1) { /* SoundDescription V1 extended info */
-        avio_wb32(pb, track->enc->frame_size); /* Samples per packet */
-        avio_wb32(pb, track->sampleSize / track->enc->channels); /* Bytes per packet */
-        avio_wb32(pb, track->sampleSize); /* Bytes per frame */
-        avio_wb32(pb, 2); /* Bytes per sample */
-    }
-
     if(track->mode == MODE_MOV &&
        (track->enc->codec_id == CODEC_ID_AAC ||
         track->enc->codec_id == CODEC_ID_AC3 ||
@@ -1293,7 +1302,7 @@ static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
     avio_wb32(pb, track->enc->height << 16);
 
     return updateSize(pb, pos);
-};
+}
 
 // This box seems important for the psp playback ... without it the movie seems to hang
 static int mov_write_edts_tag(AVIOContext *pb, MOVTrack *track)
@@ -1391,14 +1400,14 @@ static int mov_write_udta_sdp(AVIOContext *pb, AVFormatContext *ctx, int index)
     return len + 24;
 }
 
-static int mov_write_trak_tag(AVIOContext *pb, MOVTrack *track, AVStream *st)
+static int mov_write_trak_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track, AVStream *st)
 {
     int64_t pos = avio_tell(pb);
     avio_wb32(pb, 0); /* size */
     ffio_wfourcc(pb, "trak");
     mov_write_tkhd_tag(pb, track, st);
-    if (track->mode == MODE_PSP || track->flags & MOV_TRACK_CTTS || track->cluster[0].dts)
-        mov_write_edts_tag(pb, track);  // PSP Movies require edts box
+    if(!mov->fragments) // EDTS with fragments is tricky as we dont know the duration when its written
+        mov_write_edts_tag(pb, track);  // PSP Movies and several other cases require edts box
     if (track->tref_tag)
         mov_write_tref_tag(pb, track);
     mov_write_mdia_tag(pb, track);
@@ -1414,6 +1423,63 @@ static int mov_write_trak_tag(AVIOContext *pb, MOVTrack *track, AVStream *st)
     return updateSize(pb, pos);
 }
 
+static int mov_write_tfhd_tag(AVIOContext *pb, MOVTrack *track, AVStream *st)
+{
+    int64_t pos = avio_tell(pb);
+    int flags=1;
+
+    avio_wb32(pb, 0);
+    ffio_wfourcc(pb, "tfhd");
+    avio_w8(pb, 0);
+    avio_wb24(pb, flags);
+    avio_wb32(pb, track->trackID);
+
+    track->base_data_offset_pos= avio_tell(pb);
+    if (flags & 0x01) avio_wb64(pb, 0);
+
+    return updateSize(pb, pos);
+}
+
+static int mov_write_trun_tag(AVIOContext *pb, MOVTrack *track)
+{
+    int64_t pos = avio_tell(pb);
+    int sample_count= track->entry - track->cluster_write_index;
+    int tr_flags=0;
+    int i;
+
+    tr_flags |= 0xF00; //FIXME
+
+    avio_wb32(pb, 0);
+    ffio_wfourcc(pb, "trun");
+    avio_w8(pb, 0);
+    avio_wb24(pb, tr_flags);
+    avio_wb32(pb, sample_count);
+    if(tr_flags&1) avio_wb32(pb, 0);
+
+    for(i=track->cluster_write_index; i<track->entry; i++){
+        int64_t duration = i + 1 == track->entry ?
+                track->trackDuration - track->cluster[i].dts + track->cluster[0].dts : /* readjusting */
+                track->cluster[i+1].dts - track->cluster[i].dts;
+
+        if(tr_flags&0x100) avio_wb32(pb, duration);
+        if(tr_flags&0x200) avio_wb32(pb, track->cluster[i].size);
+        if(tr_flags&0x400) avio_wb32(pb, (track->cluster[i].flags&MOV_SYNC_SAMPLE) ? 0x02000000 : 0x01010000);
+        if(tr_flags&0x800) avio_wb32(pb, track->cluster[i].cts);
+    }
+
+    return updateSize(pb, pos);
+}
+
+static int mov_write_traf_tag(AVIOContext *pb, MOVTrack *track, AVStream *st)
+{
+    int64_t pos = avio_tell(pb);
+    avio_wb32(pb, 0); /* size */
+    ffio_wfourcc(pb, "traf");
+    mov_write_tfhd_tag(pb, track, st);
+    mov_write_trun_tag(pb, track);
+    return updateSize(pb, pos);
+}
+
 #if 0
 /* TODO: Not sorted out, but not necessary either */
 static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
@@ -1827,6 +1893,39 @@ static void build_chunks(MOVTrack *trk)
     }
 }
 
+static int mov_write_trex_tag(AVIOContext *pb, MOVTrack *track, AVStream *st)
+{
+    int64_t pos = avio_tell(pb);
+    avio_wb32(pb, 0); /* size */
+    ffio_wfourcc(pb, "trex");
+
+    avio_w8(pb, 0);
+    avio_wb24(pb, 0);
+    avio_wb32(pb, track->trackID);
+    avio_wb32(pb, 1); // stsd_id
+    avio_wb32(pb, 1); // duration
+    avio_wb32(pb, 1/*Size*/);
+    avio_wb32(pb, 1<<16);
+    return updateSize(pb, pos);
+}
+
+static int mov_write_mvex_tag(AVIOContext *pb, MOVMuxContext *mov,
+                              AVFormatContext *s)
+{
+    int i;
+    int64_t pos = avio_tell(pb);
+    avio_wb32(pb, 0); /* size placeholder*/
+    ffio_wfourcc(pb, "mvex");
+
+    for (i=0; i<mov->nb_streams; i++) {
+        if(mov->tracks[i].entry > 0) {
+            mov_write_trex_tag(pb, &(mov->tracks[i]), i < s->nb_streams ? s->streams[i] : NULL);
+        }
+    }
+
+    return updateSize(pb, pos);
+}
+
 static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
                               AVFormatContext *s)
 {
@@ -1861,10 +1960,13 @@ static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *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]), i < s->nb_streams ? s->streams[i] : NULL);
+            mov_write_trak_tag(pb, mov, &(mov->tracks[i]), i < s->nb_streams ? s->streams[i] : NULL);
         }
     }
 
+    if(mov->fragments)
+        mov_write_mvex_tag(pb, mov, s);
+
     if (mov->mode == MODE_PSP)
         mov_write_uuidusmt_tag(pb, s);
     else
@@ -1873,6 +1975,36 @@ static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
     return updateSize(pb, pos);
 }
 
+static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
+{
+    int i;
+    int64_t pos = avio_tell(pb);
+    avio_wb32(pb, 0); /* size placeholder*/
+    ffio_wfourcc(pb, "mfhd");
+    avio_wb32(pb, 0);
+    avio_wb32(pb, mov->frag_seq_num++);
+
+    return updateSize(pb, pos); //FIXME replace by hardcoded num also above
+}
+
+static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov,
+                              AVFormatContext *s)
+{
+    int i;
+    int64_t pos = avio_tell(pb);
+    avio_wb32(pb, 0); /* size placeholder*/
+    ffio_wfourcc(pb, "moof");
+
+    mov_write_mfhd_tag(pb, mov);
+    for (i=0; i<mov->nb_streams; i++) {
+        if(mov->tracks[i].entry > 0) {
+            mov_write_traf_tag(pb, &(mov->tracks[i]), i < s->nb_streams ? s->streams[i] : NULL);
+        }
+    }
+
+    return updateSize(pb, pos);
+}
+
 static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov)
 {
     avio_wb32(pb, 8);    // placeholder for extended size field (64 bit)
@@ -2023,18 +2155,69 @@ static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
     return 0;
 }
 
+static int flush_cluster_buffer(AVFormatContext *s){
+    MOVMuxContext *mov = s->priv_data;
+    int i, j;
+    int has_data=0;
+
+    for (i=0; i<mov->nb_streams; i++){
+        MOVTrack *track= &mov->tracks[i];
+        if(track->entry != track->cluster_write_index)
+            has_data=1;
+    }
+
+    if(mov->frag_seq_num==0){
+        update_first_fragment(s);
+        mov->frag_seq_num++;
+    }else if(has_data) {
+        mov_write_moof_tag(s->pb, mov, s);
+        mov_write_mdat_tag(s->pb, mov);
+        for (i=0; i<mov->nb_streams; i++){
+            MOVTrack *track= &mov->tracks[i];
+            if(track->entry > 0) {
+                int64_t pos= avio_tell(s->pb);
+                avio_seek(s->pb, track->base_data_offset_pos, SEEK_SET);
+                avio_wb64(s->pb, pos);
+                avio_seek(s->pb, pos, SEEK_SET);
+                for(j=track->cluster_write_index; j<track->entry; j++){
+                    avio_write(s->pb, track->cluster[j].data, track->cluster[j].size);
+                    av_freep(&track->cluster[j].data);
+                }
+            }
+        }
+        updateSize(s->pb, mov->mdat_pos);
+    }
+    mov->mdat_size = 0;
+    for (i=0; i<mov->nb_streams; i++) {
+        MOVTrack *track= &mov->tracks[i];
+        track->cluster_write_index= track->entry;
+    }
+    avio_flush(s->pb);
+
+    return 0;
+}
+
 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
 {
     MOVMuxContext *mov = s->priv_data;
     AVIOContext *pb = s->pb;
     MOVTrack *trk = &mov->tracks[pkt->stream_index];
+    AVStream *st = s->streams[pkt->stream_index];
     AVCodecContext *enc = trk->enc;
     unsigned int samplesInChunk = 0;
     int size= pkt->size;
+    uint8_t *reformatted_data = NULL;
 
     if (!s->pb->seekable) return 0; /* Can't handle that */
     if (!size) return 0; /* Discard 0 sized packets */
 
+    if (mov->fragments && trk->entry > trk->cluster_write_index &&
+        (   mov->max_fragment_duration && av_rescale_q(pkt->dts - trk->cluster[ trk->cluster_write_index ].dts, st->time_base, AV_TIME_BASE_Q) >= mov->max_fragment_duration
+         || mov->max_fragment_size     && mov->mdat_size + size >= mov->max_fragment_size)
+        ){
+        flush_cluster_buffer(s);
+    }
+
     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] =
@@ -2049,9 +2232,6 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
             av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
             return -1;
         }
-    } else if (enc->codec_id == CODEC_ID_ADPCM_MS ||
-               enc->codec_id == CODEC_ID_ADPCM_IMA_WAV) {
-        samplesInChunk = enc->frame_size;
     } else if (trk->sampleSize)
         samplesInChunk = size/trk->sampleSize;
     else
@@ -2064,14 +2244,44 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
         memcpy(trk->vosData, enc->extradata, trk->vosLen);
     }
 
+    if (!(trk->entry % MOV_INDEX_CLUSTER_SIZE)) {
+        trk->cluster = av_realloc_f(trk->cluster, sizeof(*trk->cluster), (trk->entry + MOV_INDEX_CLUSTER_SIZE));
+        if (!trk->cluster)
+            return -1;
+    }
+
     if (enc->codec_id == CODEC_ID_H264 && trk->vosLen > 0 && *(uint8_t *)trk->vosData != 1) {
         /* from x264 or from bytestream h264 */
         /* nal reformating needed */
-        size = ff_avc_parse_nal_units(pb, pkt->data, pkt->size);
+        if(mov->frag_seq_num>0){
+            uint8_t *buf=NULL;
+            size= pkt->size;
+
+            if(ff_avc_parse_nal_units_buf(pkt->data, &buf, &size) < 0){
+                av_log(s, AV_LOG_ERROR, "malformated H264 bitstream\n");
+                return -1;
+            }
+            trk->cluster[trk->entry].data= buf;
+            if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams) {
+                reformatted_data= av_malloc(size);
+                memcpy(reformatted_data, buf, size);
+            }
+        }else if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams) {
+            ff_avc_parse_nal_units_buf(pkt->data, &reformatted_data,
+                                       &size);
+            avio_write(pb, reformatted_data, size);
+        } else {
+            size = ff_avc_parse_nal_units(pb, pkt->data, pkt->size);
+        }
     } else if (enc->codec_id == CODEC_ID_AAC && pkt->size > 2 &&
                (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
         av_log(s, AV_LOG_ERROR, "malformated aac bitstream, use -absf aac_adtstoasc\n");
         return -1;
+    } else if (mov->frag_seq_num>0){
+        trk->cluster[trk->entry].data = av_malloc(size);
+        if (!trk->cluster[trk->entry].data)
+            return AVERROR(ENOMEM);
+        memcpy(trk->cluster[trk->entry].data, pkt->data, size);
     } else {
         avio_write(pb, pkt->data, size);
     }
@@ -2086,13 +2296,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
         memcpy(trk->vosData, pkt->data, size);
     }
 
-    if (!(trk->entry % MOV_INDEX_CLUSTER_SIZE)) {
-        trk->cluster = av_realloc_f(trk->cluster, sizeof(*trk->cluster), (trk->entry + MOV_INDEX_CLUSTER_SIZE));
-        if (!trk->cluster)
-            return -1;
-    }
-
-    trk->cluster[trk->entry].pos = avio_tell(pb) - size;
+    trk->cluster[trk->entry].pos = avio_tell(pb) - (mov->frag_seq_num==0 ? size : 0);
     trk->cluster[trk->entry].samplesInChunk = samplesInChunk;
     trk->cluster[trk->entry].chunkNum = 0;
     trk->cluster[trk->entry].size = size;
@@ -2127,7 +2331,9 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
     avio_flush(pb);
 
     if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams)
-        ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry);
+        ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
+                                 reformatted_data, size);
+    av_free(reformatted_data);
     return 0;
 }
 
@@ -2181,6 +2387,10 @@ static int mov_write_header(AVFormatContext *s)
     /* Default mode == MP4 */
     mov->mode = MODE_MP4;
 
+    if(mov->max_fragment_duration || mov->max_fragment_size){
+        mov->fragments= 1;
+    }
+
     if (s->oformat != NULL) {
         if (!strcmp("3gp", s->oformat->name)) mov->mode = MODE_3GP;
         else if (!strcmp("3g2", s->oformat->name)) mov->mode = MODE_3GP|MODE_3G2;
@@ -2263,21 +2473,21 @@ static int mov_write_header(AVFormatContext *s)
                        "or choose different container.\n");
         }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;
-            }else if(st->codec->codec_id == CODEC_ID_ADPCM_MS ||
-                     st->codec->codec_id == CODEC_ID_ADPCM_IMA_WAV){
+            /* set sampleSize for PCM and ADPCM */
+            if (av_get_bits_per_sample(st->codec->codec_id)) {
                 if (!st->codec->block_align) {
-                    av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
+                    av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set\n", i);
                     goto error;
                 }
                 track->sampleSize = st->codec->block_align;
-            }else if(st->codec->frame_size > 1){ /* assume compressed audio */
+            }
+            /* set audio_vbr for compressed audio */
+            if (av_get_bits_per_sample(st->codec->codec_id) < 8) {
+                if (!st->codec->frame_size) {
+                    av_log(s, AV_LOG_ERROR, "track %d: codec frame size is not set\n", i);
+                    goto error;
+                }
                 track->audio_vbr = 1;
-            }else{
-                st->codec->frame_size = 1;
-                track->sampleSize = (av_get_bits_per_sample(st->codec->codec_id) >> 3) * st->codec->channels;
             }
             if (track->mode != MODE_MOV) {
                 if (track->timescale > UINT16_MAX) {
@@ -2339,7 +2549,7 @@ static int mov_write_header(AVFormatContext *s)
     return -1;
 }
 
-static int mov_write_trailer(AVFormatContext *s)
+static int update_first_fragment(AVFormatContext *s)
 {
     MOVMuxContext *mov = s->priv_data;
     AVIOContext *pb = s->pb;
@@ -2375,6 +2585,18 @@ static int mov_write_trailer(AVFormatContext *s)
         avio_seek(pb, moov_pos, SEEK_SET);
     }
 
+    return 0;
+}
+
+static int mov_write_trailer(AVFormatContext *s)
+{
+    MOVMuxContext *mov = s->priv_data;
+    AVIOContext *pb = s->pb;
+    int res = 0;
+    int i;
+
+    flush_cluster_buffer(s);
+
     if (mov->chapter_track)
         av_freep(&mov->tracks[mov->chapter_track].enc);