nut.c 42.5 KB
Newer Older
1
/*
michael's avatar
michael committed
2
 * "NUT" Container Format muxer and demuxer (DRAFT-200403??)
3
 * Copyright (c) 2003 Alex Beregszaszi
michael's avatar
michael committed
4
 * Copyright (c) 2004 Michael Niedermayer
5
 *
6 7
 * Visit the official site at http://www.nut-container.org/.
 *
8 9 10
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
11 12
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
13
 * version 2.1 of the License, or (at your option) any later version.
14
 *
15
 * FFmpeg is distributed in the hope that it will be useful,
16 17 18 19
 * 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.
 *
20
 * You should have received a copy of the GNU Lesser General Public
21
 * License along with FFmpeg; if not, write to the Free Software
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 24 25 26 27
 */

/*
 * TODO:
 * - index writing
michael's avatar
michael committed
28
 * - index packet reading support
29 30 31 32
*/

//#define DEBUG 1

michael's avatar
michael committed
33
#include <limits.h>
34 35
#include "avformat.h"
#include "mpegaudio.h"
36
#include "riff.h"
mru's avatar
mru committed
37
#include "adler32.h"
38

michael's avatar
michael committed
39 40 41
#undef NDEBUG
#include <assert.h>

michael's avatar
michael committed
42 43
//#define TRACE

michaelni's avatar
michaelni committed
44 45
//from /dev/random

46 47 48 49 50
#define     MAIN_STARTCODE (0x7A561F5F04ADULL + (((uint64_t)('N'<<8) + 'M')<<48))
#define   STREAM_STARTCODE (0x11405BF2F9DBULL + (((uint64_t)('N'<<8) + 'S')<<48))
#define KEYFRAME_STARTCODE (0xE4ADEECA4569ULL + (((uint64_t)('N'<<8) + 'K')<<48))
#define    INDEX_STARTCODE (0xDD672F23E64EULL + (((uint64_t)('N'<<8) + 'X')<<48))
#define     INFO_STARTCODE (0xAB68B596BA78ULL + (((uint64_t)('N'<<8) + 'I')<<48))
michael's avatar
michael committed
51

michael's avatar
michael committed
52 53
#define ID_STRING "nut/multimedia container\0"

michael's avatar
michael committed
54 55
#define MAX_DISTANCE (1024*16-1)
#define MAX_SHORT_DISTANCE (1024*4-1)
michael's avatar
michael committed
56

michael's avatar
michael committed
57 58 59
#define FLAG_DATA_SIZE       1
#define FLAG_KEY_FRAME       2
#define FLAG_INVALID         4
michael's avatar
michael committed
60 61 62 63

typedef struct {
    uint8_t flags;
    uint8_t stream_id_plus1;
michael's avatar
michael committed
64 65
    uint16_t size_mul;
    uint16_t size_lsb;
michael's avatar
michael committed
66 67
    int16_t timestamp_delta;
    uint8_t reserved_count;
michael's avatar
michael committed
68 69 70 71 72 73 74 75
} FrameCode;

typedef struct {
    int last_key_frame;
    int msb_timestamp_shift;
    int rate_num;
    int rate_den;
    int64_t last_pts;
michael's avatar
michael committed
76
    int64_t last_sync_pos;                    ///<pos of last 1/2 type frame
michael's avatar
michael committed
77
    int decode_delay;
michael's avatar
michael committed
78
} StreamContext;
michaelni's avatar
michaelni committed
79

80
typedef struct {
michael's avatar
michael committed
81 82
    AVFormatContext *avf;
    int written_packet_size;
michael's avatar
michael committed
83
    int64_t packet_start[3]; //0-> startcode less, 1-> short startcode 2-> long startcodes
michael's avatar
michael committed
84
    FrameCode frame_code[256];
michael's avatar
michael committed
85
    unsigned int stream_count;
diego's avatar
diego committed
86
    uint64_t next_startcode;     ///< stores the next startcode if it has already been parsed but the stream is not seekable
michael's avatar
michael committed
87
    StreamContext *stream;
michael's avatar
michael committed
88
    int max_distance;
michael's avatar
michael committed
89
    int max_short_distance;
michael's avatar
michael committed
90 91 92
    int rate_num;
    int rate_den;
    int short_startcode;
93 94
} NUTContext;

michael's avatar
michael committed
95
static char *info_table[][2]={
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
        {NULL                   ,  NULL }, // end
        {NULL                   ,  NULL },
        {NULL                   , "UTF8"},
        {NULL                   , "v"},
        {NULL                   , "s"},
        {"StreamId"             , "v"},
        {"SegmentId"            , "v"},
        {"StartTimestamp"       , "v"},
        {"EndTimestamp"         , "v"},
        {"Author"               , "UTF8"},
        {"Title"                , "UTF8"},
        {"Description"          , "UTF8"},
        {"Copyright"            , "UTF8"},
        {"Encoder"              , "UTF8"},
        {"Keyword"              , "UTF8"},
        {"Cover"                , "JPEG"},
        {"Cover"                , "PNG"},
michael's avatar
michael committed
113 114
};

michael's avatar
michael committed
115 116
static void update(NUTContext *nut, int stream_index, int64_t frame_start, int frame_type, int frame_code, int key_frame, int size, int64_t pts){
    StreamContext *stream= &nut->stream[stream_index];
117

michael's avatar
michael committed
118
    stream->last_key_frame= key_frame;
michael's avatar
michael committed
119
    nut->packet_start[ frame_type ]= frame_start;
michael's avatar
michael committed
120 121 122
    stream->last_pts= pts;
}

michael's avatar
michael committed
123
static void reset(AVFormatContext *s, int64_t global_ts){
michael's avatar
michael committed
124 125
    NUTContext *nut = s->priv_data;
    int i;
126

michael's avatar
michael committed
127 128
    for(i=0; i<s->nb_streams; i++){
        StreamContext *stream= &nut->stream[i];
129

michael's avatar
michael committed
130
        stream->last_key_frame= 1;
michael's avatar
michael committed
131 132

        stream->last_pts= av_rescale(global_ts, stream->rate_num*(int64_t)nut->rate_den, stream->rate_den*(int64_t)nut->rate_num);
michael's avatar
michael committed
133 134 135 136 137
    }
}

static void build_frame_code(AVFormatContext *s){
    NUTContext *nut = s->priv_data;
michael's avatar
michael committed
138
    int key_frame, index, pred, stream_id;
michael's avatar
michael committed
139 140 141
    int start=0;
    int end= 255;
    int keyframe_0_esc= s->nb_streams > 2;
michael's avatar
michael committed
142
    int pred_table[10];
michael's avatar
michael committed
143 144

    if(keyframe_0_esc){
michael's avatar
michael committed
145 146
        /* keyframe = 0 escape */
        FrameCode *ft= &nut->frame_code[start];
michael's avatar
michael committed
147
        ft->flags= FLAG_DATA_SIZE;
michael's avatar
michael committed
148 149
        ft->stream_id_plus1= 0;
        ft->size_mul=1;
michael's avatar
michael committed
150
        ft->timestamp_delta=0;
michael's avatar
michael committed
151
        start++;
michael's avatar
michael committed
152 153 154 155 156
    }

    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;
157
        AVCodecContext *codec = s->streams[stream_id]->codec;
michael's avatar
michael committed
158 159 160 161 162 163 164
        int is_audio= codec->codec_type == CODEC_TYPE_AUDIO;
        int intra_only= /*codec->intra_only || */is_audio;
        int pred_count;

        for(key_frame=0; key_frame<2; key_frame++){
            if(intra_only && keyframe_0_esc && key_frame==0)
                continue;
165

michael's avatar
michael committed
166 167 168
            {
                FrameCode *ft= &nut->frame_code[start2];
                ft->flags= FLAG_KEY_FRAME*key_frame;
michael's avatar
michael committed
169
                ft->flags|= FLAG_DATA_SIZE;
michael's avatar
michael committed
170 171
                ft->stream_id_plus1= stream_id + 1;
                ft->size_mul=1;
michael's avatar
michael committed
172
                ft->timestamp_delta=0;
michael's avatar
michael committed
173
                start2++;
michael's avatar
michael committed
174 175 176 177 178 179 180
            }
        }

        key_frame= intra_only;
#if 1
        if(is_audio){
            int frame_bytes= codec->frame_size*(int64_t)codec->bit_rate / (8*codec->sample_rate);
michael's avatar
michael committed
181 182
            int pts;
            for(pts=0; pts<2; pts++){
michael's avatar
michael committed
183
                for(pred=0; pred<2; pred++){
michael's avatar
michael committed
184
                    FrameCode *ft= &nut->frame_code[start2];
michael's avatar
michael committed
185
                    ft->flags= FLAG_KEY_FRAME*key_frame;
michael's avatar
michael committed
186
                    ft->stream_id_plus1= stream_id + 1;
michael's avatar
michael committed
187 188
                    ft->size_mul=frame_bytes + 2;
                    ft->size_lsb=frame_bytes + pred;
michael's avatar
michael committed
189
                    ft->timestamp_delta=pts;
michael's avatar
michael committed
190 191 192 193 194 195 196 197
                    start2++;
                }
            }
        }else{
            FrameCode *ft= &nut->frame_code[start2];
            ft->flags= FLAG_KEY_FRAME | FLAG_DATA_SIZE;
            ft->stream_id_plus1= stream_id + 1;
            ft->size_mul=1;
michael's avatar
michael committed
198
            ft->timestamp_delta=1;
michael's avatar
michael committed
199 200 201
            start2++;
        }
#endif
michael's avatar
michael committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219

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

michael's avatar
michael committed
220 221 222 223 224 225
        for(pred=0; pred<pred_count; pred++){
            int start3= start2 + (end2-start2)*pred / pred_count;
            int end3  = start2 + (end2-start2)*(pred+1) / pred_count;

            for(index=start3; index<end3; index++){
                FrameCode *ft= &nut->frame_code[index];
michael's avatar
michael committed
226
                ft->flags= FLAG_KEY_FRAME*key_frame;
michael's avatar
michael committed
227 228 229 230 231
                ft->flags|= FLAG_DATA_SIZE;
                ft->stream_id_plus1= stream_id + 1;
//FIXME use single byte size and pred from last
                ft->size_mul= end3-start3;
                ft->size_lsb= index - start3;
michael's avatar
michael committed
232
                ft->timestamp_delta= pred_table[pred];
michael's avatar
michael committed
233 234 235 236
            }
        }
    }
    memmove(&nut->frame_code['N'+1], &nut->frame_code['N'], sizeof(FrameCode)*(255-'N'));
