]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/mov.c
add hdv2 fourcc to MPEG2 codec mapping
[ffmpeg] / libavformat / mov.c
index 6bfa2d5048d7bdcce9ed0f9e1b3bbf71a42860bc..63529ce9bff32aa22d9683b065e8e7b530ae6df3 100644 (file)
@@ -118,6 +118,7 @@ static const CodecTag mov_video_tags[] = {
     { CODEC_ID_QTRLE, MKTAG('r', 'l', 'e', ' ') }, /* Apple Animation (RLE) */
     { CODEC_ID_QDRAW, MKTAG('q', 'd', 'r', 'w') }, /* QuickDraw */
     { CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') }, /* AVC-1/H.264 */
+    { CODEC_ID_MPEG2VIDEO, MKTAG('h', 'd', 'v', '2') }, /* MPEG2 produced by Sony HD camera */
     { CODEC_ID_NONE, 0 },
 };
 
@@ -253,9 +254,6 @@ typedef struct MOVStreamContext {
     int time_scale;
     long current_sample;
     long left_in_chunk; /* how many samples before next chunk */
-    /* specific MPEG4 header which is added at the beginning of the stream */
-    unsigned int header_len;
-    uint8_t *header_data;
     MOV_esds_t esds;
 } MOVStreamContext;
 
@@ -268,6 +266,7 @@ typedef struct MOVContext {
     int found_mdat; /* we suppose we have enough data to read the file */
     int64_t mdat_size;
     int64_t mdat_offset;
+    int ni;                                         ///< non interleaved mode
     int total_streams;
     /* some streams listed here aren't presented to the ffmpeg API, since they aren't either video nor audio
      * but we need the info to be able to skip data from those streams in the 'mdat' section
@@ -654,7 +653,7 @@ static int mov_read_mdhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
 #ifdef DEBUG
     av_log(NULL, AV_LOG_DEBUG, "track[%i].time_scale = %i\n", c->fc->nb_streams-1, c->streams[c->fc->nb_streams-1]->time_scale); /* time scale */
 #endif
-    get_be32(pb); /* duration */
+    c->fc->streams[c->fc->nb_streams-1]->duration= get_be32(pb); /* duration */
 
     get_be16(pb); /* language */
     get_be16(pb); /* quality */
@@ -768,6 +767,16 @@ static int mov_read_stco(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
         }
     } else
         return -1;
+    
+    for(i=0; i<c->fc->nb_streams; i++){
+        MOVStreamContext *sc2 = (MOVStreamContext *)c->fc->streams[i]->priv_data;
+        if(sc2 && sc2->chunk_offsets){
+            int64_t first= sc2->chunk_offsets[0];
+            int64_t last= sc2->chunk_offsets[sc2->chunk_count-1];
+            if(first >= sc->chunk_offsets[entries-1] || last <= sc->chunk_offsets[0])
+                c->ni=1;
+        }
+    }
 #ifdef DEBUG
 /*
     for(i=0; i<entries; i++) {
@@ -840,16 +849,13 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
             get_be32(pb); /* vendor */
             get_be32(pb); /* temporal quality */
             get_be32(pb); /* spacial quality */
-            st->codec.width = get_be16(pb); /* width */
-            st->codec.height = get_be16(pb); /* height */
-#if 1
-            if (st->codec.codec_id == CODEC_ID_MPEG4) {
-                /* in some MPEG4 the width/height are not correct, so
-                   we ignore this info */
-                st->codec.width = 0;
-                st->codec.height = 0;
+            if(st->codec.codec_id == CODEC_ID_MPEG4){ //FIXME this is silly
+                get_be16(pb);
+                get_be16(pb);
+            }else{
+                st->codec.width = get_be16(pb); /* width */
+                st->codec.height = get_be16(pb); /* height */
             }
-#endif
             get_be32(pb); /* horiz resolution */
             get_be32(pb); /* vert resolution */
             get_be32(pb); /* data size, always 0 */
@@ -867,8 +873,8 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
             st->codec.color_table_id = get_be16(pb); /* colortable id */
 
 /*          These are set in mov_read_stts and might already be set!
-            st->codec.frame_rate      = 25;
-            st->codec.frame_rate_base = 1;
+            st->codec.time_base.den      = 25;
+            st->codec.time_base.num = 1;
 */
            size -= (16+8*4+2+32+2*2);
 #if 0
@@ -1333,44 +1339,20 @@ av_log(NULL, AV_LOG_DEBUG, "track[%i].stts.entries = %i\n", c->fc->nb_streams-1,
         sample_duration = get_be32(pb);
         c->streams[c->fc->nb_streams - 1]->stts_data[i].count= sample_count;
         c->streams[c->fc->nb_streams - 1]->stts_data[i].duration= sample_duration;
+
 #ifdef DEBUG
         av_log(NULL, AV_LOG_DEBUG, "sample_count=%d, sample_duration=%d\n",sample_count,sample_duration);
 #endif
         duration+=sample_duration*sample_count;
         total_sample_count+=sample_count;
-
-#if 0 //We calculate an average instead, needed by .mp4-files created with nec e606 3g phone
-
-        if (!i && st->codec.codec_type==CODEC_TYPE_VIDEO) {
-            st->codec.frame_rate_base = sample_duration ? sample_duration : 1;
-            st->codec.frame_rate = c->streams[c->fc->nb_streams-1]->time_scale;
-#ifdef DEBUG
-            av_log(NULL, AV_LOG_DEBUG, "VIDEO FRAME RATE= %i (sd= %i)\n", st->codec.frame_rate, sample_duration);
-#endif
-        }
-#endif
     }
 
-    /*The stsd atom which contain codec type sometimes comes after the stts so we cannot check for codec_type*/
-    if(duration>0)
-    {
-        av_reduce(
-            &st->codec.frame_rate, 
-            &st->codec.frame_rate_base, 
-            c->streams[c->fc->nb_streams-1]->time_scale * total_sample_count,
-            duration,
-            INT_MAX
-        );
-
-#ifdef DEBUG
-        av_log(NULL, AV_LOG_DEBUG, "FRAME RATE average (video or audio)= %f (tot sample count= %i ,tot dur= %i timescale=%d)\n", (float)st->codec.frame_rate/st->codec.frame_rate_base,total_sample_count,duration,c->streams[c->fc->nb_streams-1]->time_scale);
-#endif
-    }
-    else
-    {
-        st->codec.frame_rate_base = 1;
-        st->codec.frame_rate = c->streams[c->fc->nb_streams-1]->time_scale;
-    }
+    av_set_pts_info(st, 64, 1, c->streams[c->fc->nb_streams-1]->time_scale);
+//    st->codec.time_base.num = 1;
+//    st->codec.time_base.den = c->streams[c->fc->nb_streams-1]->time_scale;
+    st->nb_frames= total_sample_count;
+    if(duration)
+        st->duration= duration;
     return 0;
 }
 
@@ -1420,7 +1402,6 @@ static int mov_read_trak(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
     st->priv_data = sc;
     st->codec.codec_type = CODEC_TYPE_MOV_OTHER;
     st->start_time = 0; /* XXX: check */
-    st->duration = (c->duration * (int64_t)AV_TIME_BASE) / c->time_scale;
     c->streams[c->fc->nb_streams-1] = sc;
 
     return mov_read_default(c, pb, atom);
@@ -1450,7 +1431,7 @@ static int mov_read_tkhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
     st->id = (int)get_be32(pb); /* track id (NOT 0 !)*/
     get_be32(pb); /* reserved */
     st->start_time = 0; /* check */
-    st->duration = (get_be32(pb) * (int64_t)AV_TIME_BASE) / c->time_scale; /* duration */
+    get_be32(pb); /* highlevel (considering edits) duration in movie timebase */
     get_be32(pb); /* reserved */
     get_be32(pb); /* reserved */
 
@@ -1462,8 +1443,8 @@ static int mov_read_tkhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
     url_fskip(pb, 36); /* display matrix */
 
     /* those are fixed-point */
-    st->codec.width = get_be32(pb) >> 16; /* track width */
-    st->codec.height = get_be32(pb) >> 16; /* track height */
+    /*st->codec.width =*/ get_be32(pb) >> 16; /* track width */
+    /*st->codec.height =*/ get_be32(pb) >> 16; /* track height */
 
     return 0;
 }
@@ -1664,7 +1645,6 @@ static void mov_free_stream_context(MOVStreamContext *sc)
         av_freep(&sc->sample_to_chunk);
         av_freep(&sc->sample_sizes);
         av_freep(&sc->keyframes);
-        av_freep(&sc->header_data);
         av_freep(&sc->stts_data);        
         av_freep(&sc->ctts_data);        
         av_freep(&sc);
@@ -1712,6 +1692,7 @@ static int mov_probe(AVProbeData *p)
             return AVPROBE_SCORE_MAX - 5;
         case MKTAG( 'f', 't', 'y', 'p' ):
         case MKTAG( 's', 'k', 'i', 'p' ):
+        case MKTAG( 'u', 'u', 'i', 'd' ):
             offset = to_be32(p->buf+offset) + offset;
             /* if we only find those cause probedata is too small at least rate them */
             score = AVPROBE_SCORE_MAX - 50;
@@ -1739,7 +1720,7 @@ static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap)
         mov->mp4 = 1;
 #endif
     if(!url_is_streamed(pb)) /* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */
