nutenc.c 38.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * nut muxer
 * Copyright (c) 2004-2007 Michael Niedermayer
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

22 23
#include <stdint.h>

24
#include "libavutil/intreadwrite.h"
25
#include "libavutil/mathematics.h"
26
#include "libavutil/tree.h"
27
#include "libavutil/dict.h"
28
#include "libavutil/avassert.h"
29
#include "libavcodec/bytestream.h"
30
#include "libavcodec/mpegaudiodata.h"
31
#include "nut.h"
32
#include "internal.h"
33
#include "avio_internal.h"
34
#include "riff.h"
35

36 37 38 39
static int find_expected_header(AVCodecContext *c, int size, int key_frame,
                                uint8_t out[64])
{
    int sample_rate = c->sample_rate;
40

41
    if (size > 4096)
42 43 44 45
        return 0;

    AV_WB24(out, 1);

46 47
    if (c->codec_id == AV_CODEC_ID_MPEG4) {
        if (key_frame) {
48
            return 3;
49 50
        } else {
            out[3] = 0xB6;
51 52
            return 4;
        }
53 54
    } else if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO ||
               c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
55
        return 3;
56
    } else if (c->codec_id == AV_CODEC_ID_H264) {
57
        return 3;
58 59
    } else if (c->codec_id == AV_CODEC_ID_MP3 ||
               c->codec_id == AV_CODEC_ID_MP2) {
60
        int lsf, mpeg25, sample_rate_index, bitrate_index, frame_size;
61 62
        int layer           = c->codec_id == AV_CODEC_ID_MP3 ? 3 : 2;
        unsigned int header = 0xFFF00000;
63

64 65
        lsf           = sample_rate < (24000 + 32000) / 2;
        mpeg25        = sample_rate < (12000 + 16000) / 2;
66
        sample_rate <<= lsf + mpeg25;
67 68 69
        if      (sample_rate < (32000 + 44100) / 2) sample_rate_index = 2;
        else if (sample_rate < (44100 + 48000) / 2) sample_rate_index = 0;
        else                                        sample_rate_index = 1;
70

71
        sample_rate = avpriv_mpa_freq_tab[sample_rate_index] >> (lsf + mpeg25);
72

73 74 75 76 77
        for (bitrate_index = 2; bitrate_index < 30; bitrate_index++) {
            frame_size =
                avpriv_mpa_bitrate_tab[lsf][layer - 1][bitrate_index >> 1];
            frame_size = (frame_size * 144000) / (sample_rate << lsf) +
                (bitrate_index & 1);
78

79
            if (frame_size == size)
80 81 82
                break;
        }

83 84 85
        header |= (!lsf) << 19;
        header |= (4 - layer) << 17;
        header |= 1 << 16; //no crc
86
        AV_WB32(out, header);
87 88 89 90
        if (size <= 0)
            return 2;  //we guess there is no crc, if there is one the user clearly does not care about overhead
        if (bitrate_index == 30)
            return -1;  //something is wrong ...
91

92 93 94
        header |= (bitrate_index >> 1) << 12;
        header |= sample_rate_index << 10;
        header |= (bitrate_index & 1) << 9;
95 96

        return 2; //FIXME actually put the needed ones in build_elision_headers()
97
        //return 3; //we guess that the private bit is not set
Diego Biurrun's avatar
Diego Biurrun committed
98
//FIXME the above assumptions should be checked, if these turn out false too often something should be done
99 100 101 102
    }
    return 0;
}

103
static int find_header_idx(AVFormatContext *s, AVCodecContext *c, int size, int frame_type)
104
{
105 106 107
    NUTContext *nut = s->priv_data;
    uint8_t out[64];
    int i;
108
    int len = find_expected_header(c, size, frame_type, out);
109

110 111
    for (i = 1; i < nut->header_count; i++) {
        if (len == nut->header_len[i] && !memcmp(out, nut->header[i], len)) {
112 113 114
            return i;
        }
    }
115

116 117 118
    return 0;
}

119 120
static void build_elision_headers(AVFormatContext *s)
{
121 122 123 124
    NUTContext *nut = s->priv_data;
    int i;
    //FIXME this is lame
    //FIXME write a 2pass mode to find the maximal headers
125 126 127 128 129 130 131
    static const uint8_t headers[][5] = {
        { 3, 0x00, 0x00, 0x01 },
        { 4, 0x00, 0x00, 0x01, 0xB6},
        { 2, 0xFF, 0xFA }, //mp3+crc
        { 2, 0xFF, 0xFB }, //mp3
        { 2, 0xFF, 0xFC }, //mp2+crc
        { 2, 0xFF, 0xFD }, //mp2
132 133
    };

134 135 136 137
    nut->header_count = 7;
    for (i = 1; i < nut->header_count; i++) {
        nut->header_len[i] = headers[i - 1][0];
        nut->header[i]     = &headers[i - 1][1];
138 139
    }
}
140