michael's avatar
michael committed
237
    nut->frame_code['N'].flags= FLAG_INVALID;
michael's avatar
michael committed
238 239
}

240 241 242 243
static uint64_t get_v(ByteIOContext *bc)
{
    uint64_t val = 0;

michael's avatar
michael committed
244
    for(;;)
245
    {
246
        int tmp = get_byte(bc);
247

248 249 250
        if (tmp&0x80)
            val= (val<<7) + tmp - 0x80;
        else{
251
//av_log(NULL, AV_LOG_DEBUG, "get_v()= %"PRId64"\n", (val<<7) + tmp);
252
            return (val<<7) + tmp;
michael's avatar
michael committed
253
        }
254 255 256 257
    }
    return -1;
}

michael's avatar
michael committed
258 259
static int get_str(ByteIOContext *bc, char *string, unsigned int maxlen){
    unsigned int len= get_v(bc);
260

michael's avatar
michael committed
261 262 263 264 265 266
    if(len && maxlen)
        get_buffer(bc, string, FFMIN(len, maxlen));
    while(len > maxlen){
        get_byte(bc);
        len--;
    }
michaelni's avatar
michaelni committed
267

michael's avatar
michael committed
268 269
    if(maxlen)
        string[FFMIN(len, maxlen-1)]= 0;
270

michael's avatar
michael committed
271 272 273 274
    if(maxlen == len)
        return -1;
    else
        return 0;
275 276
}

michael's avatar
michael committed
277 278 279 280 281 282 283
static int64_t get_s(ByteIOContext *bc){
    int64_t v = get_v(bc) + 1;

    if (v&1) return -(v>>1);
    else     return  (v>>1);
}

michael's avatar
michael committed
284 285
static uint64_t get_vb(ByteIOContext *bc){
    uint64_t val=0;
michael's avatar
michael committed
286
    unsigned int i= get_v(bc);
287

michael's avatar
michael committed
288 289
    if(i>8)
        return UINT64_MAX;
290

michael's avatar
michael committed
291 292
    while(i--)
        val = (val<<8) + get_byte(bc);
293

294
//av_log(NULL, AV_LOG_DEBUG, "get_vb()= %"PRId64"\n", val);
michael's avatar
michael committed
295 296 297
    return val;
}