-       atom.size = url_filesize(url_fileno(pb));
+       atom.size = url_fsize(pb);
     else
        atom.size = 0x7FFFFFFFFFFFFFFFLL;
 
@@ -1801,7 +1782,8 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
 {
     MOVContext *mov = (MOVContext *) s->priv_data;
     MOVStreamContext *sc;
-    int64_t offset = 0x0FFFFFFFFFFFFFFFLL;
+    int64_t offset = INT64_MAX;
+    int64_t best_dts = INT64_MAX;
     int i, a, b, m;
     int size;
     int idx;
@@ -1816,10 +1798,11 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
 #ifdef DEBUG
         fprintf(stderr, "sc[ffid %d]->sample_size = %d\n", sc->ffindex, sc->sample_size);
 #endif
-        // sample_size is not always correct for audio. Quicktime ignores this value and
-        // computes it differently.
-        if(s->streams[sc->ffindex]->codec.codec_type == CODEC_TYPE_VIDEO)
-            size = sc->sample_size?sc->sample_size:sc->sample_sizes[sc->current_sample];
+        //size = sc->sample_sizes[sc->current_sample];
+        // that ain't working...
+        //size = (sc->sample_size)?sc->sample_size:sc->sample_sizes[sc->current_sample];
+        size = (sc->sample_size > 1)?sc->sample_size:sc->sample_sizes[sc->current_sample];
+
         sc->current_sample++;
         sc->left_in_chunk--;
 
@@ -1834,17 +1817,44 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
 
 again:
     sc = 0;
+    if(offset == INT64_MAX)
+        best_dts= INT64_MAX;
     for(i=0; i<mov->total_streams; i++) {
        MOVStreamContext *msc = mov->streams[i];
-       //av_log(NULL, AV_LOG_DEBUG, "MOCHUNK %ld  %d   %p  pos:%Ld\n", mov->streams[i]->next_chunk, mov->total_streams, mov->streams[i], url_ftell(&s->pb));
-        if ((msc->next_chunk < msc->chunk_count) && msc->next_chunk >= 0
-          && (msc->chunk_offsets[msc->next_chunk] < offset)) {
-           sc = msc;
-           offset = msc->chunk_offsets[msc->next_chunk];
-           //av_log(NULL, AV_LOG_DEBUG, "SELETED  %Ld  i:%d\n", offset, i);
+
+        if ((msc->next_chunk < msc->chunk_count) && msc->next_chunk >= 0){
+            if (msc->sample_to_time_index < msc->stts_count && mov->ni) {
+                int64_t dts;
+                int index= msc->sample_to_time_index;
+                int sample= msc->sample_to_time_sample;
+                int time= msc->sample_to_time_time;
+                int duration = msc->stts_data[index].duration;
+                int count = msc->stts_data[index].count;
+                if (sample + count < msc->current_sample) {
+                    sample += count;
+                    time   += count*duration;
+                    index ++;
+                    duration = msc->stts_data[index].duration;
+                }
+                dts = time + (msc->current_sample-1 - sample) * (int64_t)duration;
+                dts = av_rescale(dts, AV_TIME_BASE, msc->time_scale);
+//                av_log(NULL, AV_LOG_DEBUG, "%d %Ld %Ld %Ld \n", i, dts, best_dts, offset);
+                if(dts < best_dts){
+                    best_dts= dts;
+                    sc = msc;
+                    offset = msc->chunk_offsets[msc->next_chunk];
+                }
+            }else{
+            //av_log(NULL, AV_LOG_DEBUG, "MOCHUNK %ld  %d   %p  pos:%Ld\n", mov->streams[i]->next_chunk, mov->total_streams, mov->streams[i], url_ftell(&s->pb));
+                if ((msc->chunk_offsets[msc->next_chunk] < offset)) {
+                    sc = msc;
+                    offset = msc->chunk_offsets[msc->next_chunk];
+                    //av_log(NULL, AV_LOG_DEBUG, "SELETED  %Ld  i:%d\n", offset, i);
+                }
+            }
         }
     }
-    if (!sc || offset==0x0FFFFFFFFFFFFFFFLL)
+    if (!sc || offset==INT64_MAX)
        return -1;
 
     sc->next_chunk++;
@@ -1858,7 +1868,7 @@ again:
     if(!sc->is_ff_stream || (s->streams[sc->ffindex]->discard >= AVDISCARD_ALL)) {
         url_fskip(&s->pb, (offset - mov->next_chunk_offset));
         mov->next_chunk_offset = offset;
-       offset = 0x0FFFFFFFFFFFFFFFLL;
+       offset = INT64_MAX;
         goto again;
     }
 
@@ -1867,7 +1877,8 @@ again:
     for(i=0; i<mov->total_streams; i++) {
        MOVStreamContext *msc = mov->streams[i];
        if ((msc->next_chunk < msc->chunk_count)
-           && ((msc->chunk_offsets[msc->next_chunk] - offset) < size))
+            && msc->chunk_offsets[msc->next_chunk] - offset < size
+            && msc->chunk_offsets[msc->next_chunk] > offset)
            size = msc->chunk_offsets[msc->next_chunk] - offset;
     }
 
@@ -1903,23 +1914,23 @@ again:
     }
 #endif //MOV_MINOLTA_FIX
 