141 142
static void build_frame_code(AVFormatContext *s)
{
143 144
    NUTContext *nut = s->priv_data;
    int key_frame, index, pred, stream_id;
145 146 147
    int start = 1;
    int end   = 254;
    int keyframe_0_esc = s->nb_streams > 2;
148
    int pred_table[10];
149 150
    FrameCode *ft;

151 152 153 154
    ft            = &nut->frame_code[start];
    ft->flags     = FLAG_CODED;
    ft->size_mul  = 1;
    ft->pts_delta = 1;
155
    start++;
156

157
    if (keyframe_0_esc) {
158
        /* keyframe = 0 escape */
159 160 161
        FrameCode *ft = &nut->frame_code[start];
        ft->flags    = FLAG_STREAM_ID | FLAG_SIZE_MSB | FLAG_CODED_PTS;
        ft->size_mul = 1;
162 163 164
        start++;
    }

165 166 167
    for (stream_id = 0; stream_id < s->nb_streams; stream_id++) {
        int start2 = start + (end - start) * stream_id       / s->nb_streams;
        int end2   = start + (end - start) * (stream_id + 1) / s->nb_streams;
168
        AVCodecContext *codec = s->streams[stream_id]->codec;
169 170
        int is_audio          = codec->codec_type == AVMEDIA_TYPE_AUDIO;
        int intra_only        = /*codec->intra_only || */ is_audio;
171
        int pred_count;
172 173 174 175 176 177 178 179
        int frame_size = 0;

        if (codec->codec_type == AVMEDIA_TYPE_AUDIO) {
            frame_size = av_get_audio_frame_duration(codec, 0);
            if (codec->codec_id == AV_CODEC_ID_VORBIS && !frame_size)
                frame_size = 64;
        } else {
            AVRational f = av_div_q(codec->time_base, *nut->stream[stream_id].time_base);
180
            if (f.den == 1 && f.num>0)
181
                frame_size = f.num;
182
        }
183
        if (!frame_size)
184
            frame_size = 1;
185

186 187 188 189 190 191 192 193 194
        for (key_frame = 0; key_frame < 2; key_frame++) {
            if (!intra_only || !keyframe_0_esc || key_frame != 0) {
                FrameCode *ft = &nut->frame_code[start2];
                ft->flags     = FLAG_KEY * key_frame;
                ft->flags    |= FLAG_SIZE_MSB | FLAG_CODED_PTS;
                ft->stream_id = stream_id;
                ft->size_mul  = 1;
                if (is_audio)
                    ft->header_idx = find_header_idx(s, codec, -1, key_frame);
195 196 197 198
                start2++;
            }
        }

199
        key_frame = intra_only;
200
#if 1
201 202 203
        if (is_audio) {
            int frame_bytes = codec->frame_size * (int64_t)codec->bit_rate /
                              (8 * codec->sample_rate);
204
            int pts;
205
            for (pts = 0; pts < 2; pts++) {
206
                for (pred = 0; pred < 2; pred++) {
207
                    FrameCode *ft  = &nut->frame_code[start2];
208 209 210 211
                    ft->flags      = FLAG_KEY * key_frame;
                    ft->stream_id  = stream_id;
                    ft->size_mul   = frame_bytes + 2;
                    ft->size_lsb   = frame_bytes + pred;
212
                    ft->pts_delta  = pts * frame_size;
213
                    ft->header_idx = find_header_idx(s, codec, frame_bytes + pred, key_frame);
214 215 216
                    start2++;
                }
            }
217 218 219 220 221
        } else {
            FrameCode *ft = &nut->frame_code[start2];
            ft->flags     = FLAG_KEY | FLAG_SIZE_MSB;
            ft->stream_id = stream_id;
            ft->size_mul  = 1;
222
            ft->pts_delta = frame_size;
223 224
            start2++;
        }
225
#endif
226

227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
        if (codec->has_b_frames) {
            pred_count    = 5;
            pred_table[0] = -2;
            pred_table[1] = -1;
            pred_table[2] = 1;
            pred_table[3] = 3;
            pred_table[4] = 4;
        } else if (codec->codec_id == AV_CODEC_ID_VORBIS) {
            pred_count    = 3;
            pred_table[0] = 2;
            pred_table[1] = 9;
            pred_table[2] = 16;
        } else {
            pred_count    = 1;
            pred_table[0] = 1;
242 243
        }

244 245 246
        for (pred = 0; pred < pred_count; pred++) {
            int start3 = start2 + (end2 - start2) * pred / pred_count;
            int end3   = start2 + (end2 - start2) * (pred + 1) / pred_count;
247

248 249
            pred_table[pred] *= frame_size;

250 251 252 253 254
            for (index = start3; index < end3; index++) {
                FrameCode *ft = &nut->frame_code[index];
                ft->flags     = FLAG_KEY * key_frame;
                ft->flags    |= FLAG_SIZE_MSB;
                ft->stream_id = stream_id;
255
//FIXME use single byte size and pred from last
256 257 258 259 260
                ft->size_mul  = end3 - start3;
                ft->size_lsb  = index - start3;
                ft->pts_delta = pred_table[pred];
                if (is_audio)
                    ft->header_idx = find_header_idx(s, codec, -1, key_frame);
261 262 263
            }
        }
    }
264
    memmove(&nut->frame_code['N' + 1], &nut->frame_code['N'], sizeof(FrameCode) * (255 - 'N'));
265 266 267
    nut->frame_code[0].flags       =
        nut->frame_code[255].flags =
        nut->frame_code['N'].flags = FLAG_INVALID;
268 269
}

270
static void put_tt(NUTContext *nut, AVRational *time_base, AVIOContext *bc, uint64_t val)
271
{
Michael Niedermayer's avatar
Michael Niedermayer committed
272
    val *= nut->time_base_count;
Anton Khirnov's avatar
Anton Khirnov committed
273
    val += time_base - nut->time_base;
274
    ff_put_v(bc, val);
Michael Niedermayer's avatar
Michael Niedermayer committed
275
}
276
/**
277
 * Store a string as vb.
278
 */
279 280 281
static void put_str(AVIOContext *bc, const char *string)
{
    int len = strlen(string);
282

283
    ff_put_v(bc, len);
284
    avio_write(bc, string, len);
285 286
}

287 288 289
static void put_s(AVIOContext *bc, int64_t val)
{
    ff_put_v(bc, 2 * FFABS(val) - (val > 0));
290 291 292
}