michael's avatar
michael committed
298 299 300 301
#ifdef TRACE
static inline uint64_t get_v_trace(ByteIOContext *bc, char *file, char *func, int line){
    uint64_t v= get_v(bc);

302
    printf("get_v %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line);
michael's avatar
michael committed
303 304 305 306 307 308
    return v;
}

static inline int64_t get_s_trace(ByteIOContext *bc, char *file, char *func, int line){
    int64_t v= get_s(bc);

309
    printf("get_s %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line);
michael's avatar
michael committed
310 311 312 313 314 315
    return v;
}

static inline uint64_t get_vb_trace(ByteIOContext *bc, char *file, char *func, int line){
    uint64_t v= get_vb(bc);

316
    printf("get_vb %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line);
michael's avatar
michael committed
317 318 319 320 321 322 323 324
    return v;
}
#define get_v(bc)  get_v_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#define get_s(bc)  get_s_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#define get_vb(bc)  get_vb_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#endif


michael's avatar
michael committed
325
static int get_packetheader(NUTContext *nut, ByteIOContext *bc, int calculate_checksum)
326
{
michael's avatar
michael committed
327 328
    int64_t start, size;
    start= url_ftell(bc) - 8;
michael's avatar
michael committed
329 330 331

    size= get_v(bc);

332
    init_checksum(bc, calculate_checksum ? av_adler32_update : NULL, 1);
333

michael's avatar
michael committed
334
    nut->packet_start[2] = start;
michael's avatar
michael committed
335 336 337
    nut->written_packet_size= size;

    return size;
338 339
}

340 341 342 343 344
static int check_checksum(ByteIOContext *bc){
    unsigned long checksum= get_checksum(bc);
    return checksum != get_be32(bc);
}

michaelni's avatar
michaelni committed
345
/**
346
 *
michaelni's avatar
michaelni committed
347 348 349
 */
static int get_length(uint64_t val){
    int i;
350

michael's avatar
michael committed
351
    for (i=7; val>>i; i+=7);
352

michael's avatar
michael committed
353
    return i;
354 355
}

michael's avatar
michael committed
356 357
static uint64_t find_any_startcode(ByteIOContext *bc, int64_t pos){
    uint64_t state=0;
358

michael's avatar
michael committed
359
    if(pos >= 0)
diego's avatar
diego committed
360
        url_fseek(bc, pos, SEEK_SET); //note, this may fail if the stream is not seekable, but that should not matter, as in this case we simply start where we are currently
michael's avatar
michael committed
361

michael's avatar
michael committed
362
    while(!url_feof(bc)){
michael's avatar
michael committed
363 364 365 366 367 368 369 370 371 372 373 374
        state= (state<<8) | get_byte(bc);
        if((state>>56) != 'N')
            continue;
        switch(state){
        case MAIN_STARTCODE:
        case STREAM_STARTCODE:
        case KEYFRAME_STARTCODE:
        case INFO_STARTCODE:
        case INDEX_STARTCODE:
            return state;
        }
    }
michael's avatar
michael committed
375

michael's avatar
michael committed
376 377 378
    return 0;
}

michael's avatar
michael committed
379 380 381 382 383 384 385
/**
 * find the given startcode.
 * @param code the startcode
 * @param pos the start position of the search, or -1 if the current position
 * @returns the position of the startcode or -1 if not found
 */
static int64_t find_startcode(ByteIOContext *bc, uint64_t code, int64_t pos){
michael's avatar
michael committed
386 387 388
    for(;;){
        uint64_t startcode= find_any_startcode(bc, pos);
        if(startcode == code)
michael's avatar
michael committed
389
            return url_ftell(bc) - 8;
michael's avatar
michael committed
390 391 392 393 394 395
        else if(startcode == 0)
            return -1;
        pos=-1;
    }
}

396 397 398 399 400 401
static int64_t lsb2full(StreamContext *stream, int64_t lsb){
    int64_t mask = (1<<stream->msb_timestamp_shift)-1;
    int64_t delta= stream->last_pts - mask/2;
    return  ((lsb - delta)&mask) + delta;
}

402
#ifdef CONFIG_MUXERS
michael's avatar
michael committed
403

michael's avatar
michael committed
404
static void put_v(ByteIOContext *bc, uint64_t val)
405 406 407
{
    int i;

408
//av_log(NULL, AV_LOG_DEBUG, "put_v()= %"PRId64"\n", val);
409
    val &= 0x7FFFFFFFFFFFFFFFULL; // FIXME can only encode upto 63 bits currently
michaelni's avatar
michaelni committed
410
    i= get_length(val);
411

michaelni's avatar
michaelni committed
412
    for (i-=7; i>0; i-=7){
413
        put_byte(bc, 0x80 | (val>>i));
michaelni's avatar
michaelni committed
414
    }
415 416 417 418

    put_byte(bc, val&0x7f);
}

michael's avatar
michael committed
419 420 421 422
/**
 * stores a string as vb.
 */
static void put_str(ByteIOContext *bc, const char *string){
michael's avatar
michael committed
423
    int len= strlen(string);
424

425
    put_v(bc, len);
michael's avatar
michael committed
426
    put_buffer(bc, string, len);
michael's avatar
michael committed
427 428
}

429
static void put_s(ByteIOContext *bc, int64_t val){
michael's avatar
michael committed
430 431 432 433
    if (val<=0) put_v(bc, -2*val  );
    else        put_v(bc,  2*val-1);
}

michael's avatar
michael committed
434 435
static void put_vb(ByteIOContext *bc, uint64_t val){
    int i;
436

michael's avatar
michael committed
437 438 439 440 441
    for (i=8; val>>i; i+=8);

    put_v(bc, i>>3);
    for(i-=8; i>=0; i-=8)
        put_byte(bc, (val>>i)&0xFF);
442 443
}

michael's avatar
michael committed
444 445
#ifdef TRACE
static inline void put_v_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){
446
    printf("get_v %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line);
447

michael's avatar
michael committed
448 449 450 451
    put_v(bc, v);
}

static inline void put_s_trace(ByteIOContext *bc, int64_t v, char *file, char *func, int line){
452
    printf("get_s %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line);
453

michael's avatar
michael committed
454 455 456 457
    put_s(bc, v);
}

static inline void put_vb_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){
458
    printf("get_vb %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line);
459

michael's avatar
michael committed
460 461 462 463 464 465 466
    put_vb(bc, v);
}
#define put_v(bc, v)  put_v_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#define put_s(bc, v)  put_s_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#define put_vb(bc, v)  put_vb_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#endif

467
static int put_packetheader(NUTContext *nut, ByteIOContext *bc, int max_size, int calculate_checksum)
468 469
{
    put_flush_packet(bc);
470
    nut->packet_start[2]= url_ftell(bc) - 8;
michael's avatar
michael committed
471
    nut->written_packet_size = max_size;
472

473
    /* packet header */
michael's avatar
michael committed
474
    put_v(bc, nut->written_packet_size); /* forward ptr */
475

476
    if(calculate_checksum)
477
        init_checksum(bc, av_adler32_update, 1);
478

479 480 481
    return 0;
}

482 483 484 485
/**
 *
 * must not be called more then once per packet
 */
486
static int update_packetheader(NUTContext *nut, ByteIOContext *bc, int additional_size, int calculate_checksum){
michael's avatar
michael committed
487
    int64_t start= nut->packet_start[2];
michael's avatar
michael committed
488
    int64_t cur= url_ftell(bc);
489
    int size= cur - start - get_length(nut->written_packet_size)/7 - 8;
490

491 492
    if(calculate_checksum)
        size += 4;
493

michael's avatar
michael committed
494 495 496 497
    if(size != nut->written_packet_size){
        int i;

        assert( size <= nut->written_packet_size );
498

michael's avatar
michael committed
499
        url_fseek(bc, start + 8, SEEK_SET);
michael's avatar
michael committed
500 501 502 503 504 505
        for(i=get_length(size); i < get_length(nut->written_packet_size); i+=7)
            put_byte(bc, 0x80);
        put_v(bc, size);

        url_fseek(bc, cur, SEEK_SET);
        nut->written_packet_size= size; //FIXME may fail if multiple updates with differing sizes, as get_length may differ
506

507 508
        if(calculate_checksum)
            put_be32(bc, get_checksum(bc));
michael's avatar
michael committed
509
    }
510

511 512 513 514 515 516 517 518
    return 0;
}

static int nut_write_header(AVFormatContext *s)
{
    NUTContext *nut = s->priv_data;
    ByteIOContext *bc = &s->pb;
    AVCodecContext *codec;
michael's avatar
michael committed
519
    int i, j, tmp_time, tmp_flags,tmp_stream, tmp_mul, tmp_size, tmp_fields;
520

521 522 523 524 525
    if (strcmp(s->filename, "./data/b-libav.nut")) {
        av_log(s, AV_LOG_ERROR, " libavformat NUT is non-compliant and disabled\n");
        return -1;
    }

michael's avatar
michael committed
526
    nut->avf= s;
527 528

    nut->stream =
529
        av_mallocz(sizeof(StreamContext)*s->nb_streams);
530

michael's avatar
michael committed
531 532 533 534

    put_buffer(bc, ID_STRING, strlen(ID_STRING));
    put_byte(bc, 0);
    nut->packet_start[2]= url_ftell(bc);
535

536
    /* main header */
michaelni's avatar
michaelni committed
537
    put_be64(bc, MAIN_STARTCODE);
538
    put_packetheader(nut, bc, 120+5*256, 1);
michael's avatar
michael committed
539
    put_v(bc, 2); /* version */
540
    put_v(bc, s->nb_streams);
michael's avatar
michael committed
541
    put_v(bc, MAX_DISTANCE);
michael's avatar
michael committed
542
    put_v(bc, MAX_SHORT_DISTANCE);
543

michael's avatar
michael committed
544 545 546
    put_v(bc, nut->rate_num=1);
    put_v(bc, nut->rate_den=2);
    put_v(bc, nut->short_startcode=0x4EFE79);
547

michael's avatar
michael committed
548
    build_frame_code(s);
michael's avatar
michael committed
549
    assert(nut->frame_code['N'].flags == FLAG_INVALID);
550

michael's avatar
michael committed
551
    tmp_time= tmp_flags= tmp_stream= tmp_mul= tmp_size= /*tmp_res=*/ INT_MAX;
michael's avatar
michael committed
552
    for(i=0; i<256;){
michael's avatar
michael committed
553 554 555 556 557 558 559 560 561 562 563 564 565 566
        tmp_fields=0;
        tmp_size= 0;
        if(tmp_time   != nut->frame_code[i].timestamp_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_plus1) 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;

        tmp_time  = nut->frame_code[i].timestamp_delta;
        tmp_flags = nut->frame_code[i].flags;
        tmp_stream= nut->frame_code[i].stream_id_plus1;
        tmp_mul   = nut->frame_code[i].size_mul;
        tmp_size  = nut->frame_code[i].size_lsb;
//        tmp_res   = nut->frame_code[i].res;
567

michael's avatar
michael committed
568
        for(j=0; i<256; j++,i++){
michael's avatar
michael committed
569
            if(nut->frame_code[i].timestamp_delta != tmp_time  ) break;
michael's avatar
michael committed
570 571 572
            if(nut->frame_code[i].flags           != tmp_flags ) break;
            if(nut->frame_code[i].stream_id_plus1 != tmp_stream) break;
            if(nut->frame_code[i].size_mul        != tmp_mul   ) break;
michael's avatar
michael committed
573 574
            if(nut->frame_code[i].size_lsb        != tmp_size+j) break;
//            if(nut->frame_code[i].res             != tmp_res   ) break;
michael's avatar
michael committed
575
        }
michael's avatar
michael committed
576 577 578 579 580 581 582 583 584 585
        if(j != tmp_mul - tmp_size) tmp_fields=6;

        put_v(bc, tmp_flags);
        put_v(bc, tmp_fields);
        if(tmp_fields>0) put_s(bc, tmp_time);
        if(tmp_fields>1) put_v(bc, tmp_mul);
        if(tmp_fields>2) put_v(bc, tmp_stream);
        if(tmp_fields>3) put_v(bc, tmp_size);
        if(tmp_fields>4) put_v(bc, 0 /*tmp_res*/);
        if(tmp_fields>5) put_v(bc, j);
michael's avatar
michael committed
586 587
    }

588
    update_packetheader(nut, bc, 0, 1);
589

590 591 592
    /* stream headers */
    for (i = 0; i < s->nb_streams; i++)
    {
593
        int nom, denom, ssize;
594

595
        codec = s->streams[i]->codec;
596

597 598 599
        put_be64(bc, STREAM_STARTCODE);
        put_packetheader(nut, bc, 120 + codec->extradata_size, 1);
        put_v(bc, i /*s->streams[i]->index*/);
michael's avatar
michael committed
600 601 602 603 604 605 606
        switch(codec->codec_type){
        case CODEC_TYPE_VIDEO: put_v(bc, 0); break;
        case CODEC_TYPE_AUDIO: put_v(bc, 1); break;
//        case CODEC_TYPE_TEXT : put_v(bc, 2); break;
        case CODEC_TYPE_DATA : put_v(bc, 3); break;
        default: return -1;
        }
607 608 609 610 611 612 613 614 615 616
        if (codec->codec_tag)
            put_vb(bc, codec->codec_tag);
        else if (codec->codec_type == CODEC_TYPE_VIDEO)
        {
            put_vb(bc, codec_get_bmp_tag(codec->codec_id));
        }
        else if (codec->codec_type == CODEC_TYPE_AUDIO)
        {
            put_vb(bc, codec_get_wav_tag(codec->codec_id));
        }
michael's avatar
michael committed
617
        else
michael's avatar
michael committed
618
            put_vb(bc, 0);
619

michael's avatar
michael committed
620
        ff_parse_specific_params(codec, &nom, &ssize, &denom);
alex's avatar
10l  
alex committed
621

michael's avatar
michael committed
622 623
        nut->stream[i].rate_num= nom;
        nut->stream[i].rate_den= denom;
624
        av_set_pts_info(s->streams[i], 60, denom, nom);
michael's avatar
michael committed
625

626 627 628 629
        put_v(bc, codec->bit_rate);
        put_vb(bc, 0); /* no language code */
        put_v(bc, nom);
        put_v(bc, denom);
michael's avatar
michael committed
630
        if(nom / denom < 1000)
631
            nut->stream[i].msb_timestamp_shift = 7;
michael's avatar
michael committed
632
        else
633 634
            nut->stream[i].msb_timestamp_shift = 14;
        put_v(bc, nut->stream[i].msb_timestamp_shift);
michael's avatar
michael committed
635
        put_v(bc, codec->has_b_frames);
636
        put_byte(bc, 0); /* flags: 0x1 - fixed_fps, 0x2 - index_present */
637

michael's avatar
michael committed
638 639 640
        if(codec->extradata_size){
            put_v(bc, 1);
            put_v(bc, codec->extradata_size);
641
            put_buffer(bc, codec->extradata, codec->extradata_size);
michael's avatar
michael committed
642
        }
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
        put_v(bc, 0); /* end of codec specific headers */

        switch(codec->codec_type)
        {
            case CODEC_TYPE_AUDIO:
                put_v(bc, codec->sample_rate);
                put_v(bc, 1);
                put_v(bc, codec->channels);
                break;
            case CODEC_TYPE_VIDEO:
                put_v(bc, codec->width);
                put_v(bc, codec->height);
                put_v(bc, codec->sample_aspect_ratio.num);
                put_v(bc, codec->sample_aspect_ratio.den);
                put_v(bc, 0); /* csp type -- unknown */
                break;
659 660
            default:
                break;
661
        }
662
        update_packetheader(nut, bc, 0, 1);
663 664 665
    }

    /* info header */
al3x's avatar
al3x committed
666
    put_be64(bc, INFO_STARTCODE);
michael's avatar
michael committed
667
    put_packetheader(nut, bc, 30+strlen(s->author)+strlen(s->title)+
668
        strlen(s->comment)+strlen(s->copyright)+strlen(LIBAVFORMAT_IDENT), 1);
669 670
    if (s->author[0])
    {
michael's avatar
michael committed
671 672
        put_v(bc, 9); /* type */
        put_str(bc, s->author);
673 674 675
    }
    if (s->title[0])
    {
michael's avatar
michael committed
676 677
        put_v(bc, 10); /* type */
        put_str(bc, s->title);
678 679 680
    }
    if (s->comment[0])
    {
michael's avatar
michael committed
681 682
        put_v(bc, 11); /* type */
        put_str(bc, s->comment);
683 684 685
    }
    if (s->copyright[0])
    {
michael's avatar
michael committed
686 687
        put_v(bc, 12); /* type */
        put_str(bc, s->copyright);
688 689
    }
    /* encoder */
690
    if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)){
michael's avatar
michael committed
691 692 693
        put_v(bc, 13); /* type */
        put_str(bc, LIBAVFORMAT_IDENT);
    }
694

al3x's avatar
al3x committed
695
    put_v(bc, 0); /* eof info */
696
    update_packetheader(nut, bc, 0, 1);
697

698
    put_flush_packet(bc);
699

700 701 702
    return 0;
}

703
static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
704 705
{
    NUTContext *nut = s->priv_data;
706
    StreamContext *stream= &nut->stream[pkt->stream_index];
707
    ByteIOContext *bc = &s->pb;
michael's avatar
michael committed
708
    int key_frame = 0, full_pts=0;
709
    AVCodecContext *enc;
michael's avatar
michael committed
710
    int64_t coded_pts;
michael's avatar
michael committed
711
    int frame_type, best_length, frame_code, flags, i, size_mul, size_lsb, time_delta;
michael's avatar
michael committed
712
    const int64_t frame_start= url_ftell(bc);
713 714 715
    int64_t pts= pkt->pts;
    int size= pkt->size;
    int stream_index= pkt->stream_index;
716

717
    enc = s->streams[stream_index]->codec;
718
    key_frame = !!(pkt->flags & PKT_FLAG_KEY);
719

michael's avatar
michael committed
720
    frame_type=0;
michael's avatar
michael committed
721 722 723 724
    if(frame_start + size + 20 - FFMAX(nut->packet_start[1], nut->packet_start[2]) > MAX_DISTANCE)
        frame_type=2;
    if(key_frame && !stream->last_key_frame)
        frame_type=2;
725

michael's avatar
michael committed
726 727 728
    if(frame_type>1){
        int64_t global_ts= av_rescale(pts, stream->rate_den*(int64_t)nut->rate_num, stream->rate_num*(int64_t)nut->rate_den);
        reset(s, global_ts);
729
        put_be64(bc, KEYFRAME_STARTCODE);
michael's avatar
michael committed
730
        put_v(bc, global_ts);
michael's avatar
michael committed
731
    }
michael's avatar
michael committed
732 733 734 735
    assert(stream->last_pts != AV_NOPTS_VALUE);
    coded_pts = pts & ((1<<stream->msb_timestamp_shift)-1);
    if(lsb2full(stream, coded_pts) != pts)
        full_pts=1;
michael's avatar
michael committed
736

michael's avatar
michael committed
737 738
    if(full_pts)
        coded_pts= pts + (1<<stream->msb_timestamp_shift);
michael's avatar
michael committed
739 740 741 742 743

    best_length=INT_MAX;
    frame_code= -1;
    for(i=0; i<256; i++){
        int stream_id_plus1= nut->frame_code[i].stream_id_plus1;
744
        int fc_key_frame;
michael's avatar
michael committed
745 746 747
        int length=0;
        size_mul= nut->frame_code[i].size_mul;
        size_lsb= nut->frame_code[i].size_lsb;
michael's avatar
michael committed
748
        time_delta= nut->frame_code[i].timestamp_delta;
michael's avatar
michael committed
749 750
        flags= nut->frame_code[i].flags;

michael's avatar
michael committed
751
        assert(size_mul > size_lsb);
752

michael's avatar
michael committed
753 754 755
        if(stream_id_plus1 == 0) length+= get_length(stream_index);
        else if(stream_id_plus1 - 1 != stream_index)
            continue;
756 757
        fc_key_frame= !!(flags & FLAG_KEY_FRAME);

michael's avatar
michael committed
758 759 760 761
        assert(key_frame==0 || key_frame==1);
        if(fc_key_frame != key_frame)
            continue;

michael's avatar
michael committed
762
        if(flags & FLAG_DATA_SIZE){
michael's avatar
michael committed
763 764
            if(size % size_mul != size_lsb)
                continue;
michael's avatar
michael committed
765 766 767
            length += get_length(size / size_mul);
        }else if(size != size_lsb)
            continue;
michael's avatar
michael committed
768

michael's avatar
michael committed
769
        if(full_pts && time_delta)
michael's avatar
michael committed
770
            continue;
771

michael's avatar
michael committed
772
        if(!time_delta){
michael's avatar
michael committed
773
            length += get_length(coded_pts);
michael's avatar
michael committed
774
        }else{
michael's avatar
michael committed
775
            if(time_delta != pts - stream->last_pts)
michael's avatar
michael committed
776 777 778 779 780 781 782 783 784
                continue;
        }

        if(length < best_length){
            best_length= length;
            frame_code=i;
        }
//    av_log(s, AV_LOG_DEBUG, "%d %d %d %d %d %d %d %d %d %d\n", key_frame, frame_type, full_pts, size, stream_index, flags, size_mul, size_lsb, stream_id_plus1, length);
    }
michaelni's avatar
michaelni committed
785

michael's avatar
michael committed
786 787 788 789
    assert(frame_code != -1);
    flags= nut->frame_code[frame_code].flags;
    size_mul= nut->frame_code[frame_code].size_mul;
    size_lsb= nut->frame_code[frame_code].size_lsb;
michael's avatar
michael committed
790 791
    time_delta= nut->frame_code[frame_code].timestamp_delta;
#ifdef TRACE
michael's avatar
michael committed
792 793
    best_length /= 7;
    best_length ++; //frame_code
michael's avatar
michael committed
794 795
    if(frame_type==2){
        best_length += 8; // startcode
michael's avatar
michael committed
796
    }
797
    av_log(s, AV_LOG_DEBUG, "kf:%d ft:%d pt:%d fc:%2X len:%2d size:%d stream:%d flag:%d mul:%d lsb:%d s+1:%d pts_delta:%d pts:%"PRId64" fs:%"PRId64"\n", key_frame, frame_type, full_pts ? 1 : 0, frame_code, best_length, size, stream_index, flags, size_mul, size_lsb, nut->frame_code[frame_code].stream_id_plus1,(int)(pts - stream->last_pts), pts, frame_start);
michael's avatar
michael committed
798
//    av_log(s, AV_LOG_DEBUG, "%d %d %d\n", stream->lru_pts_delta[0], stream->lru_pts_delta[1], stream->lru_pts_delta[2]);
michael's avatar
michael committed
799 800
#endif

michael's avatar
michael committed
801
    assert(frame_type != 1); //short startcode not implemented yet
michael's avatar
michael committed
802 803 804 805
    put_byte(bc, frame_code);

    if(nut->frame_code[frame_code].stream_id_plus1 == 0)
        put_v(bc, stream_index);
michael's avatar
michael committed
806
    if (!time_delta){
michael's avatar
michael committed
807
        put_v(bc, coded_pts);
michael's avatar
michael committed
808 809 810
    }
    if(flags & FLAG_DATA_SIZE)
        put_v(bc, size / size_mul);
michael's avatar
michael committed
811 812
    else
        assert(size == size_lsb);
michael's avatar
michael committed
813 814
    if(size > MAX_DISTANCE){
        assert(frame_type > 1);
michael's avatar
michael committed
815
    }
816

817
    put_buffer(bc, pkt->data, size);
818

michael's avatar
michael committed
819
    update(nut, stream_index, frame_start, frame_type, frame_code, key_frame, size, pts);
820

821 822 823 824 825
    return 0;
}

static int nut_write_trailer(AVFormatContext *s)
{
alex's avatar
alex committed
826
    NUTContext *nut = s->priv_data;
827
    ByteIOContext *bc = &s->pb;
michael's avatar
michael committed
828

829 830 831 832 833 834 835
#if 0
    int i;

    /* WRITE INDEX */

    for (i = 0; s->nb_streams; i++)
    {
836 837 838 839
        put_be64(bc, INDEX_STARTCODE);
        put_packetheader(nut, bc, 64, 1);
        put_v(bc, s->streams[i]->id);
        put_v(bc, ...);
840
        update_packetheader(nut, bc, 0, 1);
841 842 843 844
    }
#endif

    put_flush_packet(bc);
845

michael's avatar
michael committed
846
    av_freep(&nut->stream);
847 848 849

    return 0;
}
850
#endif //CONFIG_MUXERS
851 852 853

static int nut_probe(AVProbeData *p)
{
michaelni's avatar
michaelni committed
854
    int i;
michael's avatar
michael committed
855
    uint64_t code= 0xff;
michaelni's avatar
michaelni committed
856 857

    for (i = 0; i < p->buf_size; i++) {
michael's avatar
michael committed
858
        code = (code << 8) | p->buf[i];
michaelni's avatar
michaelni committed
859 860 861 862
        if (code == MAIN_STARTCODE)
            return AVPROBE_SCORE_MAX;
    }
    return 0;
863 864
}

michael's avatar
michael committed
865 866
static int decode_main_header(NUTContext *nut){
    AVFormatContext *s= nut->avf;
867
    ByteIOContext *bc = &s->pb;
michaelni's avatar
michaelni committed
868
    uint64_t tmp;
michael's avatar
michael committed
869
    int i, j, tmp_stream, tmp_mul, tmp_time, tmp_size, count, tmp_res;
870

michael's avatar
michael committed
871
    get_packetheader(nut, bc, 1);
michael's avatar
michael committed
872

873
    tmp = get_v(bc);
michael's avatar
michael committed
874
    if (tmp != 2){
875
        av_log(s, AV_LOG_ERROR, "bad version (%"PRId64")\n", tmp);
michael's avatar
michael committed
876 877
        return -1;
    }
878

michael's avatar
michael committed
879
    nut->stream_count = get_v(bc);
michael's avatar
michael committed
880 881 882 883
    if(nut->stream_count > MAX_STREAMS){
        av_log(s, AV_LOG_ERROR, "too many streams\n");
        return -1;
    }
michael's avatar
michael committed
884
    nut->max_distance = get_v(bc);
michael's avatar
michael committed
885
    nut->max_short_distance = get_v(bc);
michael's avatar
michael committed
886 887 888 889
    nut->rate_num= get_v(bc);
    nut->rate_den= get_v(bc);
    nut->short_startcode= get_v(bc);
    if(nut->short_startcode>>16 != 'N'){
890
        av_log(s, AV_LOG_ERROR, "invalid short startcode %X\n", nut->short_startcode);
michael's avatar
michael committed
891 892
        return -1;
    }
893

michael's avatar
michael committed
894 895
    for(i=0; i<256;){
        int tmp_flags = get_v(bc);
michael's avatar
michael committed
896 897 898 899 900 901 902 903 904 905
        int tmp_fields= get_v(bc);
        if(tmp_fields>0) tmp_time  = get_s(bc);
        if(tmp_fields>1) tmp_mul   = get_v(bc);
        if(tmp_fields>2) tmp_stream= get_v(bc);
        if(tmp_fields>3) tmp_size  = get_v(bc);
        else             tmp_size  = 0;
        if(tmp_fields>4) tmp_res   = get_v(bc);
        else             tmp_res   = 0;
        if(tmp_fields>5) count     = get_v(bc);
        else             count     = tmp_mul - tmp_size;
906 907

        while(tmp_fields-- > 6)
michael's avatar
michael committed
908
           get_v(bc);
909

michael's avatar
michael committed
910 911 912 913
        if(count == 0 || i+count > 256){
            av_log(s, AV_LOG_ERROR, "illegal count %d at %d\n", count, i);
            return -1;
        }
michael's avatar
michael committed
914 915 916 917
        if(tmp_stream > nut->stream_count + 1){
            av_log(s, AV_LOG_ERROR, "illegal stream number\n");
            return -1;
        }
michael's avatar
michael committed
918 919 920

        for(j=0; j<count; j++,i++){
            nut->frame_code[i].flags           = tmp_flags ;
michael's avatar
michael committed
921
            nut->frame_code[i].timestamp_delta = tmp_time  ;
michael's avatar
michael committed
922 923
            nut->frame_code[i].stream_id_plus1 = tmp_stream;
            nut->frame_code[i].size_mul        = tmp_mul   ;
michael's avatar
michael committed
924 925
            nut->frame_code[i].size_lsb        = tmp_size+j;
            nut->frame_code[i].reserved_count  = tmp_res   ;
michael's avatar
michael committed
926 927
        }
    }
michael's avatar
michael committed
928
    if(nut->frame_code['N'].flags != FLAG_INVALID){
michael's avatar
michael committed
929 930 931
        av_log(s, AV_LOG_ERROR, "illegal frame_code table\n");
        return -1;
    }
michael's avatar
michael committed
932

933
    if(check_checksum(bc)){
934
        av_log(s, AV_LOG_ERROR, "Main header checksum mismatch\n");
935 936
        return -1;
    }
alex's avatar
alex committed
937

michael's avatar
michael committed
938 939 940 941 942 943
    return 0;
}

static int decode_stream_header(NUTContext *nut){
    AVFormatContext *s= nut->avf;
    ByteIOContext *bc = &s->pb;
michael's avatar
michael committed
944
    int class, nom, denom, stream_id;
michael's avatar
michael committed
945 946
    uint64_t tmp;
    AVStream *st;
947

michael's avatar
michael committed
948
    get_packetheader(nut, bc, 1);
michael's avatar
michael committed
949 950 951
    stream_id= get_v(bc);
    if(stream_id >= nut->stream_count || s->streams[stream_id])
        return -1;
952

michael's avatar
michael committed
953 954 955
    st = av_new_stream(s, stream_id);
    if (!st)
        return AVERROR_NOMEM;
956

michael's avatar
michael committed
957
    class = get_v(bc);
michael's avatar
michael committed
958
    tmp = get_vb(bc);
959
    st->codec->codec_tag= tmp;
michael's avatar
michael committed
960
    switch(class)
961
    {
michael's avatar
michael committed
962
        case 0:
963 964 965
            st->codec->codec_type = CODEC_TYPE_VIDEO;
            st->codec->codec_id = codec_get_bmp_id(tmp);
            if (st->codec->codec_id == CODEC_ID_NONE)
michael's avatar
michael committed
966 967
                av_log(s, AV_LOG_ERROR, "Unknown codec?!\n");
            break;
michael's avatar
michael committed
968 969
        case 1:
        case 32: //compatibility
970 971 972
            st->codec->codec_type = CODEC_TYPE_AUDIO;
            st->codec->codec_id = codec_get_wav_id(tmp);
            if (st->codec->codec_id == CODEC_ID_NONE)
michael's avatar
michael committed
973 974
                av_log(s, AV_LOG_ERROR, "Unknown codec?!\n");
            break;
michael's avatar
michael committed
975
        case 2:
976
//            st->codec->codec_type = CODEC_TYPE_TEXT;
michael's avatar
michael committed
977 978
//            break;
        case 3:
979
            st->codec->codec_type = CODEC_TYPE_DATA;
michael's avatar
michael committed
980
            break;
michael's avatar
michael committed
981 982
        default:
            av_log(s, AV_LOG_ERROR, "Unknown stream class (%d)\n", class);
983
            return -1;
michael's avatar
michael committed
984
    }
michael's avatar
michael committed
985
    s->bit_rate += get_v(bc);
michael's avatar
michael committed
986
    get_vb(bc); /* language code */
michael's avatar
michael committed
987 988 989
    nom = get_v(bc);
    denom = get_v(bc);
    nut->stream[stream_id].msb_timestamp_shift = get_v(bc);
990
    st->codec->has_b_frames=
michael's avatar
michael committed
991
    nut->stream[stream_id].decode_delay= get_v(bc);
michael's avatar
michael committed
992 993 994 995
    get_byte(bc); /* flags */

    /* codec specific data headers */
    while(get_v(bc) != 0){
996 997
        st->codec->extradata_size= get_v(bc);
        if((unsigned)st->codec->extradata_size > (1<<30))
michael's avatar
michael committed
998
            return -1;
999
        st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
1000
        get_buffer(bc, st->codec->extradata, st->codec->extradata_size);
1001
//            url_fskip(bc, get_v(bc));
michael's avatar
michael committed
1002
    }
1003

1004
    if (st->codec->codec_type == CODEC_TYPE_VIDEO) /* VIDEO */
michael's avatar
michael committed
1005
    {
1006 1007 1008 1009
        st->codec->width = get_v(bc);
        st->codec->height = get_v(bc);
        st->codec->sample_aspect_ratio.num= get_v(bc);
        st->codec->sample_aspect_ratio.den= get_v(bc);
michael's avatar
michael committed
1010 1011
        get_v(bc); /* csp type */
    }
1012
    if (st->codec->codec_type == CODEC_TYPE_AUDIO) /* AUDIO */
michael's avatar
michael committed
1013
    {
1014
        st->codec->sample_rate = get_v(bc);
michael's avatar
michael committed
1015
        get_v(bc); // samplerate_den
1016
        st->codec->channels = get_v(bc);
michael's avatar
michael committed
1017 1018
    }
    if(check_checksum(bc)){
1019
        av_log(s, AV_LOG_ERROR, "Stream header %d checksum mismatch\n", stream_id);
michael's avatar
michael committed
1020 1021
        return -1;
    }
1022
    av_set_pts_info(s->streams[stream_id], 60, denom, nom);
michael's avatar
michael committed
1023 1024 1025 1026
    nut->stream[stream_id].rate_num= nom;
    nut->stream[stream_id].rate_den= denom;
    return 0;
}
michael's avatar
michael committed
1027

michael's avatar
michael committed
1028 1029 1030
static int decode_info_header(NUTContext *nut){
    AVFormatContext *s= nut->avf;
    ByteIOContext *bc = &s->pb;
1031

michael's avatar
michael committed
1032
    get_packetheader(nut, bc, 1);
michael's avatar
michael committed
1033 1034 1035 1036 1037 1038 1039 1040

    for(;;){
        int id= get_v(bc);
        char *name, *type, custom_name[256], custom_type[256];

        if(!id)
            break;
        else if(id >= sizeof(info_table)/sizeof(info_table[0])){
1041
            av_log(s, AV_LOG_ERROR, "info id is too large %d %zd\n", id, sizeof(info_table)/sizeof(info_table[0]));
michael's avatar
michael committed
1042 1043
            return -1;
        }
michael's avatar
michael committed
1044

michael's avatar
michael committed
1045 1046
        type= info_table[id][1];
        name= info_table[id][0];
michael's avatar
michael committed
1047 1048
//av_log(s, AV_LOG_DEBUG, "%d %s %s\n", id, type, name);

michael's avatar
michael committed
1049 1050 1051 1052 1053 1054 1055
        if(!type){
            get_str(bc, custom_type, sizeof(custom_type));
            type= custom_type;
        }
        if(!name){
            get_str(bc, custom_name, sizeof(custom_name));
            name= custom_name;
michael's avatar
michael committed
1056
        }
1057

michael's avatar
michael committed
1058
        if(!strcmp(type, "v")){
1059
            get_v(bc);
michael's avatar
michael committed
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
        }else{
            if(!strcmp(name, "Author"))
                get_str(bc, s->author, sizeof(s->author));
            else if(!strcmp(name, "Title"))
                get_str(bc, s->title, sizeof(s->title));
            else if(!strcmp(name, "Copyright"))
                get_str(bc, s->copyright, sizeof(s->copyright));
            else if(!strcmp(name, "Description"))
                get_str(bc, s->comment, sizeof(s->comment));
            else
                get_str(bc, NULL, 0);
1071
        }
michael's avatar
michael committed
1072 1073
    }
    if(check_checksum(bc)){
1074
        av_log(s, AV_LOG_ERROR, "Info header checksum mismatch\n");
michael's avatar
michael committed
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087
        return -1;
    }
    return 0;
}

static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
    NUTContext *nut = s->priv_data;
    ByteIOContext *bc = &s->pb;
    int64_t pos;
    int inited_stream_count;

    nut->avf= s;
1088

michael's avatar
michael committed
1089 1090 1091
    /* main header */
    pos=0;
    for(;;){
michael's avatar
michael committed
1092 1093
        pos= find_startcode(bc, MAIN_STARTCODE, pos)+1;
        if (pos<0){
michael's avatar
michael committed
1094 1095 1096 1097 1098 1099
            av_log(s, AV_LOG_ERROR, "no main startcode found\n");
            return -1;
        }
        if(decode_main_header(nut) >= 0)
            break;
    }
1100 1101


michael's avatar
michael committed
1102 1103 1104 1105 1106 1107 1108
    s->bit_rate = 0;

    nut->stream = av_malloc(sizeof(StreamContext)*nut->stream_count);

    /* stream headers */
    pos=0;
    for(inited_stream_count=0; inited_stream_count < nut->stream_count;){
michael's avatar
michael committed
1109
        pos= find_startcode(bc, STREAM_STARTCODE, pos)+1;
michael's avatar
michael committed
1110
        if (pos<0+1){
michael's avatar
michael committed
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
            av_log(s, AV_LOG_ERROR, "not all stream headers found\n");
            return -1;
        }
        if(decode_stream_header(nut) >= 0)
            inited_stream_count++;
    }

    /* info headers */
    pos=0;
    for(;;){
        uint64_t startcode= find_any_startcode(bc, pos);
        pos= url_ftell(bc);

        if(startcode==0){
            av_log(s, AV_LOG_ERROR, "EOF before video frames\n");
            return -1;
        }else if(startcode == KEYFRAME_STARTCODE){
michael's avatar
michael committed
1128
            nut->next_startcode= startcode;
michael's avatar
michael committed
1129 1130 1131 1132 1133 1134 1135 1136
            break;
        }else if(startcode != INFO_STARTCODE){
            continue;
        }

        decode_info_header(nut);
    }

1137 1138 1139
    return 0;
}

michael's avatar
michael committed
1140
static int decode_frame_header(NUTContext *nut, int *key_frame_ret, int64_t *pts_ret, int *stream_id_ret, int frame_code, int frame_type, int64_t frame_start){
michael's avatar
michael committed
1141
    AVFormatContext *s= nut->avf;
michael's avatar
michael committed
1142
    StreamContext *stream;
1143
    ByteIOContext *bc = &s->pb;
michael's avatar
michael committed
1144
    int size, flags, size_mul, size_lsb, stream_id, time_delta;
alex's avatar
alex committed
1145
    int64_t pts = 0;
1146

michael's avatar
michael committed
1147 1148 1149 1150 1151 1152 1153
    if(frame_type < 2 && frame_start - nut->packet_start[2] > nut->max_distance){
        av_log(s, AV_LOG_ERROR, "last frame must have been damaged\n");
        return -1;
    }

    if(frame_type)
        nut->packet_start[ frame_type ]= frame_start; //otherwise 1 goto 1 may happen
1154

michael's avatar
michael committed
1155 1156 1157 1158
    flags= nut->frame_code[frame_code].flags;
    size_mul= nut->frame_code[frame_code].size_mul;
    size_lsb= nut->frame_code[frame_code].size_lsb;
    stream_id= nut->frame_code[frame_code].stream_id_plus1 - 1;
michael's avatar
michael committed
1159
    time_delta= nut->frame_code[frame_code].timestamp_delta;
1160

michael's avatar
michael committed
1161 1162 1163 1164 1165 1166 1167
    if(stream_id==-1)
        stream_id= get_v(bc);
    if(stream_id >= s->nb_streams){
        av_log(s, AV_LOG_ERROR, "illegal stream_id\n");
        return -1;
    }
    stream= &nut->stream[stream_id];
michael's avatar
michael committed
1168 1169

//    av_log(s, AV_LOG_DEBUG, "ft:%d ppts:%d %d %d\n", frame_type, stream->lru_pts_delta[0], stream->lru_pts_delta[1], stream->lru_pts_delta[2]);
michael's avatar
michael committed
1170 1171 1172

    *key_frame_ret= !!(flags & FLAG_KEY_FRAME);

michael's avatar
michael committed
1173
    if(!time_delta){
michael's avatar
michael committed
1174 1175 1176 1177
        int64_t mask = (1<<stream->msb_timestamp_shift)-1;
        pts= get_v(bc);
        if(pts > mask){
            pts -= mask+1;
michael's avatar
michael committed
1178
        }else{
michael's avatar
michael committed
1179 1180 1181 1182 1183
            if(stream->last_pts == AV_NOPTS_VALUE){
                av_log(s, AV_LOG_ERROR, "no reference pts available\n");
                return -1;
            }
            pts= lsb2full(stream, pts);
michael's avatar
michael committed
1184 1185
        }
    }else{
michael's avatar
michael committed
1186 1187 1188 1189
        if(stream->last_pts == AV_NOPTS_VALUE){
            av_log(s, AV_LOG_ERROR, "no reference pts available\n");
            return -1;
        }
michael's avatar
michael committed
1190
        pts= stream->last_pts + time_delta;
michael's avatar
michael committed
1191
    }
michael's avatar
michael committed
1192 1193

    if(*key_frame_ret){
1194
//        av_log(s, AV_LOG_DEBUG, "stream:%d start:%"PRId64" pts:%"PRId64" length:%"PRId64"\n",stream_id, frame_start, av_pts, frame_start - nut->stream[stream_id].last_sync_pos);
michael's avatar
michael committed
1195
        av_add_index_entry(
1196 1197 1198
            s->streams[stream_id],
            frame_start,
            pts,
michael's avatar
michael committed
1199
            0,
michael's avatar
michael committed
1200 1201 1202 1203
            frame_start - nut->stream[stream_id].last_sync_pos,
            AVINDEX_KEYFRAME);
        nut->stream[stream_id].last_sync_pos= frame_start;
//                assert(nut->packet_start == frame_start);
michael's avatar
michael committed
1204
    }
michael's avatar
michael committed
1205 1206 1207 1208 1209

    assert(size_mul > size_lsb);
    size= size_lsb;
    if(flags & FLAG_DATA_SIZE)
        size+= size_mul*get_v(bc);
1210

michael's avatar
michael committed
1211
#ifdef TRACE
1212
av_log(s, AV_LOG_DEBUG, "fs:%"PRId64" fc:%d ft:%d kf:%d pts:%"PRId64" size:%d mul:%d lsb:%d flags:%d delta:%d\n", frame_start, frame_code, frame_type, *key_frame_ret, pts, size, size_mul, size_lsb, flags, time_delta);
michael's avatar
michael committed
1213
#endif
michael's avatar
michael committed
1214

michael's avatar
michael committed
1215
    if(frame_type==0 && url_ftell(bc) - nut->packet_start[2] + size > nut->max_distance){
michael's avatar
michael committed
1216 1217 1218
        av_log(s, AV_LOG_ERROR, "frame size too large\n");
        return -1;
    }
1219

michael's avatar
michael committed
1220
    *stream_id_ret = stream_id;
1221
    *pts_ret = pts;
michael's avatar
michael committed
1222 1223 1224 1225 1226 1227

    update(nut, stream_id, frame_start, frame_type, frame_code, *key_frame_ret, size, pts);

    return size;
}

michael's avatar
michael committed
1228
static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code, int frame_type, int64_t frame_start){
michael's avatar
michael committed
1229 1230
    AVFormatContext *s= nut->avf;
    ByteIOContext *bc = &s->pb;
1231 1232
    int size, stream_id, key_frame, discard;
    int64_t pts, last_IP_pts;
1233

michael's avatar
michael committed
1234
    size= decode_frame_header(nut, &key_frame, &pts, &stream_id, frame_code, frame_type, frame_start);
michael's avatar
michael committed
1235 1236 1237
    if(size < 0)
        return -1;

1238 1239 1240 1241 1242
    discard= s->streams[ stream_id ]->discard;
    last_IP_pts= s->streams[ stream_id ]->last_IP_pts;
    if(  (discard >= AVDISCARD_NONKEY && !key_frame)
       ||(discard >= AVDISCARD_BIDIR && last_IP_pts != AV_NOPTS_VALUE && last_IP_pts > pts)
       || discard >= AVDISCARD_ALL){
1243 1244 1245 1246
        url_fskip(bc, size);
        return 1;
    }

michael's avatar
michael committed
1247
    av_get_packet(bc, pkt, size);
michael's avatar
michael committed
1248
    pkt->stream_index = stream_id;
1249
    if (key_frame)
1250
        pkt->flags |= PKT_FLAG_KEY;
michael's avatar
michael committed
1251
    pkt->pts = pts;
michael's avatar
michael committed
1252 1253 1254 1255

    return 0;
}