+    idx = sc->sample_to_chunk_index;
+    if (idx + 1 < sc->sample_to_chunk_sz && sc->next_chunk >= sc->sample_to_chunk[idx + 1].first)
+        idx++;
+    sc->sample_to_chunk_index = idx;
 #ifdef MOV_SPLIT_CHUNKS
     /* split chunks into samples */
-    if (s->streams[sc->ffindex]->codec.codec_type == CODEC_TYPE_VIDEO) {
-        // This does not support split audio, as the sample_size is often not correct
-        idx = sc->sample_to_chunk_index;
-        if ((idx + 1 < sc->sample_to_chunk_sz)
-                && (sc->next_chunk >= sc->sample_to_chunk[idx + 1].first))
-            idx++;
-        sc->sample_to_chunk_index = idx;
+    if (sc->sample_size == 0 || sc->sample_size > 100) {
         if (idx >= 0 && sc->sample_to_chunk[idx].count != 1) {
            mov->partial = sc;
             /* we'll have to get those samples before next chunk */
             sc->left_in_chunk = sc->sample_to_chunk[idx].count - 1;
-            size = sc->sample_size?sc->sample_size:sc->sample_sizes[sc->current_sample];
+            size = (sc->sample_size > 1)?sc->sample_size:sc->sample_sizes[sc->current_sample];
         }
 
         sc->current_sample++;
+    }else if(idx + 1 < sc->sample_to_chunk_sz){
+        sc->current_sample += sc->sample_size * sc->sample_to_chunk[idx].count;
     }
 #endif
 
@@ -1935,18 +1946,7 @@ readchunk:
         return -1;
     url_fseek(&s->pb, offset, SEEK_SET);
 
-    //av_log(NULL, AV_LOG_DEBUG, "READCHUNK hlen: %d  %d off: %Ld   pos:%Ld\n", size, sc->header_len, offset, url_ftell(&s->pb));
-    if (sc->header_len > 0) {
-        av_new_packet(pkt, size + sc->header_len);
-        memcpy(pkt->data, sc->header_data, sc->header_len);
-        get_buffer(&s->pb, pkt->data + sc->header_len, size);
-        /* free header */
-        av_freep(&sc->header_data);
-        sc->header_len = 0;
-    } else {
-        av_new_packet(pkt, size);
-        get_buffer(&s->pb, pkt->data, pkt->size);
-    }
+    av_get_packet(&s->pb, pkt, size);
     pkt->stream_index = sc->ffindex;
     
     // If the keyframes table exists, mark any samples that are in the table as key frames.
@@ -2009,12 +2009,8 @@ readchunk:
             pts = dts + duration;
         }else
             pts = dts;
