avformat/avienc: Store pal8 palette
[ffmpeg.git] / libavformat / nutenc.c
index dfb7992..b6582ef 100644 (file)
@@ -280,7 +280,7 @@ static void put_tt(NUTContext *nut, AVRational *time_base, AVIOContext *bc, uint
  */
 static void put_str(AVIOContext *bc, const char *string)
 {
-    int len = strlen(string);
+    size_t len = strlen(string);
 
     ff_put_v(bc, len);
     avio_write(bc, string, len);
@@ -524,7 +524,10 @@ static int write_streaminfo(NUTContext *nut, AVIOContext *bc, int stream_id) {
     }
     if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
         uint8_t buf[256];
-        snprintf(buf, sizeof(buf), "%d/%d", st->codec->time_base.den, st->codec->time_base.num);
+        if (st->r_frame_rate.num>0 && st->r_frame_rate.den>0)
+            snprintf(buf, sizeof(buf), "%d/%d", st->r_frame_rate.num, st->r_frame_rate.den);
+        else
+            snprintf(buf, sizeof(buf), "%d/%d", st->codec->time_base.den, st->codec->time_base.num);
         count += add_info(dyn_bc, "r_frame_rate", buf);
     }
     dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
@@ -584,7 +587,7 @@ static int write_index(NUTContext *nut, AVIOContext *bc) {
     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);
+        av_tree_find(nut->syncpoints, &dummy, 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;
     }
@@ -663,11 +666,8 @@ static int write_headers(AVFormatContext *avctx, AVIOContext *bc)
             return ret;
         if (ret > 0)
             put_packet(nut, bc, dyn_bc, 1, INFO_STARTCODE);
-        else {
-            uint8_t *buf;
-            avio_close_dyn_buf(dyn_bc, &buf);
-            av_free(buf);
-        }
+        else
+            ffio_free_dyn_buf(&dyn_bc);
     }
 
     for (i = 0; i < nut->avf->nb_chapters; i++) {
@@ -676,9 +676,7 @@ static int write_headers(AVFormatContext *avctx, AVIOContext *bc)
             return ret;
         ret = write_chapter(nut, dyn_bc, i);
         if (ret < 0) {
-            uint8_t *buf;
-            avio_close_dyn_buf(dyn_bc, &buf);
-            av_freep(&buf);
+            ffio_free_dyn_buf(&dyn_bc);
             return ret;
         }
         put_packet(nut, bc, dyn_bc, 1, INFO_STARTCODE);
@@ -698,7 +696,7 @@ static int nut_write_header(AVFormatContext *s)
     nut->avf = s;
 
     nut->version = FFMAX(NUT_STABLE_VERSION, 3 + !!nut->flags);
-    if (nut->flags && s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
+    if (nut->version > 3 && s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
         av_log(s, AV_LOG_ERROR,
                "The additional syncpoint modes require version %d, "
                "that is currently not finalized, "
@@ -722,7 +720,7 @@ static int nut_write_header(AVFormatContext *s)
         AVStream *st = s->streams[i];
         int ssize;
         AVRational time_base;
-        ff_parse_specific_params(st->codec, &time_base.den, &ssize, &time_base.num);
+        ff_parse_specific_params(st, &time_base.den, &ssize, &time_base.num);
 
         if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && st->codec->sample_rate) {
             time_base = (AVRational) {1, st->codec->sample_rate};
@@ -849,14 +847,18 @@ static int write_sm_data(AVFormatContext *s, AVIOContext *bc, AVPacket *pkt, int
         if (is_meta) {
             if (   pkt->side_data[i].type == AV_PKT_DATA_METADATA_UPDATE
                 || pkt->side_data[i].type == AV_PKT_DATA_STRINGS_METADATA) {
-                if (!size || data[size-1])
-                    return AVERROR(EINVAL);
+                if (!size || data[size-1]) {
+                    ret = AVERROR(EINVAL);
+                    goto fail;
+                }
                 while (data < data_end) {
                     const uint8_t *key = data;
                     const uint8_t *val = data + strlen(key) + 1;
 
-                    if(val >= data_end)
-                        return AVERROR(EINVAL);
+                    if(val >= data_end) {
+                        ret = AVERROR(EINVAL);
+                        goto fail;
+                    }
                     put_str(dyn_bc, key);
                     put_s(dyn_bc, -1);
                     put_str(dyn_bc, val);
@@ -931,18 +933,20 @@ static int write_sm_data(AVFormatContext *s, AVIOContext *bc, AVPacket *pkt, int
                 break;
             case AV_PKT_DATA_METADATA_UPDATE:
             case AV_PKT_DATA_STRINGS_METADATA:
+            case AV_PKT_DATA_QUALITY_STATS:
                 // belongs into meta, not side data
                 break;
             }
         }
     }
 
+fail:
     ff_put_v(bc, sm_data_count);
     dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
     avio_write(bc, dyn_buf, dyn_size);
     av_freep(&dyn_buf);
 
-    return 0;
+    return ret;
 }
 
 static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
@@ -956,15 +960,17 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
     int best_header_idx;
     int key_frame = !!(pkt->flags & AV_PKT_FLAG_KEY);
     int store_sp  = 0;
-    int ret;
+    int ret = 0;
     int sm_size = 0;
     int data_size = pkt->size;
-    uint8_t *sm_buf;
+    uint8_t *sm_buf = NULL;
 
     if (pkt->pts < 0) {
         av_log(s, AV_LOG_ERROR,
                "Negative pts not supported stream %d, pts %"PRId64"\n",
                pkt->stream_index, pkt->pts);
+        if (pkt->pts == AV_NOPTS_VALUE)
+            av_log(s, AV_LOG_ERROR, "Try to enable the genpts flag\n");
         return AVERROR(EINVAL);
     }
 
@@ -972,9 +978,12 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
         ret = avio_open_dyn_buf(&sm_bc);
         if (ret < 0)
             return ret;
-        write_sm_data(s, sm_bc, pkt, 0);
-        write_sm_data(s, sm_bc, pkt, 1);
+        ret = write_sm_data(s, sm_bc, pkt, 0);
+        if (ret >= 0)
+            ret = write_sm_data(s, sm_bc, pkt, 1);
         sm_size = avio_close_dyn_buf(sm_bc, &sm_buf);
+        if (ret < 0)
+            goto fail;
         data_size += sm_size;
     }
 
@@ -1016,7 +1025,7 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
         nut->last_syncpoint_pos = avio_tell(bc);
         ret                     = avio_open_dyn_buf(&dyn_bc);
         if (ret < 0)
-            return ret;
+            goto fail;
         put_tt(nut, nus->time_base, dyn_bc, pkt->dts);
         ff_put_v(dyn_bc, sp_pos != INT64_MAX ? (nut->last_syncpoint_pos - sp_pos) >> 4 : 0);
 
@@ -1028,15 +1037,17 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
 
         if (nut->write_index) {
         if ((ret = ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0 /*unused*/, pkt->dts)) < 0)
-            return ret;
+            goto fail;
 
         if ((1ll<<60) % nut->sp_count == 0)
             for (i=0; i<s->nb_streams; i++) {
                 int j;
                 StreamContext *nus = &nut->stream[i];
                 av_reallocp_array(&nus->keyframe_pts, 2*nut->sp_count, sizeof(*nus->keyframe_pts));
-                if (!nus->keyframe_pts)
-                    return AVERROR(ENOMEM);
+                if (!nus->keyframe_pts) {
+                    ret = AVERROR(ENOMEM);
+                    goto fail;
+                }
                 for (j=nut->sp_count == 1 ? 0 : nut->sp_count; j<2*nut->sp_count; j++)
                     nus->keyframe_pts[j] = AV_NOPTS_VALUE;
         }
@@ -1107,6 +1118,7 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
         }
     }
     av_assert0(frame_code != -1);
+
     fc           = &nut->frame_code[frame_code];
     flags        = fc->flags;
     needed_flags = get_needed_flags(nut, nus, fc, pkt);
@@ -1128,7 +1140,6 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
 
     if (flags & FLAG_SM_DATA) {
         avio_write(bc, sm_buf, sm_size);
-        av_freep(&sm_buf);
     }
     avio_write(bc, pkt->data + nut->header_len[header_idx], pkt->size - nut->header_len[header_idx]);
 
@@ -1153,14 +1164,17 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
         nut->max_pts_tb = nus->time_base;
     }
 
-    return 0;
+fail:
+    av_freep(&sm_buf);
+
+    return ret;
 }
 
 static int nut_write_trailer(AVFormatContext *s)
 {
     NUTContext *nut = s->priv_data;
     AVIOContext *bc = s->pb, *dyn_bc;
-    int i, ret;
+    int ret;
 
     while (nut->header_count < 3)
         write_headers(s, bc);
@@ -1172,15 +1186,22 @@ static int nut_write_trailer(AVFormatContext *s)
         put_packet(nut, bc, dyn_bc, 1, INDEX_STARTCODE);
     }
 