#ifdef TRACE
293 294 295
static inline void ff_put_v_trace(AVIOContext *bc, uint64_t v, const char *file,
                                  const char *func, int line)
{
296
    av_log(NULL, AV_LOG_DEBUG, "ff_put_v %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line);
297

298
    ff_put_v(bc, v);
299 300
}

301
static inline void put_s_trace(AVIOContext *bc, int64_t v, const char *file, const char *func, int line)
302
{
Michael Niedermayer's avatar
Michael Niedermayer committed
303
    av_log(NULL, AV_LOG_DEBUG, "put_s %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line);
304 305 306

    put_s(bc, v);
}
307
#define ff_put_v(bc, v)  ff_put_v_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
308 309 310
#define put_s(bc, v)  put_s_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#endif

Michael Niedermayer's avatar
Michael Niedermayer committed
311
//FIXME remove calculate_checksum
312 313 314 315 316 317
static void put_packet(NUTContext *nut, AVIOContext *bc, AVIOContext *dyn_bc,
                       int calculate_checksum, uint64_t startcode)
{
    uint8_t *dyn_buf = NULL;
    int dyn_size     = avio_close_dyn_buf(dyn_bc, &dyn_buf);
    int forw_ptr     = dyn_size + 4 * calculate_checksum;
Michael Niedermayer's avatar
Michael Niedermayer committed
318

319
    if (forw_ptr > 4096)
320
        ffio_init_checksum(bc, ff_crc04C11DB7_update, 0);
321
    avio_wb64(bc, startcode);
322
    ff_put_v(bc, forw_ptr);
323
    if (forw_ptr > 4096)
324
        avio_wl32(bc, ffio_get_checksum(bc));
325

326
    if (calculate_checksum)
327
        ffio_init_checksum(bc, ff_crc04C11DB7_update, 0);
328
    avio_write(bc, dyn_buf, dyn_size);
329
    if (calculate_checksum)
330
        avio_wl32(bc, ffio_get_checksum(bc));
331

332
    av_free(dyn_buf);
333 334
}

335 336 337 338
static void write_mainheader(NUTContext *nut, AVIOContext *bc)
{
    int i, j, tmp_pts, tmp_flags, tmp_stream, tmp_mul, tmp_size, tmp_fields,
        tmp_head_idx;
339
    int64_t tmp_match;
340

341
    ff_put_v(bc, nut->version = NUT_VERSION);
342 343
    if (nut->version > 3)
        ff_put_v(bc, nut->minor_version);
344 345 346
    ff_put_v(bc, nut->avf->nb_streams);
    ff_put_v(bc, nut->max_distance);
    ff_put_v(bc, nut->time_base_count);
347

348
    for (i = 0; i < nut->time_base_count; i++) {
349 350
        ff_put_v(bc, nut->time_base[i].num);
        ff_put_v(bc, nut->time_base[i].den);
351 352
    }

353 354 355 356 357 358 359 360
    tmp_pts      = 0;
    tmp_mul      = 1;
    tmp_stream   = 0;
    tmp_match    = 1 - (1LL << 62);
    tmp_head_idx = 0;
    for (i = 0; i < 256; ) {
        tmp_fields = 0;
        tmp_size   = 0;
361
//        tmp_res=0;
362 363 364 365 366 367
        if (tmp_pts      != nut->frame_code[i].pts_delta ) tmp_fields = 1;
        if (tmp_mul      != nut->frame_code[i].size_mul  ) tmp_fields = 2;
        if (tmp_stream   != nut->frame_code[i].stream_id ) tmp_fields = 3;
        if (tmp_size     != nut->frame_code[i].size_lsb  ) tmp_fields = 4;
//        if (tmp_res    != nut->frame_code[i].res            ) tmp_fields=5;
        if (tmp_head_idx != nut->frame_code[i].header_idx) tmp_fields = 8;
368 369 370 371 372 373

        tmp_pts    = nut->frame_code[i].pts_delta;
        tmp_flags  = nut->frame_code[i].flags;
        tmp_stream = nut->frame_code[i].stream_id;
        tmp_mul    = nut->frame_code[i].size_mul;
        tmp_size   = nut->frame_code[i].size_lsb;
374
//        tmp_res   = nut->frame_code[i].res;
375
        tmp_head_idx = nut->frame_code[i].header_idx;
376

377 378
        for (j = 0; i < 256; j++, i++) {
            if (i == 'N') {
379 380 381
                j--;
                continue;
            }
382 383 384 385 386 387 388 389
            if (nut->frame_code[i].pts_delta  != tmp_pts      ||
                nut->frame_code[i].flags      != tmp_flags    ||
                nut->frame_code[i].stream_id  != tmp_stream   ||
                nut->frame_code[i].size_mul   != tmp_mul      ||
                nut->frame_code[i].size_lsb   != tmp_size + j ||
//              nut->frame_code[i].res        != tmp_res      ||
                nut->frame_code[i].header_idx != tmp_head_idx)
                break;
390
        }
391 392
        if (j != tmp_mul - tmp_size)
            tmp_fields = 6;
393

394 395
        ff_put_v(bc, tmp_flags);
        ff_put_v(bc, tmp_fields);
396 397 398 399 400 401 402 403
        if (tmp_fields > 0) put_s(bc, tmp_pts);
        if (tmp_fields > 1) ff_put_v(bc, tmp_mul);
        if (tmp_fields > 2) ff_put_v(bc, tmp_stream);
        if (tmp_fields > 3) ff_put_v(bc, tmp_size);
        if (tmp_fields > 4) ff_put_v(bc, 0 /*tmp_res*/);
        if (tmp_fields > 5) ff_put_v(bc, j);
        if (tmp_fields > 6) ff_put_v(bc, tmp_match);
        if (tmp_fields > 7) ff_put_v(bc, tmp_head_idx);
404
    }
405 406
    ff_put_v(bc, nut->header_count - 1);
    for (i = 1; i < nut->header_count; i++) {
407
        ff_put_v(bc, nut->header_len[i]);
408
        avio_write(bc, nut->header[i], nut->header_len[i]);
409
    }
410
}
411

412 413 414 415
static int write_streamheader(AVFormatContext *avctx, AVIOContext *bc,
                              AVStream *st, int i)
{
    NUTContext *nut       = avctx->priv_data;
416
    AVCodecContext *codec = st->codec;
417

418
    ff_put_v(bc, i);
419
    switch (codec->codec_type) {
420 421
    case AVMEDIA_TYPE_VIDEO:    ff_put_v(bc, 0); break;
    case AVMEDIA_TYPE_AUDIO:    ff_put_v(bc, 1); break;
422
    case AVMEDIA_TYPE_SUBTITLE: ff_put_v(bc, 2); break;
423
    default:                    ff_put_v(bc, 3); break;
424
    }
425
    ff_put_v(bc, 4);
426
    if (codec->codec_tag) {
427
        avio_wl32(bc, codec->codec_tag);
428 429
    } else {
        av_log(avctx, AV_LOG_ERROR, "No codec tag defined for stream %d\n", i);
430
        return AVERROR(EINVAL);
431
    }
432

433 434 435 436
    ff_put_v(bc, nut->stream[i].time_base - nut->time_base);
    ff_put_v(bc, nut->stream[i].msb_pts_shift);
    ff_put_v(bc, nut->stream[i].max_pts_distance);
    ff_put_v(bc, codec->has_b_frames);
437
    avio_w8(bc, 0); /* flags: 0x1 - fixed_fps, 0x2 - index_present */
438

439
    ff_put_v(bc, codec->extradata_size);
440
    avio_write(bc, codec->extradata, codec->extradata_size);
441

442
    switch (codec->codec_type) {
443
    case AVMEDIA_TYPE_AUDIO:
444 445 446
        ff_put_v(bc, codec->sample_rate);
        ff_put_v(bc, 1);
        ff_put_v(bc, codec->channels);
447
        break;
448
    case AVMEDIA_TYPE_VIDEO:
449 450
        ff_put_v(bc, codec->width);
        ff_put_v(bc, codec->height);
451

452 453
        if (st->sample_aspect_ratio.num <= 0 ||
            st->sample_aspect_ratio.den <= 0) {
454 455
            ff_put_v(bc, 0);
            ff_put_v(bc, 0);
456
        } else {
457 458
            ff_put_v(bc, st->sample_aspect_ratio.num);
            ff_put_v(bc, st->sample_aspect_ratio.den);
459
        }
460
        ff_put_v(bc, 0); /* csp type -- unknown */
461 462 463 464 465 466 467
        break;
    default:
        break;
    }
    return 0;
}

468 469
static int add_info(AVIOContext *bc, const char *type, const char *value)
{
Michael Niedermayer's avatar
Michael Niedermayer committed
470 471 472 473 474 475
    put_str(bc, type);
    put_s(bc, -1);
    put_str(bc, value);
    return 1;
}

476 477 478
static int write_globalinfo(NUTContext *nut, AVIOContext *bc)
{
    AVFormatContext *s   = nut->avf;
479
    AVDictionaryEntry *t = NULL;
480
    AVIOContext *dyn_bc;
481 482 483 484
    uint8_t *dyn_buf = NULL;
    int count        = 0, dyn_size;
    int ret          = avio_open_dyn_buf(&dyn_bc);
    if (ret < 0)
485
        return ret;
Michael Niedermayer's avatar
Michael Niedermayer committed
486

487
    while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX)))