michael's avatar
michael committed
1256 1257 1258 1259
static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
{
    NUTContext *nut = s->priv_data;
    ByteIOContext *bc = &s->pb;
1260
    int i, frame_code=0, ret;
michael's avatar
michael committed
1261 1262

    for(;;){
michael's avatar
michael committed
1263
        int64_t pos= url_ftell(bc);
michael's avatar
michael committed
1264
        int frame_type= 0;
michael's avatar
michael committed
1265 1266 1267 1268 1269 1270
        uint64_t tmp= nut->next_startcode;
        nut->next_startcode=0;

        if (url_feof(bc))
            return -1;

michael's avatar
michael committed
1271 1272 1273
        if(tmp){
            pos-=8;
        }else{
michael's avatar
michael committed
1274 1275 1276
            frame_code = get_byte(bc);
            if(frame_code == 'N'){
                tmp= frame_code;
michael's avatar
michael committed
1277 1278
                for(i=1; i<8; i++)
                    tmp = (tmp<<8) + get_byte(bc);
michael's avatar
michael committed
1279 1280 1281 1282 1283 1284
            }
        }
        switch(tmp){
        case MAIN_STARTCODE:
        case STREAM_STARTCODE:
        case INDEX_STARTCODE:
michael's avatar
michael committed
1285
            get_packetheader(nut, bc, 0);
michael's avatar
michael committed
1286
            assert(nut->packet_start[2] == pos);
1287
            url_fseek(bc, nut->written_packet_size, SEEK_CUR);
michael's avatar
michael committed
1288 1289 1290 1291 1292
            break;
        case INFO_STARTCODE:
            if(decode_info_header(nut)<0)
                goto resync;
            break;
michael's avatar
michael committed
1293 1294
        case KEYFRAME_STARTCODE:
            frame_type = 2;
michael's avatar
michael committed
1295
            reset(s, get_v(bc));
michael's avatar
michael committed
1296
            frame_code = get_byte(bc);
michael's avatar
michael committed
1297
        case 0:
1298 1299
            ret= decode_frame(nut, pkt, frame_code, frame_type, pos);
            if(ret==0)
michael's avatar
michael committed
1300
                return 0;
1301 1302
            else if(ret==1) //ok but discard packet
                break;
michael's avatar
michael committed
1303 1304
        default:
resync:
1305
av_log(s, AV_LOG_DEBUG, "syncing from %"PRId64"\n", nut->packet_start[2]+1);
michael's avatar
michael committed
1306
            tmp= find_any_startcode(bc, nut->packet_start[2]+1);
michael's avatar
michael committed
1307 1308 1309
            if(tmp==0)
                return -1;
av_log(s, AV_LOG_DEBUG, "sync\n");
michael's avatar
michael committed
1310
            nut->next_startcode= tmp;
michael's avatar
michael committed
1311 1312 1313 1314
        }
    }
}