+    return 0;
+}
+
+static void nut_write_deinit(AVFormatContext *s)
+{
+    NUTContext *nut = s->priv_data;
+    int i;
+
     ff_nut_free_sp(nut);
-    for (i=0; i<s->nb_streams; i++)
-        av_freep(&nut->stream[i].keyframe_pts);
+    if (nut->stream)
+        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);
-
-    return 0;
 }
 
 #define OFFSET(x) offsetof(NUTContext, x)
@@ -1190,7 +1211,7 @@ static const AVOption options[] = {
     { "default",     "",                                                0,             AV_OPT_TYPE_CONST, {.i64 = 0},             INT_MIN, INT_MAX, E, "syncpoints" },
     { "none",        "Disable syncpoints, low overhead and unseekable", 0,             AV_OPT_TYPE_CONST, {.i64 = NUT_PIPE},      INT_MIN, INT_MAX, E, "syncpoints" },
     { "timestamped", "Extend syncpoints with a wallclock timestamp",    0,             AV_OPT_TYPE_CONST, {.i64 = NUT_BROADCAST}, INT_MIN, INT_MAX, E, "syncpoints" },
-    { "write_index", "Write index",                               OFFSET(write_index), AV_OPT_TYPE_INT,   {.i64 = 1},                   0,       1, E, },
+    { "write_index", "Write index",                               OFFSET(write_index), AV_OPT_TYPE_BOOL,  {.i64 = 1},                   0,       1, E, },
     { NULL },
 };
 
@@ -1213,6 +1234,7 @@ AVOutputFormat ff_nut_muxer = {
     .write_header   = nut_write_header,
     .write_packet   = nut_write_packet,
     .write_trailer  = nut_write_trailer,
+    .deinit         = nut_write_deinit,
     .flags          = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS,
     .codec_tag      = ff_nut_codec_tags,
     .priv_class     = &class,