488
        count += add_info(dyn_bc, t->key, t->value);
Michael Niedermayer's avatar
Michael Niedermayer committed
489

490 491 492 493
    ff_put_v(bc, 0); //stream_if_plus1
    ff_put_v(bc, 0); //chapter_id
    ff_put_v(bc, 0); //timestamp_start
    ff_put_v(bc, 0); //length
Michael Niedermayer's avatar
Michael Niedermayer committed
494

495
    ff_put_v(bc, count);
Michael Niedermayer's avatar
Michael Niedermayer committed
496

497
    dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
498
    avio_write(bc, dyn_buf, dyn_size);
Michael Niedermayer's avatar
Michael Niedermayer committed
499
    av_free(dyn_buf);
500
    return 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
501 502
}

503
static int write_streaminfo(NUTContext *nut, AVIOContext *bc, int stream_id) {
504 505
    AVFormatContext *s= nut->avf;
    AVStream* st = s->streams[stream_id];
506
    AVDictionaryEntry *t = NULL;
507
    AVIOContext *dyn_bc;
508 509
    uint8_t *dyn_buf=NULL;
    int count=0, dyn_size, i;
510
    int ret = avio_open_dyn_buf(&dyn_bc);
511
    if (ret < 0)
512 513
        return ret;

514 515
    while ((t = av_dict_get(st->metadata, "", t, AV_DICT_IGNORE_SUFFIX)))
        count += add_info(dyn_bc, t->key, t->value);
516 517 518 519
    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);
    }
520 521 522 523 524
    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);
        count += add_info(dyn_bc, "r_frame_rate", buf);
    }
525
    dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
526 527

    if (count) {
528 529 530 531
        ff_put_v(bc, stream_id + 1); //stream_id_plus1
        ff_put_v(bc, 0); //chapter_id
        ff_put_v(bc, 0); //timestamp_start
        ff_put_v(bc, 0); //length
532

533
        ff_put_v(bc, count);
534

535
        avio_write(bc, dyn_buf, dyn_size);
536 537 538 539 540 541
    }

    av_free(dyn_buf);
    return count;
}

Anton Khirnov's avatar
Anton Khirnov committed
542 543 544
static int write_chapter(NUTContext *nut, AVIOContext *bc, int id)
{
    AVIOContext *dyn_bc;
545
    uint8_t *dyn_buf     = NULL;
546
    AVDictionaryEntry *t = NULL;
547
    AVChapter *ch        = nut->avf->chapters[id];
Anton Khirnov's avatar
Anton Khirnov committed
548 549
    int ret, dyn_size, count = 0;

550
    ret = avio_open_dyn_buf(&dyn_bc);
Anton Khirnov's avatar
Anton Khirnov committed
551 552 553 554 555 556 557 558
    if (ret < 0)
        return ret;

    ff_put_v(bc, 0);                                        // stream_id_plus1
    put_s(bc, id + 1);                                      // chapter_id
    put_tt(nut, nut->chapter[id].time_base, bc, ch->start); // chapter_start
    ff_put_v(bc, ch->end - ch->start);                      // chapter_len

559
    while ((t = av_dict_get(ch->metadata, "", t, AV_DICT_IGNORE_SUFFIX)))
Anton Khirnov's avatar
Anton Khirnov committed
560 561 562 563
        count += add_info(dyn_bc, t->key, t->value);

    ff_put_v(bc, count);

564
    dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
Anton Khirnov's avatar
Anton Khirnov committed
565 566 567 568 569
    avio_write(bc, dyn_buf, dyn_size);
    av_freep(&dyn_buf);
    return 0;
}

570
static int write_index(NUTContext *nut, AVIOContext *bc) {
571 572 573 574 575 576 577 578 579 580
    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);

581
    for (i=0; i<nut->sp_count; i++) {
582 583 584 585 586
        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;
    }