1315
static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos_arg, int64_t pos_limit){
michael's avatar
michael committed
1316
    NUTContext *nut = s->priv_data;
1317
    StreamContext *stream;
michael's avatar
michael committed
1318 1319 1320
    ByteIOContext *bc = &s->pb;
    int64_t pos, pts;
    uint64_t code;
michael's avatar
michael committed
1321
    int frame_code,step, stream_id, i,size, key_frame;
1322
av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%"PRId64",%"PRId64")\n", stream_index, *pos_arg, pos_limit);
michael's avatar
michael committed
1323 1324 1325 1326 1327 1328 1329 1330 1331 1332

    if(*pos_arg < 0)
        return AV_NOPTS_VALUE;

    pos= *pos_arg;
    step= FFMIN(16*1024, pos);
    do{
        pos-= step;
        code= find_any_startcode(bc, pos);

michael's avatar
michael committed
1333
        if(code && url_ftell(bc) - 8 <= *pos_arg)
michael's avatar
michael committed
1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
            break;
        step= FFMIN(2*step, pos);
    }while(step);

    if(!code) //nothing found, not even after pos_arg
        return AV_NOPTS_VALUE;

    url_fseek(bc, -8, SEEK_CUR);
    for(i=0; i<s->nb_streams; i++)
        nut->stream[i].last_sync_pos= url_ftell(bc);
