Merge remote-tracking branch 'qatar/master'
[ffmpeg.git] / libavformat / asfenc.c
index 55d1871..23f1142 100644 (file)
@@ -19,6 +19,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 #include "avformat.h"
+#include "internal.h"
 #include "riff.h"
 #include "asf.h"
 #include "avio_internal.h"
@@ -29,7 +30,7 @@
 
 
 #define ASF_INDEXED_INTERVAL    10000000
-#define ASF_INDEX_BLOCK         600
+#define ASF_INDEX_BLOCK         (1<<9)
 
 #define ASF_PACKET_ERROR_CORRECTION_DATA_SIZE 0x2
 #define ASF_PACKET_ERROR_CORRECTION_FLAGS (\
@@ -207,23 +208,25 @@ typedef struct {
     /* only for reading */
     uint64_t data_offset;                ///< beginning of the first data packet
 
-    int64_t last_indexed_pts;
     ASFIndex* index_ptr;
-    uint32_t nb_index_count;
     uint32_t nb_index_memory_alloc;
     uint16_t maximum_packet;
+    uint32_t next_packet_number;
+    uint16_t next_packet_count;
+    int      next_start_sec;
+    int      end_sec;
 } ASFContext;
 
 static const AVCodecTag codec_asf_bmp_tags[] = {
-    { CODEC_ID_MPEG4, MKTAG('M', '4', 'S', '2') },
-    { CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') },
-    { CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') },
-    { CODEC_ID_NONE, 0 },
+    { AV_CODEC_ID_MPEG4, MKTAG('M', '4', 'S', '2') },
+    { AV_CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') },
+    { AV_CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') },
+    { AV_CODEC_ID_NONE, 0 },
 };
 
 #define PREROLL_TIME 3100
 
-static void put_guid(AVIOContext *s, const ff_asf_guid *g)
+void ff_put_guid(AVIOContext *s, const ff_asf_guid *g)
 {
     assert(sizeof(*g) == 16);
     avio_write(s, *g, sizeof(*g));
@@ -249,7 +252,7 @@ static int64_t put_header(AVIOContext *pb, const ff_asf_guid *g)
     int64_t pos;
 
     pos = avio_tell(pb);
-    put_guid(pb, g);
+    ff_put_guid(pb, g);
     avio_wl64(pb, 24);
     return pos;
 }
@@ -315,13 +318,13 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data
 
     duration = asf->duration + PREROLL_TIME * 10000;
     has_title = tags[0] || tags[1] || tags[2] || tags[3] || tags[4];
-    metadata_count = s->metadata ? s->metadata->count : 0;
+    metadata_count = av_dict_count(s->metadata);
 
     bit_rate = 0;
     for(n=0;n<s->nb_streams;n++) {
         enc = s->streams[n]->codec;
 
-        av_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */
+        avpriv_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */
 
         bit_rate += enc->bit_rate;
     }
@@ -330,7 +333,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data
         put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */
     }
 
-    put_guid(pb, &ff_asf_header);
+    ff_put_guid(pb, &ff_asf_header);
     avio_wl64(pb, -1); /* header length, will be patched after */
     avio_wl32(pb, 3 + has_title + !!metadata_count + s->nb_streams); /* number of chunks in header */
     avio_w8(pb, 1); /* ??? */
@@ -339,7 +342,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data
     /* file header */
     header_offset = avio_tell(pb);
     hpos = put_header(pb, &ff_asf_file_header);
-    put_guid(pb, &ff_asf_my_guid);
+    ff_put_guid(pb, &ff_asf_my_guid);
     avio_wl64(pb, file_size);
     file_time = 0;
     avio_wl64(pb, unix_to_file_time(file_time));
@@ -355,7 +358,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data
 
     /* unknown headers */
     hpos = put_header(pb, &ff_asf_head1_guid);
-    put_guid(pb, &ff_asf_head2_guid);
+    ff_put_guid(pb, &ff_asf_head2_guid);
     avio_wl32(pb, 6);
     avio_wl16(pb, 0);
     end_header(pb, hpos);
@@ -399,7 +402,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data
 
         enc = s->streams[n]->codec;
         asf->streams[n].num = n + 1;
-        asf->streams[n].seq = 0;
+        asf->streams[n].seq = 1;
 
 
         switch(enc->codec_type) {
@@ -418,11 +421,11 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data
 
         hpos = put_header(pb, &ff_asf_stream_header);
         if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
-            put_guid(pb, &ff_asf_audio_stream);
-            put_guid(pb, &ff_asf_audio_conceal_spread);
+            ff_put_guid(pb, &ff_asf_audio_stream);
+            ff_put_guid(pb, &ff_asf_audio_conceal_spread);
         } else {
-            put_guid(pb, &ff_asf_video_stream);
-            put_guid(pb, &ff_asf_video_conceal_none);
+            ff_put_guid(pb, &ff_asf_video_stream);
+            ff_put_guid(pb, &ff_asf_video_conceal_none);
         }
         avio_wl64(pb, 0); /* ??? */
         es_pos = avio_tell(pb);
@@ -434,10 +437,6 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data
         if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
             /* WAVEFORMATEX header */
             int wavsize = ff_put_wav_header(pb, enc);
-            if ((enc->codec_id != CODEC_ID_MP3) && (enc->codec_id != CODEC_ID_MP2) && (enc->codec_id != CODEC_ID_ADPCM_IMA_WAV) && (enc->extradata_size==0)) {
-                wavsize += 2;
-                avio_wl16(pb, 0);
-            }
 
             if (wavsize < 0)
                 return -1;
@@ -449,7 +448,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data
             }
             /* ERROR Correction */
             avio_w8(pb, 0x01);
-            if(enc->codec_id == CODEC_ID_ADPCM_G726 || !enc->block_align){
+            if(enc->codec_id == AV_CODEC_ID_ADPCM_G726 || !enc->block_align){
                 avio_wl16(pb, 0x0190);
                 avio_wl16(pb, 0x0190);
             }else{
@@ -473,7 +472,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data
     /* media comments */
 
     hpos = put_header(pb, &ff_asf_codec_comment_header);
-    put_guid(pb, &ff_asf_codec_comment1_header);
+    ff_put_guid(pb, &ff_asf_codec_comment1_header);
     avio_wl32(pb, s->nb_streams);
     for(n=0;n<s->nb_streams;n++) {
         AVCodec *p;
@@ -492,7 +491,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data
         else
             avio_wl16(pb, -1);
 
-        if(enc->codec_id == CODEC_ID_WMAV2)
+        if(enc->codec_id == AV_CODEC_ID_WMAV2)
             desc = "Windows Media Audio V8";
         else
             desc = p ? p->name : enc->codec_name;
@@ -544,9 +543,9 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data
 
     /* movie chunk, followed by packets of packet_size */
     asf->data_offset = cur_pos;
-    put_guid(pb, &ff_asf_data_header);
+    ff_put_guid(pb, &ff_asf_data_header);
     avio_wl64(pb, data_chunk_size);
-    put_guid(pb, &ff_asf_my_guid);
+    ff_put_guid(pb, &ff_asf_my_guid);
     avio_wl64(pb, asf->nb_packets); /* nb packets */
     avio_w8(pb, 1); /* ??? */
     avio_w8(pb, 1); /* ??? */
@@ -560,10 +559,8 @@ static int asf_write_header(AVFormatContext *s)
     s->packet_size  = PACKET_SIZE;
     asf->nb_packets = 0;
 
-    asf->last_indexed_pts = 0;
     asf->index_ptr = av_malloc( sizeof(ASFIndex) * ASF_INDEX_BLOCK );
     asf->nb_index_memory_alloc = ASF_INDEX_BLOCK;
-    asf->nb_index_count = 0;
     asf->maximum_packet = 0;
 
     /* the data-chunk-size has to be 50, which is data_size - asf->data_offset
@@ -785,14 +782,42 @@ static void put_frame(
     stream->seq++;
 }
 
+static void update_index(AVFormatContext *s, int start_sec,
+                         uint32_t packet_number, uint16_t packet_count)
+{
+    ASFContext *asf = s->priv_data;
+
+    if (start_sec > asf->next_start_sec) {
+        int i;
+
+        if (!asf->next_start_sec) {
+            asf->next_packet_number = packet_number;
+            asf->next_packet_count  = packet_count;
+        }
+
+        if (start_sec > asf->nb_index_memory_alloc) {
+            asf->nb_index_memory_alloc = (start_sec + ASF_INDEX_BLOCK) & ~(ASF_INDEX_BLOCK - 1);
+            asf->index_ptr = av_realloc( asf->index_ptr, sizeof(ASFIndex) * asf->nb_index_memory_alloc );
+        }
+        for (i = asf->next_start_sec; i < start_sec; i++) {
+            asf->index_ptr[i].packet_number = asf->next_packet_number;
+            asf->index_ptr[i].packet_count  = asf->next_packet_count;
+        }
+    }
+    asf->maximum_packet     = FFMAX(asf->maximum_packet, packet_count);
+    asf->next_packet_number = packet_number;
+    asf->next_packet_count  = packet_count;
+    asf->next_start_sec     = start_sec;
+}
+
 static int asf_write_packet(AVFormatContext *s, AVPacket *pkt)
 {
     ASFContext *asf = s->priv_data;
     ASFStream *stream;
-    int64_t duration;
     AVCodecContext *codec;
-    int64_t packet_st,pts;
-    int start_sec,i;
+    uint32_t packet_number;
+    int64_t pts;
+    int start_sec;
     int flags= pkt->flags;
 
     codec = s->streams[pkt->stream_index]->codec;
@@ -803,30 +828,22 @@ static int asf_write_packet(AVFormatContext *s, AVPacket *pkt)
 
     pts = (pkt->pts != AV_NOPTS_VALUE) ? pkt->pts : pkt->dts;
     assert(pts != AV_NOPTS_VALUE);
-    duration = pts * 10000;
-    asf->duration= FFMAX(asf->duration, duration + pkt->duration * 10000);
+    pts *= 10000;
+    asf->duration= FFMAX(asf->duration, pts + pkt->duration * 10000);
 
-    packet_st = asf->nb_packets;
+    packet_number = asf->nb_packets;
     put_frame(s, stream, s->streams[pkt->stream_index], pkt->dts, pkt->data, pkt->size, flags);
 
+    start_sec = (int)((PREROLL_TIME * 10000 + pts + ASF_INDEXED_INTERVAL - 1)
+              / ASF_INDEXED_INTERVAL);
+
     /* check index */
     if ((!asf->is_streamed) && (flags & AV_PKT_FLAG_KEY)) {
-        start_sec = (int)(duration / INT64_C(10000000));
-        if (start_sec != (int)(asf->last_indexed_pts / INT64_C(10000000))) {
-            for(i=asf->nb_index_count;i<start_sec;i++) {
-                if (i>=asf->nb_index_memory_alloc) {
-                    asf->nb_index_memory_alloc += ASF_INDEX_BLOCK;
-                    asf->index_ptr = (ASFIndex*)av_realloc( asf->index_ptr, sizeof(ASFIndex) * asf->nb_index_memory_alloc );
-                }
-                // store
-                asf->index_ptr[i].packet_number = (uint32_t)packet_st;
-                asf->index_ptr[i].packet_count  = (uint16_t)(asf->nb_packets-packet_st);
-                asf->maximum_packet = FFMAX(asf->maximum_packet, (uint16_t)(asf->nb_packets-packet_st));
-            }
-            asf->nb_index_count = start_sec;
-            asf->last_indexed_pts = duration;
-        }
+        uint16_t packet_count = asf->nb_packets - packet_number;
+        update_index(s, start_sec, packet_number, packet_count);
     }
+    asf->end_sec = start_sec;
+
     return 0;
 }
 
@@ -836,9 +853,9 @@ static int asf_write_index(AVFormatContext *s, ASFIndex *index, uint16_t max, ui
     AVIOContext *pb = s->pb;
     int i;
 
-    put_guid(pb, &ff_asf_simple_index_header);
+    ff_put_guid(pb, &ff_asf_simple_index_header);
     avio_wl64(pb, 24 + 16 + 8 + 4 + 4 + (4 + 2)*count);
-    put_guid(pb, &ff_asf_my_guid);
+    ff_put_guid(pb, &ff_asf_my_guid);
     avio_wl64(pb, ASF_INDEXED_INTERVAL);
     avio_wl32(pb, max);
     avio_wl32(pb, count);
@@ -861,8 +878,9 @@ static int asf_write_trailer(AVFormatContext *s)
 
     /* write index */
     data_size = avio_tell(s->pb);
-    if ((!asf->is_streamed) && (asf->nb_index_count != 0)) {
-        asf_write_index(s, asf->index_ptr, asf->maximum_packet, asf->nb_index_count);
+    if (!asf->is_streamed && asf->next_start_sec) {
+        update_index(s, asf->end_sec + 1, 0, 0);
+        asf_write_index(s, asf->index_ptr, asf->maximum_packet, asf->next_start_sec);
     }
     avio_flush(s->pb);
 
@@ -883,41 +901,37 @@ static int asf_write_trailer(AVFormatContext *s)
 #if CONFIG_ASF_MUXER
 AVOutputFormat ff_asf_muxer = {
     .name           = "asf",
-    .long_name      = NULL_IF_CONFIG_SMALL("ASF format"),
+    .long_name      = NULL_IF_CONFIG_SMALL("ASF (Advanced / Active Streaming Format)"),
     .mime_type      = "video/x-ms-asf",
     .extensions     = "asf,wmv,wma",
     .priv_data_size = sizeof(ASFContext),
-#if CONFIG_LIBMP3LAME
-    .audio_codec    = CODEC_ID_MP3,
-#else
-    .audio_codec    = CODEC_ID_MP2,
-#endif
-    .video_codec    = CODEC_ID_MSMPEG4V3,
+    .audio_codec    = AV_CODEC_ID_WMAV2,
+    .video_codec    = AV_CODEC_ID_MSMPEG4V3,
     .write_header   = asf_write_header,
     .write_packet   = asf_write_packet,
     .write_trailer  = asf_write_trailer,
-    .flags = AVFMT_GLOBALHEADER,
-    .codec_tag= (const AVCodecTag* const []){codec_asf_bmp_tags, ff_codec_bmp_tags, ff_codec_wav_tags, 0},
+    .flags          = AVFMT_GLOBALHEADER,
+    .codec_tag      = (const AVCodecTag* const []){
+        codec_asf_bmp_tags, ff_codec_bmp_tags, ff_codec_wav_tags, 0
+    },
 };
 #endif
 
 #if CONFIG_ASF_STREAM_MUXER
 AVOutputFormat ff_asf_stream_muxer = {
     .name           = "asf_stream",
-    .long_name      = NULL_IF_CONFIG_SMALL("ASF format"),
+    .long_name      = NULL_IF_CONFIG_SMALL("ASF (Advanced / Active Streaming Format)"),
     .mime_type      = "video/x-ms-asf",
     .extensions     = "asf,wmv,wma",
     .priv_data_size = sizeof(ASFContext),
-#if CONFIG_LIBMP3LAME
-    .audio_codec    = CODEC_ID_MP3,
-#else
-    .audio_codec    = CODEC_ID_MP2,
-#endif
-    .video_codec    = CODEC_ID_MSMPEG4V3,
+    .audio_codec    = AV_CODEC_ID_WMAV2,
+    .video_codec    = AV_CODEC_ID_MSMPEG4V3,
     .write_header   = asf_write_stream_header,
     .write_packet   = asf_write_packet,
     .write_trailer  = asf_write_trailer,
-    .flags = AVFMT_GLOBALHEADER,
-    .codec_tag= (const AVCodecTag* const []){codec_asf_bmp_tags, ff_codec_bmp_tags, ff_codec_wav_tags, 0},
+    .flags          = AVFMT_GLOBALHEADER,
+    .codec_tag      = (const AVCodecTag* const []){
+        codec_asf_bmp_tags, ff_codec_bmp_tags, ff_codec_wav_tags, 0
+    },
 };
 #endif //CONFIG_ASF_STREAM_MUXER