587
    for (i=0; i<nut->avf->nb_streams; i++) {
588 589 590
        StreamContext *nus= &nut->stream[i];
        int64_t last_pts= -1;
        int j, k;
591
        for (j=0; j<nut->sp_count; j++) {
592
            int flag;
593
            int n = 0;
594 595 596 597 598 599 600

            if (j && nus->keyframe_pts[j] == nus->keyframe_pts[j-1]) {
                av_log(nut->avf, AV_LOG_WARNING, "Multiple keyframes with same PTS\n");
                nus->keyframe_pts[j] = AV_NOPTS_VALUE;
            }

            flag = (nus->keyframe_pts[j] != AV_NOPTS_VALUE) ^ (j+1 == nut->sp_count);
601
            for (; j<nut->sp_count && (nus->keyframe_pts[j] != AV_NOPTS_VALUE) == flag; j++)
602 603 604
                n++;

            ff_put_v(bc, 1 + 2*flag + 4*n);
605 606
            for (k= j - n; k<=j && k<nut->sp_count; k++) {
                if (nus->keyframe_pts[k] == AV_NOPTS_VALUE)
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
                    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;
}

622 623
static int write_headers(AVFormatContext *avctx, AVIOContext *bc)
{
624
    NUTContext *nut = avctx->priv_data;
625
    AVIOContext *dyn_bc;
626
    int i, ret;
627

628 629
    ff_metadata_conv_ctx(avctx, ff_nut_metadata_conv, NULL);

630
    ret = avio_open_dyn_buf(&dyn_bc);
631
    if (ret < 0)
632 633 634
        return ret;
    write_mainheader(nut, dyn_bc);
    put_packet(nut, bc, dyn_bc, 1, MAIN_STARTCODE);
635

636
    for (i = 0; i < nut->avf->nb_streams; i++) {
637
        ret = avio_open_dyn_buf(&dyn_bc);
638
        if (ret < 0)
639
            return ret;
640 641
        ret = write_streamheader(avctx, dyn_bc, nut->avf->streams[i], i);
        if (ret < 0)
642
            return ret;
643
        put_packet(nut, bc, dyn_bc, 1, STREAM_STARTCODE);
644
    }
Michael Niedermayer's avatar
Michael Niedermayer committed
645

646
    ret = avio_open_dyn_buf(&dyn_bc);
647
    if (ret < 0)
648 649 650
        return ret;
    write_globalinfo(nut, dyn_bc);
    put_packet(nut, bc, dyn_bc, 1, INFO_STARTCODE);
Michael Niedermayer's avatar
Michael Niedermayer committed
651

652
    for (i = 0; i < nut->avf->nb_streams; i++) {
653
        ret = avio_open_dyn_buf(&dyn_bc);
654
        if (ret < 0)
655 656 657 658 659 660 661
            return ret;
        ret = write_streaminfo(nut, dyn_bc, i);
        if (ret < 0)
            return ret;
        if (ret > 0)
            put_packet(nut, bc, dyn_bc, 1, INFO_STARTCODE);
        else {
662
            uint8_t *buf;
663
            avio_close_dyn_buf(dyn_bc, &buf);
664 665 666 667
            av_free(buf);
        }
    }

Anton Khirnov's avatar
Anton Khirnov committed
668
    for (i = 0; i < nut->avf->nb_chapters; i++) {
669
        ret = avio_open_dyn_buf(&dyn_bc);
Anton Khirnov's avatar
Anton Khirnov committed
670 671 672 673 674
        if (ret < 0)
            return ret;
        ret = write_chapter(nut, dyn_bc, i);
        if (ret < 0) {
            uint8_t *buf;
675
            avio_close_dyn_buf(dyn_bc, &buf);
Anton Khirnov's avatar
Anton Khirnov committed
676 677 678 679 680 681
            av_freep(&buf);
            return ret;
        }
        put_packet(nut, bc, dyn_bc, 1, INFO_STARTCODE);
    }

682
    nut->last_syncpoint_pos = INT_MIN;
Michael Niedermayer's avatar
Michael Niedermayer committed
683
    nut->header_count++;
684
    return 0;
685 686
}

687 688
static int nut_write_header(AVFormatContext *s)
{
689
    NUTContext *nut = s->priv_data;
690
    AVIOContext *bc = s->pb;
691
    int i, j, ret;
692

693
    nut->avf = s;
694

695 696 697 698
    nut->stream   = av_calloc(s->nb_streams,  sizeof(*nut->stream ));
    nut->chapter  = av_calloc(s->nb_chapters, sizeof(*nut->chapter));
    nut->time_base= av_calloc(s->nb_streams +
                              s->nb_chapters, sizeof(*nut->time_base));
Reimar Döffinger's avatar
Reimar Döffinger committed
699
    if (!nut->stream || !nut->chapter || !nut->time_base) {
700 701 702 703 704
        av_freep(&nut->stream);
        av_freep(&nut->chapter);
        av_freep(&nut->time_base);
        return AVERROR(ENOMEM);
    }
705

706 707
    for (i = 0; i < s->nb_streams; i++) {
        AVStream *st = s->streams[i];
708 709 710 711
        int ssize;
        AVRational time_base;
        ff_parse_specific_params(st->codec, &time_base.den, &ssize, &time_base.num);

712 713
        if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && st->codec->sample_rate) {
            time_base = (AVRational) {1, st->codec->sample_rate};
714
        } else {
715
            time_base = ff_choose_timebase(s, st, 48000);
716 717
        }

718
        avpriv_set_pts_info(st, 64, time_base.num, time_base.den);
719

720 721
        for (j = 0; j < nut->time_base_count; j++)
            if (!memcmp(&time_base, &nut->time_base[j], sizeof(AVRational))) {
722 723
                break;
            }
724 725 726
        nut->time_base[j]        = time_base;
        nut->stream[i].time_base = &nut->time_base[j];
        if (j == nut->time_base_count)
727 728
            nut->time_base_count++;

729
        if (INT64_C(1000) * time_base.num >= time_base.den)
730 731 732
            nut->stream[i].msb_pts_shift = 7;
        else
            nut->stream[i].msb_pts_shift = 14;
733 734
        nut->stream[i].max_pts_distance =
            FFMAX(time_base.den, time_base.num) / time_base.num;
735 736
    }

Anton Khirnov's avatar
Anton Khirnov committed
737 738 739
    for (i = 0; i < s->nb_chapters; i++) {
        AVChapter *ch = s->chapters[i];

740
        for (j = 0; j < nut->time_base_count; j++)
Anton Khirnov's avatar
Anton Khirnov committed
741 742 743
            if (!memcmp(&ch->time_base, &nut->time_base[j], sizeof(AVRational)))
                break;

744
        nut->time_base[j]         = ch->time_base;
Anton Khirnov's avatar
Anton Khirnov committed
745
        nut->chapter[i].time_base = &nut->time_base[j];
746
        if (j == nut->time_base_count)
Anton Khirnov's avatar
Anton Khirnov committed
747 748 749
            nut->time_base_count++;
    }

750
    nut->max_distance = MAX_DISTANCE;
751
    build_elision_headers(s);
752
    build_frame_code(s);
753
    av_assert0(nut->frame_code['N'].flags == FLAG_INVALID);
754

755 756
    avio_write(bc, ID_STRING, strlen(ID_STRING));
    avio_w8(bc, 0);
757

758 759
    if ((ret = write_headers(s, bc)) < 0)
        return ret;
760

761 762 763
    if (s->avoid_negative_ts < 0)
        s->avoid_negative_ts = 1;

764
    avio_flush(bc);
765 766 767 768

    return 0;
}

769 770 771 772 773 774 775 776 777 778 779 780 781
static int get_needed_flags(NUTContext *nut, StreamContext *nus, FrameCode *fc,
                            AVPacket *pkt)
{
    int flags = 0;

    if (pkt->flags & AV_PKT_FLAG_KEY)
        flags |= FLAG_KEY;
    if (pkt->stream_index != fc->stream_id)
        flags |= FLAG_STREAM_ID;
    if (pkt->size / fc->size_mul)
        flags |= FLAG_SIZE_MSB;
    if (pkt->pts - nus->last_pts != fc->pts_delta)
        flags |= FLAG_CODED_PTS;
782 783
    if (pkt->side_data_elems && nut->version > 3)
        flags |= FLAG_SM_DATA;
784 785 786 787 788 789 790 791 792
    if (pkt->size > 2 * nut->max_distance)
        flags |= FLAG_CHECKSUM;
    if (FFABS(pkt->pts - nus->last_pts) > nus->max_pts_distance)
        flags |= FLAG_CHECKSUM;
    if (pkt->size < nut->header_len[fc->header_idx] ||
        (pkt->size > 4096 && fc->header_idx)        ||
        memcmp(pkt->data, nut->header[fc->header_idx],
               nut->header_len[fc->header_idx]))
        flags |= FLAG_HEADER_IDX;
793

794
    return flags | (fc->flags & FLAG_CODED);
795 796
}

797 798
static int find_best_header_idx(NUTContext *nut, AVPacket *pkt)
{
799
    int i;
800 801
    int best_i   = 0;
    int best_len = 0;
802

803
    if (pkt->size > 4096)
804 805
        return 0;

806 807 808 809 810 811
    for (i = 1; i < nut->header_count; i++)
        if (pkt->size >= nut->header_len[i]
            && nut->header_len[i] > best_len
            && !memcmp(pkt->data, nut->header[i], nut->header_len[i])) {
            best_i   = i;
            best_len = nut->header_len[i];
812 813 814 815
        }
    return best_i;
}

816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932
static int write_sm_data(AVFormatContext *s, AVIOContext *bc, AVPacket *pkt, int is_meta)
{
    AVStream *st = s->streams[pkt->stream_index];
    int ret, i, dyn_size;
    unsigned flags;
    AVIOContext *dyn_bc;
    int sm_data_count = 0;
    uint8_t tmp[256];
    uint8_t *dyn_buf;

    ret = avio_open_dyn_buf(&dyn_bc);
    if (ret < 0)
        return ret;

    for (i = 0; i<pkt->side_data_elems; i++) {
        const uint8_t *data = pkt->side_data[i].data;
        int size = pkt->side_data[i].size;
        const uint8_t *data_end = data + size;

        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);
                while (data < data_end) {
                    const uint8_t *key = data;
                    const uint8_t *val = data + strlen(key) + 1;

                    if(val >= data_end)
                        return AVERROR(EINVAL);
                    put_str(dyn_bc, key);
                    put_s(dyn_bc, -1);
                    put_str(dyn_bc, val);
                    data = val + strlen(val) + 1;
                    sm_data_count++;
                }
            }
        } else {
            switch (pkt->side_data[i].type) {
            case AV_PKT_DATA_PALETTE:
            case AV_PKT_DATA_NEW_EXTRADATA:
            case AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL:
            default:
                if (pkt->side_data[i].type == AV_PKT_DATA_PALETTE) {
                    put_str(dyn_bc, "Palette");
                } else if(pkt->side_data[i].type == AV_PKT_DATA_NEW_EXTRADATA) {
                    put_str(dyn_bc, "Extradata");
                } else if(pkt->side_data[i].type == AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL) {
                    snprintf(tmp, sizeof(tmp), "CodecSpecificSide%"PRId64"", AV_RB64(data));
                    put_str(dyn_bc, tmp);
                } else {
                    snprintf(tmp, sizeof(tmp), "UserData%s-SD-%d",
                            (st->codec->flags & CODEC_FLAG_BITEXACT) ? "Lavf" : LIBAVFORMAT_IDENT,
                            pkt->side_data[i].type);
                    put_str(dyn_bc, tmp);
                }
                put_s(dyn_bc, -2);
                put_str(dyn_bc, "bin");
                ff_put_v(dyn_bc, pkt->side_data[i].size);
                avio_write(dyn_bc, data, pkt->side_data[i].size);
                sm_data_count++;
                break;
            case AV_PKT_DATA_PARAM_CHANGE:
                flags = bytestream_get_le32(&data);
                if (flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT) {
                    put_str(dyn_bc, "Channels");
                    put_s(dyn_bc, bytestream_get_le32(&data));
                    sm_data_count++;
                }
                if (flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT) {
                    put_str(dyn_bc, "ChannelLayout");
                    put_s(dyn_bc, -2);
                    put_str(dyn_bc, "u64");
                    ff_put_v(bc, 8);
                    avio_write(dyn_bc, data, 8); data+=8;
                    sm_data_count++;
                }
                if (flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE) {
                    put_str(dyn_bc, "SampleRate");
                    put_s(dyn_bc, bytestream_get_le32(&data));
                    sm_data_count++;
                }
                if (flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS) {
                    put_str(dyn_bc, "Width");
                    put_s(dyn_bc, bytestream_get_le32(&data));
                    put_str(dyn_bc, "Height");
                    put_s(dyn_bc, bytestream_get_le32(&data));
                    sm_data_count+=2;
                }
            case AV_PKT_DATA_SKIP_SAMPLES:
                if (AV_RL32(data)) {
                    put_str(dyn_bc, "SkipStart");
                    put_s(dyn_bc, (unsigned)AV_RL32(data));
                    sm_data_count++;
                }
                if (AV_RL32(data+4)) {
                    put_str(dyn_bc, "SkipEnd");
                    put_s(dyn_bc, (unsigned)AV_RL32(data+4));
                    sm_data_count++;
                }
                break;
            case AV_PKT_DATA_METADATA_UPDATE:
            case AV_PKT_DATA_STRINGS_METADATA:
                // belongs into meta, not side data
                break;
            }
        }
    }

    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;
}