1344

michael's avatar
michael committed
1345
    for(;;){
michael's avatar
michael committed
1346
        int frame_type=0;
michael's avatar
michael committed
1347 1348
        int64_t pos= url_ftell(bc);
        uint64_t tmp=0;
1349

michael's avatar
michael committed
1350
        if(pos > pos_limit || url_feof(bc))
michael's avatar
michael committed
1351 1352 1353 1354 1355 1356 1357 1358
            return AV_NOPTS_VALUE;

        frame_code = get_byte(bc);
        if(frame_code == 'N'){
            tmp= frame_code;
            for(i=1; i<8; i++)
                tmp = (tmp<<8) + get_byte(bc);
        }
1359
//av_log(s, AV_LOG_DEBUG, "before switch %"PRIX64" at=%"PRId64"\n", tmp, pos);
michael's avatar
michael committed
1360 1361 1362 1363 1364 1365

        switch(tmp){
        case MAIN_STARTCODE:
        case STREAM_STARTCODE:
        case INDEX_STARTCODE:
        case INFO_STARTCODE:
michael's avatar
michael committed
1366 1367
            get_packetheader(nut, bc, 0);
            assert(nut->packet_start[2]==pos);
1368
            url_fseek(bc, nut->written_packet_size, SEEK_CUR);
michael's avatar
michael committed
1369 1370
            break;
        case KEYFRAME_STARTCODE:
michael's avatar
michael committed
1371
            frame_type=2;
michael's avatar
michael committed
1372
            reset(s, get_v(bc));
michael's avatar
michael committed
1373 1374
            frame_code = get_byte(bc);
        case 0:
michael's avatar
michael committed
1375
            size= decode_frame_header(nut, &key_frame, &pts, &stream_id, frame_code, frame_type, pos);
michael's avatar
michael committed
1376
            if(size < 0)
michael's avatar
michael committed
1377
                goto resync;
1378

1379
            stream= &nut->stream[stream_id];
michael's avatar
michael committed
1380 1381
            if(stream_id != stream_index || !key_frame || pos < *pos_arg){
                url_fseek(bc, size, SEEK_CUR);
michael's avatar
michael committed
1382 1383
                break;
            }
1384

michael's avatar
michael committed
1385
            *pos_arg= pos;
michael's avatar
michael committed
1386 1387 1388
            return pts;
        default:
resync:
1389
av_log(s, AV_LOG_DEBUG, "syncing from %"PRId64"\n", nut->packet_start[2]+1);
michael's avatar
michael committed
1390
            if(!find_any_startcode(bc, nut->packet_start[2]+1))
michael's avatar
michael committed
1391 1392 1393
                return AV_NOPTS_VALUE;

            url_fseek(bc, -8, SEEK_CUR);
michael's avatar
michael committed
1394 1395
        }
    }