-        pkt->pts = av_rescale( pts,
-                         (int64_t)s->streams[sc->ffindex]->time_base.den,
-                         (int64_t)sc->time_scale * (int64_t)s->streams[sc->ffindex]->time_base.num );
-        pkt->dts = av_rescale( dts,
-                         (int64_t)s->streams[sc->ffindex]->time_base.den,
-                         (int64_t)sc->time_scale * (int64_t)s->streams[sc->ffindex]->time_base.num );
+        pkt->pts = pts;
+        pkt->dts = dts;
 #ifdef DEBUG
     av_log(NULL, AV_LOG_DEBUG, "stream #%d smp #%ld dts = %lld pts = %lld (smp:%ld time:%lld idx:%d ent:%d count:%d dur:%d)\n"
       , pkt->stream_index, sc->current_sample-1, pkt->dts, pkt->pts
@@ -2034,12 +2030,11 @@ readchunk:
 /**
  * Seek method based on the one described in the Appendix C of QTFileFormat.pdf
  */
-static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
+static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_time, int flags)
 {
     MOVContext* mov = (MOVContext *) s->priv_data;
     MOVStreamContext* sc;
     int32_t i, a, b, m;
-    int64_t sample_time;
     int64_t start_time;
     int32_t seek_sample, sample;
     int32_t duration;
@@ -2076,10 +2071,6 @@ static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
 #ifdef DEBUG
   av_log(s, AV_LOG_DEBUG, "Searching for time %li in stream #%i (time_scale=%i)\n", (long)timestamp, mov_idx, sc->time_scale);
 #endif
-    // convert timestamp from time_base unit to timescale unit
-    sample_time = av_rescale( timestamp,
-                            (int64_t)sc->time_scale * s->streams[stream_index]->time_base.num,
-                            (int64_t)s->streams[stream_index]->time_base.den);
     start_time = 0; // FIXME use elst atom
     sample = 1; // sample are 0 based in table
 #ifdef DEBUG