933 934 935 936
static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
{
    NUTContext *nut    = s->priv_data;
    StreamContext *nus = &nut->stream[pkt->stream_index];
937
    AVIOContext *bc    = s->pb, *dyn_bc, *sm_bc = NULL;
938 939
    FrameCode *fc;
    int64_t coded_pts;
940 941
    int best_length, frame_code, flags, needed_flags, i, header_idx;
    int best_header_idx;
942
    int key_frame = !!(pkt->flags & AV_PKT_FLAG_KEY);
943
    int store_sp  = 0;
944
    int ret;
945 946 947
    int sm_size = 0;
    int data_size = pkt->size;
    uint8_t *sm_buf;
948

949
    if (pkt->pts < 0) {
950 951 952
        av_log(s, AV_LOG_ERROR,
               "Negative pts not supported stream %d, pts %"PRId64"\n",
               pkt->stream_index, pkt->pts);
953 954
        return AVERROR(EINVAL);
    }
955

956 957 958 959 960 961 962 963 964 965
    if (pkt->side_data_elems && nut->version > 3) {
        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);
        sm_size = avio_close_dyn_buf(sm_bc, &sm_buf);
        data_size += sm_size;
    }

966
    if (1LL << (20 + 3 * nut->header_count) <= avio_tell(bc))