michael's avatar
michael committed
1396 1397 1398
    return AV_NOPTS_VALUE;
}

michael's avatar
michael committed
1399
static int nut_read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){
michael's avatar
michael committed
1400
//    NUTContext *nut = s->priv_data;
1401
    int64_t pos;
michael's avatar
michael committed
1402

michael's avatar
michael committed
1403
    if(av_seek_frame_binary(s, stream_index, target_ts, flags) < 0)
1404
        return -1;
michael's avatar
michael committed
1405

1406
    pos= url_ftell(&s->pb);
michael's avatar
michael committed
1407
    nut_read_timestamp(s, stream_index, &pos, pos-1);
michael's avatar
michael committed
1408 1409

    return 0;
michael's avatar
michael committed
1410 1411
}

michael's avatar
michael committed
1412 1413 1414 1415 1416
static int nut_read_close(AVFormatContext *s)
{
    NUTContext *nut = s->priv_data;

    av_freep(&nut->stream);
1417 1418 1419 1420

    return 0;
}

1421 1422
#ifdef CONFIG_NUT_DEMUXER
AVInputFormat nut_demuxer = {
1423 1424 1425 1426 1427 1428
    "nut",
    "nut format",
    sizeof(NUTContext),
    nut_probe,
    nut_read_header,
    nut_read_packet,
michael's avatar
michael committed
1429
    nut_read_close,
michael's avatar
michael committed
1430
    nut_read_seek,
1431
    nut_read_timestamp,
1432 1433
    .extensions = "nut",
};
1434 1435 1436
#endif
#ifdef CONFIG_NUT_MUXER
AVOutputFormat nut_muxer = {
1437 1438 1439 1440 1441
    "nut",
    "nut format",
    "video/x-nut",
    "nut",
    sizeof(NUTContext),
michael's avatar
michael committed
1442
#ifdef CONFIG_LIBVORBIS
1443
    CODEC_ID_VORBIS,
1444
#elif defined(CONFIG_LIBMP3LAME)
bellard's avatar
bellard committed
1445
    CODEC_ID_MP3,
1446
#else
al3x's avatar
al3x committed
1447
    CODEC_ID_MP2, /* AC3 needs liba52 decoder */
1448 1449 1450 1451 1452
#endif
    CODEC_ID_MPEG4,
    nut_write_header,
    nut_write_packet,
    nut_write_trailer,
1453
    .flags = AVFMT_GLOBALHEADER,
1454
};
1455
#endif