]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/nutenc.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavformat / nutenc.c
index bd10b2965b07988ebf736362e46ec8f7c05fc133..c24a21a2b80d953778a644d31dd631d983ccf832 100644 (file)
@@ -37,20 +37,20 @@ static int find_expected_header(AVCodecContext *c, int size, int key_frame, uint
 
     AV_WB24(out, 1);
 
-    if(c->codec_id == CODEC_ID_MPEG4){
+    if(c->codec_id == AV_CODEC_ID_MPEG4){
         if(key_frame){
             return 3;
         }else{
             out[3]= 0xB6;
             return 4;
         }
-    }else if(c->codec_id == CODEC_ID_MPEG1VIDEO || c->codec_id == CODEC_ID_MPEG2VIDEO){
+    }else if(c->codec_id == AV_CODEC_ID_MPEG1VIDEO || c->codec_id == AV_CODEC_ID_MPEG2VIDEO){
         return 3;
-    }else if(c->codec_id == CODEC_ID_H264){
+    }else if(c->codec_id == AV_CODEC_ID_H264){
         return 3;
-    }else if(c->codec_id == CODEC_ID_MP3 || c->codec_id == CODEC_ID_MP2){
+    }else if(c->codec_id == AV_CODEC_ID_MP3 || c->codec_id == AV_CODEC_ID_MP2){
         int lsf, mpeg25, sample_rate_index, bitrate_index, frame_size;
-        int layer= c->codec_id == CODEC_ID_MP3 ? 3 : 2;
+        int layer= c->codec_id == AV_CODEC_ID_MP3 ? 3 : 2;
         unsigned int header= 0xFFF00000;
 
         lsf     = sample_rate < (24000+32000)/2;
@@ -211,7 +211,7 @@ static void build_frame_code(AVFormatContext *s){
             pred_table[2]=1;
             pred_table[3]=3;
             pred_table[4]=4;
-        }else if(codec->codec_id == CODEC_ID_VORBIS){
+        }else if(codec->codec_id == AV_CODEC_ID_VORBIS){
             pred_count=3;
             pred_table[0]=2;
             pred_table[1]=9;
@@ -462,6 +462,7 @@ static int write_globalinfo(NUTContext *nut, AVIOContext *bc){
 static int write_streaminfo(NUTContext *nut, AVIOContext *bc, int stream_id){
     AVFormatContext *s= nut->avf;
     AVStream* st = s->streams[stream_id];
+    AVDictionaryEntry *t = NULL;
     AVIOContext *dyn_bc;
     uint8_t *dyn_buf=NULL;
     int count=0, dyn_size, i;
@@ -469,6 +470,8 @@ static int write_streaminfo(NUTContext *nut, AVIOContext *bc, int stream_id){
     if(ret < 0)
         return ret;
 
+    while ((t = av_dict_get(st->metadata, "", t, AV_DICT_IGNORE_SUFFIX)))
+        count += add_info(dyn_bc, t->key, t->value);
     for (i=0; ff_nut_dispositions[i].flag; ++i) {
         if (st->disposition & ff_nut_dispositions[i].flag)
             count += add_info(dyn_bc, "Disposition", ff_nut_dispositions[i].str);
@@ -518,6 +521,51 @@ static int write_chapter(NUTContext *nut, AVIOContext *bc, int id)
     return 0;
 }
 
+static int write_index(NUTContext *nut, AVIOContext *bc){
+    int i;
+    Syncpoint dummy= { .pos= 0 };
+    Syncpoint *next_node[2] = { NULL };
+    int64_t startpos = avio_tell(bc);
+    int64_t payload_size;
+
+    put_tt(nut, nut->max_pts_tb, bc, nut->max_pts);
+
+    ff_put_v(bc, nut->sp_count);
+
+    for(i=0; i<nut->sp_count; i++){
+        av_tree_find(nut->syncpoints, &dummy, (void *) ff_nut_sp_pos_cmp, (void**)next_node);
+        ff_put_v(bc, (next_node[1]->pos >> 4) - (dummy.pos>>4));
+        dummy.pos = next_node[1]->pos;
+    }
+
+    for(i=0; i<nut->avf->nb_streams; i++){
+        StreamContext *nus= &nut->stream[i];
+        int64_t last_pts= -1;
+        int j, k;
+        for(j=0; j<nut->sp_count; j++){
+            int flag = (nus->keyframe_pts[j] != AV_NOPTS_VALUE) ^ (j+1 == nut->sp_count);
+            int n = 0;
+            for(; j<nut->sp_count && (nus->keyframe_pts[j] != AV_NOPTS_VALUE) == flag; j++)
+                n++;
+
+            ff_put_v(bc, 1 + 2*flag + 4*n);
+            for(k= j - n; k<=j && k<nut->sp_count; k++) {
+                if(nus->keyframe_pts[k] == AV_NOPTS_VALUE)
+                    continue;
+                av_assert0(nus->keyframe_pts[k] > last_pts);
+                ff_put_v(bc, nus->keyframe_pts[k] - last_pts);
+                last_pts = nus->keyframe_pts[k];
+            }
+        }
+    }
+
+    payload_size = avio_tell(bc) - startpos + 8 + 4;
+
+    avio_wb64(bc, 8 + payload_size + av_log2(payload_size) / 7 + 1 + 4*(payload_size > 4096));
+
+    return 0;
+}
+
 static int write_headers(AVFormatContext *avctx, AVIOContext *bc){
     NUTContext *nut = avctx->priv_data;
     AVIOContext *dyn_bc;
@@ -704,8 +752,10 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt){
     int store_sp=0;
     int ret;
 
-    if(pkt->pts < 0)
-        return -1;
+    if (pkt->pts < 0) {
+        av_log(s, AV_LOG_ERROR, "Invalid negative packet pts %"PRId64" in input\n", pkt->pts);
+        return AVERROR(EINVAL);
+    }
 
     if(1LL<<(20+3*nut->header_count) <= avio_tell(bc))
         write_headers(s, bc);
@@ -745,6 +795,17 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt){
         put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE);
 
         ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0/*unused*/, pkt->dts);
+
+        if((1ll<<60) % nut->sp_count == 0)
+            for(i=0; i<s->nb_streams; i++){
+                int j;
+                StreamContext *nus = &nut->stream[i];
+                nus->keyframe_pts = av_realloc(nus->keyframe_pts, 2*nut->sp_count*sizeof(*nus->keyframe_pts));
+                if(!nus->keyframe_pts)
+                    return AVERROR(ENOMEM);
+                for(j=nut->sp_count == 1 ? 0 : nut->sp_count; j<2*nut->sp_count; j++)
+                    nus->keyframe_pts[j] = AV_NOPTS_VALUE;
+        }
     }
     av_assert0(nus->last_pts != AV_NOPTS_VALUE);
 
@@ -835,7 +896,7 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt){
     nus->last_pts= pkt->pts;
 
     //FIXME just store one per syncpoint
-    if(flags & FLAG_KEY)
+    if(flags & FLAG_KEY) {
         av_add_index_entry(
             s->streams[pkt->stream_index],
             nut->last_syncpoint_pos,
@@ -843,18 +904,37 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt){
             0,
             0,
             AVINDEX_KEYFRAME);
+        if(nus->keyframe_pts && nus->keyframe_pts[nut->sp_count] == AV_NOPTS_VALUE)
+            nus->keyframe_pts[nut->sp_count] = pkt->pts;
+    }
+
+    if(!nut->max_pts_tb || av_compare_ts(nut->max_pts, *nut->max_pts_tb, pkt->pts, *nus->time_base) < 0) {
+        nut->max_pts = pkt->pts;
+        nut->max_pts_tb = nus->time_base;
+    }
 
     return 0;
 }
 
 static int nut_write_trailer(AVFormatContext *s){
     NUTContext *nut= s->priv_data;
-    AVIOContext *bc= s->pb;
+    AVIOContext *bc = s->pb, *dyn_bc;
+    int i, ret;
 
     while(nut->header_count<3)
         write_headers(s, bc);
+
+    ret = avio_open_dyn_buf(&dyn_bc);
+    if(ret >= 0) {
+        write_index(nut, dyn_bc);
+        put_packet(nut, bc, dyn_bc, 1, INDEX_STARTCODE);
+    }
+
     avio_flush(bc);
     ff_nut_free_sp(nut);
+    for(i=0; i<s->nb_streams; i++)
+        av_freep(&nut->stream[i].keyframe_pts);
+
     av_freep(&nut->stream);
     av_freep(&nut->chapter);
     av_freep(&nut->time_base);
@@ -864,18 +944,13 @@ static int nut_write_trailer(AVFormatContext *s){
 
 AVOutputFormat ff_nut_muxer = {
     .name           = "nut",
-    .long_name      = NULL_IF_CONFIG_SMALL("NUT format"),
+    .long_name      = NULL_IF_CONFIG_SMALL("NUT"),
     .mime_type      = "video/x-nut",
     .extensions     = "nut",
     .priv_data_size = sizeof(NUTContext),
-#if   CONFIG_LIBVORBIS
-    .audio_codec    = CODEC_ID_VORBIS,
-#elif CONFIG_LIBMP3LAME
-    .audio_codec    = CODEC_ID_MP3,
-#else
-    .audio_codec    = CODEC_ID_MP2,
-#endif
-    .video_codec    = CODEC_ID_MPEG4,
+    .audio_codec    = CONFIG_LIBVORBIS ? AV_CODEC_ID_VORBIS :
+                      CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_MP2,
+    .video_codec    = AV_CODEC_ID_MPEG4,
     .write_header   = nut_write_header,
     .write_packet   = nut_write_packet,
     .write_trailer  = nut_write_trailer,