967
        write_headers(s, bc);
Michael Niedermayer's avatar
Michael Niedermayer committed
968

969 970
    if (key_frame && !(nus->last_flags & FLAG_KEY))
        store_sp = 1;
971

972
    if (data_size + 30 /*FIXME check*/ + avio_tell(bc) >= nut->last_syncpoint_pos + nut->max_distance)
973
        store_sp = 1;
974

975
//FIXME: Ensure store_sp is 1 in the first place.
976

977 978
    if (store_sp) {
        Syncpoint *sp, dummy = { .pos = INT64_MAX };
979

980
        ff_nut_reset_ts(nut, *nus->time_base, pkt->dts);
981 982
        for (i = 0; i < s->nb_streams; i++) {
            AVStream *st   = s->streams[i];
983 984 985 986
            int64_t dts_tb = av_rescale_rnd(pkt->dts,
                nus->time_base->num * (int64_t)nut->stream[i].time_base->den,
                nus->time_base->den * (int64_t)nut->stream[i].time_base->num,
                AV_ROUND_DOWN);
987 988 989 990
            int index = av_index_search_timestamp(st, dts_tb,
                                                  AVSEEK_FLAG_BACKWARD);
            if (index >= 0)
                dummy.pos = FFMIN(dummy.pos, st->index_entries[index].pos);
991
        }
992 993 994 995
        if (dummy.pos == INT64_MAX)
            dummy.pos = 0;
        sp = av_tree_find(nut->syncpoints, &dummy, (void *)ff_nut_sp_pos_cmp,
                          NULL);
996

997 998 999
        nut->last_syncpoint_pos = avio_tell(bc);
        ret                     = avio_open_dyn_buf(&dyn_bc);
        if (ret < 0)
1000
            return ret;
Anton Khirnov's avatar
Anton Khirnov committed
1001
        put_tt(nut, nus->time_base, dyn_bc, pkt->dts);
1002
        ff_put_v(dyn_bc, sp ? (nut->last_syncpoint_pos - sp->pos) >> 4 : 0);
1003
        put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE);
1004

1005 1006
        if ((ret = ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0 /*unused*/, pkt->dts)) < 0)
            return ret;
1007

1008 1009
        if ((1ll<<60) % nut->sp_count == 0)
            for (i=0; i<s->nb_streams; i++) {
1010 1011
                int j;
                StreamContext *nus = &nut->stream[i];
1012
                av_reallocp_array(&nus->keyframe_pts, 2*nut->sp_count, sizeof(*nus->keyframe_pts));
1013
                if (!nus->keyframe_pts)
1014
                    return AVERROR(ENOMEM);
1015
                for (j=nut->sp_count == 1 ? 0 : nut->sp_count; j<2*nut->sp_count; j++)
1016 1017
                    nus->keyframe_pts[j] = AV_NOPTS_VALUE;
        }
1018
    }
1019
    av_assert0(nus->last_pts != AV_NOPTS_VALUE);
1020

1021 1022 1023
    coded_pts = pkt->pts & ((1 << nus->msb_pts_shift) - 1);
    if (ff_lsb2full(nus, coded_pts) != pkt->pts)
        coded_pts = pkt->pts + (1 << nus->msb_pts_shift);
1024

1025
    best_header_idx = find_best_header_idx(nut, pkt);
1026

1027 1028 1029 1030 1031 1032
    best_length = INT_MAX;
    frame_code  = -1;
    for (i = 0; i < 256; i++) {
        int length    = 0;
        FrameCode *fc = &nut->frame_code[i];
        int flags     = fc->flags;
1033

1034
        if (flags & FLAG_INVALID)
1035
            continue;
1036
        needed_flags = get_needed_flags(nut, nus, fc, pkt);
1037

1038
        if (flags & FLAG_CODED) {
1039
            length++;
Michael Niedermayer's avatar
Michael Niedermayer committed
1040
            flags = needed_flags;
1041 1042
        }

1043
        if ((flags & needed_flags) != needed_flags)
1044 1045
            continue;

1046
        if ((flags ^ needed_flags) & FLAG_KEY)
1047 1048
            continue;

1049 1050
        if (flags & FLAG_STREAM_ID)
            length += ff_get_v_length(pkt->stream_index);
1051

1052
        if (data_size % fc->size_mul != fc->size_lsb)
1053
            continue;
1054
        if (flags & FLAG_SIZE_MSB)
1055
            length += ff_get_v_length(data_size / fc->size_mul);
1056

1057 1058
        if (flags & FLAG_CHECKSUM)
            length += 4;
1059

1060
        if (flags & FLAG_CODED_PTS)
1061
            length += ff_get_v_length(coded_pts);
1062

1063 1064
        if (   (flags & FLAG_CODED)
            && nut->header_len[best_header_idx] > nut->header_len[fc->header_idx] + 1) {
1065 1066 1067
            flags |= FLAG_HEADER_IDX;
        }

1068
        if (flags & FLAG_HEADER_IDX) {
1069
            length += 1 - nut->header_len[best_header_idx];
1070
        } else {
1071 1072 1073
            length -= nut->header_len[fc->header_idx];
        }

1074 1075 1076
        length *= 4;
        length += !(flags & FLAG_CODED_PTS);
        length += !(flags & FLAG_CHECKSUM);
1077

1078 1079 1080
        if (length < best_length) {
            best_length = length;
            frame_code  = i;
1081 1082
        }
    }
1083
    av_assert0(frame_code != -1);
1084 1085 1086 1087
    fc           = &nut->frame_code[frame_code];
    flags        = fc->flags;
    needed_flags = get_needed_flags(nut, nus, fc, pkt);
    header_idx   = fc->header_idx;
1088

1089
    ffio_init_checksum(bc, ff_crc04C11DB7_update, 0);
1090
    avio_w8(bc, frame_code);
1091 1092
    if (flags & FLAG_CODED) {
        ff_put_v(bc, (flags ^ needed_flags) & ~(FLAG_CODED));
1093 1094
        flags = needed_flags;
    }
1095 1096
    if (flags & FLAG_STREAM_ID)  ff_put_v(bc, pkt->stream_index);
    if (flags & FLAG_CODED_PTS)  ff_put_v(bc, coded_pts);
1097
    if (flags & FLAG_SIZE_MSB )  ff_put_v(bc, data_size / fc->size_mul);
1098
    if (flags & FLAG_HEADER_IDX) ff_put_v(bc, header_idx = best_header_idx);
1099

1100 1101
    if (flags & FLAG_CHECKSUM)   avio_wl32(bc, ffio_get_checksum(bc));
    else                         ffio_get_checksum(bc);
1102

1103 1104 1105 1106
    if (flags & FLAG_SM_DATA) {
        avio_write(bc, sm_buf, sm_size);
        av_freep(&sm_buf);
    }
1107
    avio_write(bc, pkt->data + nut->header_len[header_idx], pkt->size - nut->header_len[header_idx]);
1108

1109 1110
    nus->last_flags = flags;
    nus->last_pts   = pkt->pts;
1111 1112

    //FIXME just store one per syncpoint
1113
    if (flags & FLAG_KEY) {
1114 1115 1116 1117 1118 1119 1120
        av_add_index_entry(
            s->streams[pkt->stream_index],
            nut->last_syncpoint_pos,
            pkt->pts,
            0,
            0,
            AVINDEX_KEYFRAME);
1121
        if (nus->keyframe_pts && nus->keyframe_pts[nut->sp_count] == AV_NOPTS_VALUE)
1122 1123
            nus->keyframe_pts[nut->sp_count] = pkt->pts;
    }
1124

1125
    if (!nut->max_pts_tb || av_compare_ts(nut->max_pts, *nut->max_pts_tb, pkt->pts, *nus->time_base) < 0) {
1126 1127 1128 1129
        nut->max_pts = pkt->pts;
        nut->max_pts_tb = nus->time_base;
    }

1130 1131 1132
    return 0;
}

1133 1134 1135
static int nut_write_trailer(AVFormatContext *s)
{
    NUTContext *nut = s->priv_data;
1136 1137
    AVIOContext *bc = s->pb, *dyn_bc;
    int i, ret;
1138

1139
    while (nut->header_count < 3)
1140
        write_headers(s, bc);
1141 1142

    ret = avio_open_dyn_buf(&dyn_bc);
1143
    if (ret >= 0 && nut->sp_count) {
1144 1145 1146 1147
        write_index(nut, dyn_bc);
        put_packet(nut, bc, dyn_bc, 1, INDEX_STARTCODE);
    }

1148
    ff_nut_free_sp(nut);
1149
    for (i=0; i<s->nb_streams; i++)
1150 1151
        av_freep(&nut->stream[i].keyframe_pts);

1152
    av_freep(&nut->stream);
Anton Khirnov's avatar
Anton Khirnov committed
1153
    av_freep(&nut->chapter);
1154
    av_freep(&nut->time_base);
1155 1156 1157 1158

    return 0;
}

1159
AVOutputFormat ff_nut_muxer = {
1160
    .name           = "nut",
1161
    .long_name      = NULL_IF_CONFIG_SMALL("NUT"),
1162 1163 1164
    .mime_type      = "video/x-nut",
    .extensions     = "nut",
    .priv_data_size = sizeof(NUTContext),
1165 1166 1167
    .audio_codec    = CONFIG_LIBVORBIS ? AV_CODEC_ID_VORBIS :
                      CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_MP2,
    .video_codec    = AV_CODEC_ID_MPEG4,
1168 1169 1170
    .write_header   = nut_write_header,
    .write_packet   = nut_write_packet,
    .write_trailer  = nut_write_trailer,
1171
    .flags          = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS,
1172
    .codec_tag      = ff_nut_codec_tags,
1173
};