nutenc.c 25.7 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
#include "libavutil/intreadwrite.h"
23 24
#include "libavutil/tree.h"
#include "libavcodec/mpegaudiodata.h"
25
#include "nut.h"
26
#include "internal.h"
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

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

    if(size>4096)
        return 0;

    AV_WB24(out, 1);

    if(c->codec_id == CODEC_ID_MPEG4){
        if(key_frame){
            return 3;
        }else{
            out[3]= 0xB6;
            return 4;
        }
    }else if(c->codec_id == CODEC_ID_MPEG1VIDEO || c->codec_id == CODEC_ID_MPEG2VIDEO){
        return 3;
    }else if(c->codec_id == CODEC_ID_H264){
        return 3;
    }else if(c->codec_id == CODEC_ID_MP3 || c->codec_id == CODEC_ID_MP2){
        int lsf, mpeg25, sample_rate_index, bitrate_index, frame_size;
        int layer= c->codec_id == CODEC_ID_MP3 ? 3 : 2;
        unsigned int header= 0xFFF00000;

        lsf     = sample_rate < (24000+32000)/2;
        mpeg25  = sample_rate < (12000+16000)/2;
        sample_rate <<= lsf + mpeg25;
        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;

        sample_rate= ff_mpa_freq_tab[sample_rate_index] >> (lsf + mpeg25);

        for(bitrate_index=2; bitrate_index<30; bitrate_index++){
            frame_size = ff_mpa_bitrate_tab[lsf][layer-1][bitrate_index>>1];
            frame_size = (frame_size * 144000) / (sample_rate << lsf) + (bitrate_index&1);

            if(frame_size == size)
                break;
        }

        header |= (!lsf)<<19;
        header |= (4-layer)<<17;
        header |= 1<<16; //no crc
        AV_WB32(out, header);
        if(size <= 0)
Diego Biurrun's avatar
Diego Biurrun committed
74
            return 2; //we guess there is no crc, if there is one the user clearly does not care about overhead
75 76 77 78 79 80 81 82
        if(bitrate_index == 30)
            return -1; //something is wrong ...

        header |= (bitrate_index>>1)<<12;
        header |= sample_rate_index<<10;
        header |= (bitrate_index&1)<<9;

        return 2; //FIXME actually put the needed ones in build_elision_headers()
Diego Biurrun's avatar
Diego Biurrun committed
83 84
        return 3; //we guess that the private bit is not set
//FIXME the above assumptions should be checked, if these turn out false too often something should be done
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
    }
    return 0;
}

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

//av_log(NULL, AV_LOG_ERROR, "expected_h len=%d size=%d codec_id=%d\n", len, size, c->codec_id);

    for(i=1; i<nut->header_count; i++){
        if(   len == nut->header_len[i]
           && !memcmp(out, nut->header[i], len)){
//    av_log(NULL, AV_LOG_ERROR, "found %d\n", i);
            return i;
        }
    }
//    av_log(NULL, AV_LOG_ERROR, "nothing found\n");
    return 0;
}

static void build_elision_headers(AVFormatContext *s){
    NUTContext *nut = s->priv_data;
    int i;
    //FIXME this is lame
    //FIXME write a 2pass mode to find the maximal headers
113
    static const uint8_t headers[][5]={
114 115 116 117 118 119 120 121 122 123 124 125 126 127
        {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
    };

    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];
    }
}
128 129 130 131 132 133 134 135

static void build_frame_code(AVFormatContext *s){
    NUTContext *nut = s->priv_data;
    int key_frame, index, pred, stream_id;
    int start=1;
    int end= 254;
    int keyframe_0_esc= s->nb_streams > 2;
    int pred_table[10];
136 137 138 139 140 141 142
    FrameCode *ft;

    ft= &nut->frame_code[start];
    ft->flags= FLAG_CODED;
    ft->size_mul=1;
    ft->pts_delta=1;
    start++;
143 144 145 146 147 148 149 150 151 152 153 154 155

    if(keyframe_0_esc){
        /* keyframe = 0 escape */
        FrameCode *ft= &nut->frame_code[start];
        ft->flags= FLAG_STREAM_ID | FLAG_SIZE_MSB | FLAG_CODED_PTS;
        ft->size_mul=1;
        start++;
    }

    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;
        AVCodecContext *codec = s->streams[stream_id]->codec;
156
        int is_audio= codec->codec_type == AVMEDIA_TYPE_AUDIO;
157 158 159 160 161 162 163 164 165 166 167 168 169
        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;

            {
                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;
170 171
                if(is_audio)
                    ft->header_idx= find_header_idx(s, codec, -1, key_frame);
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
                start2++;
            }
        }

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

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

        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];
                ft->flags= FLAG_KEY*key_frame;
                ft->flags|= FLAG_SIZE_MSB;
                ft->stream_id= stream_id;
//FIXME use single byte size and pred from last
                ft->size_mul= end3-start3;
                ft->size_lsb= index - start3;
                ft->pts_delta= pred_table[pred];
233 234
                if(is_audio)
                    ft->header_idx= find_header_idx(s, codec, -1, key_frame);
235 236 237 238 239 240 241 242 243
            }
        }
    }
    memmove(&nut->frame_code['N'+1], &nut->frame_code['N'], sizeof(FrameCode)*(255-'N'));
    nut->frame_code[  0].flags=
    nut->frame_code[255].flags=
    nut->frame_code['N'].flags= FLAG_INVALID;
}

244
static void put_tt(NUTContext *nut, StreamContext *nus, ByteIOContext *bc, uint64_t val){
Michael Niedermayer's avatar
put_t()  
Michael Niedermayer committed
245 246
    val *= nut->time_base_count;
    val += nus->time_base - nut->time_base;
247
    ff_put_v(bc, val);
Michael Niedermayer's avatar
put_t()  
Michael Niedermayer committed
248 249
}

250
/**
251
 * Store a string as vb.
252 253 254 255
 */
static void put_str(ByteIOContext *bc, const char *string){
    int len= strlen(string);

256
    ff_put_v(bc, len);
257 258 259 260
    put_buffer(bc, string, len);
}

static void put_s(ByteIOContext *bc, int64_t val){
261
    ff_put_v(bc, 2*FFABS(val) - (val>0));
262 263 264
}

#ifdef TRACE
265 266
static inline void ff_put_v_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){
    av_log(NULL, AV_LOG_DEBUG, "ff_put_v %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line);
267

268
    ff_put_v(bc, v);
269 270 271
}

static inline void put_s_trace(ByteIOContext *bc, int64_t v, char *file, char *func, int line){
Michael Niedermayer's avatar
Michael Niedermayer committed
272
    av_log(NULL, AV_LOG_DEBUG, "put_s %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line);
273 274 275

    put_s(bc, v);
}
276
#define ff_put_v(bc, v)  ff_put_v_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
277 278 279
#define put_s(bc, v)  put_s_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#endif

Michael Niedermayer's avatar
Michael Niedermayer committed
280
//FIXME remove calculate_checksum
Michael Niedermayer's avatar
Michael Niedermayer committed
281
static void put_packet(NUTContext *nut, ByteIOContext *bc, ByteIOContext *dyn_bc, int calculate_checksum, uint64_t startcode){
282 283
    uint8_t *dyn_buf=NULL;
    int dyn_size= url_close_dyn_buf(dyn_bc, &dyn_buf);
Michael Niedermayer's avatar
Michael Niedermayer committed
284 285 286
    int forw_ptr= dyn_size + 4*calculate_checksum;

    if(forw_ptr > 4096)
287
        init_checksum(bc, ff_crc04C11DB7_update, 0);
Michael Niedermayer's avatar
Michael Niedermayer committed
288
    put_be64(bc, startcode);
289
    ff_put_v(bc, forw_ptr);
Michael Niedermayer's avatar
Michael Niedermayer committed
290 291
    if(forw_ptr > 4096)
        put_le32(bc, get_checksum(bc));
292 293

    if(calculate_checksum)
294
        init_checksum(bc, ff_crc04C11DB7_update, 0);
295
    put_buffer(bc, dyn_buf, dyn_size);
296
    if(calculate_checksum)
297
        put_le32(bc, get_checksum(bc));
298

299
    av_free(dyn_buf);
300 301
}

302
static void write_mainheader(NUTContext *nut, ByteIOContext *bc){
303 304
    int i, j, tmp_pts, tmp_flags, tmp_stream, tmp_mul, tmp_size, tmp_fields, tmp_head_idx;
    int64_t tmp_match;
305

306 307 308 309
    ff_put_v(bc, 3); /* version */
    ff_put_v(bc, nut->avf->nb_streams);
    ff_put_v(bc, nut->max_distance);
    ff_put_v(bc, nut->time_base_count);
310 311

    for(i=0; i<nut->time_base_count; i++){
312 313
        ff_put_v(bc, nut->time_base[i].num);
        ff_put_v(bc, nut->time_base[i].den);
314 315 316 317 318
    }

    tmp_pts=0;
    tmp_mul=1;
    tmp_stream=0;
319 320
    tmp_match= 1-(1LL<<62);
    tmp_head_idx= 0;
321 322 323 324 325 326 327 328 329
    for(i=0; i<256;){
        tmp_fields=0;
        tmp_size=0;
//        tmp_res=0;
        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;
330
        if(tmp_head_idx!=nut->frame_code[i].header_idx)tmp_fields=8;
331 332 333 334 335 336 337

        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;
//        tmp_res   = nut->frame_code[i].res;
338
        tmp_head_idx= nut->frame_code[i].header_idx;
339 340 341 342 343 344 345 346 347 348 349 350

        for(j=0; i<256; j++,i++){
            if(i == 'N'){
                j--;
                continue;
            }
            if(nut->frame_code[i].pts_delta != tmp_pts   ) break;
            if(nut->frame_code[i].flags     != tmp_flags ) break;
            if(nut->frame_code[i].stream_id != tmp_stream) break;
            if(nut->frame_code[i].size_mul  != tmp_mul   ) break;
            if(nut->frame_code[i].size_lsb  != tmp_size+j) break;
//            if(nut->frame_code[i].res       != tmp_res   ) break;
351
            if(nut->frame_code[i].header_idx!= tmp_head_idx) break;
352 353 354
        }
        if(j != tmp_mul - tmp_size) tmp_fields=6;

355 356
        ff_put_v(bc, tmp_flags);
        ff_put_v(bc, tmp_fields);
357
        if(tmp_fields>0) put_s(bc, tmp_pts);
358 359 360 361 362 363 364
        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);
365
    }
366
    ff_put_v(bc, nut->header_count-1);
367
    for(i=1; i<nut->header_count; i++){
368
        ff_put_v(bc, nut->header_len[i]);
369
        put_buffer(bc, nut->header[i], nut->header_len[i]);
370
    }
371
}
372

373 374
static int write_streamheader(AVFormatContext *avctx, ByteIOContext *bc, AVStream *st, int i){
    NUTContext *nut = avctx->priv_data;
375
    AVCodecContext *codec = st->codec;
376
    ff_put_v(bc, i);
377
    switch(codec->codec_type){
378 379 380 381
    case AVMEDIA_TYPE_VIDEO: ff_put_v(bc, 0); break;
    case AVMEDIA_TYPE_AUDIO: ff_put_v(bc, 1); break;
    case AVMEDIA_TYPE_SUBTITLE: ff_put_v(bc, 2); break;
    default              : ff_put_v(bc, 3); break;
382
    }
383
    ff_put_v(bc, 4);
384 385
    if (codec->codec_tag){
        put_le32(bc, codec->codec_tag);
386 387
    } else {
        av_log(avctx, AV_LOG_ERROR, "No codec tag defined for stream %d\n", i);
388
        return AVERROR(EINVAL);
389
    }
390

391 392 393 394
    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);
395 396
    put_byte(bc, 0); /* flags: 0x1 - fixed_fps, 0x2 - index_present */

397
    ff_put_v(bc, codec->extradata_size);
398 399 400
    put_buffer(bc, codec->extradata, codec->extradata_size);

    switch(codec->codec_type){
401
    case AVMEDIA_TYPE_AUDIO:
402 403 404
        ff_put_v(bc, codec->sample_rate);
        ff_put_v(bc, 1);
        ff_put_v(bc, codec->channels);
405
        break;
406
    case AVMEDIA_TYPE_VIDEO:
407 408
        ff_put_v(bc, codec->width);
        ff_put_v(bc, codec->height);
409

410
        if(st->sample_aspect_ratio.num<=0 || st->sample_aspect_ratio.den<=0){
411 412
            ff_put_v(bc, 0);
            ff_put_v(bc, 0);
413
        }else{
414 415
            ff_put_v(bc, st->sample_aspect_ratio.num);
            ff_put_v(bc, st->sample_aspect_ratio.den);
416
        }
417
        ff_put_v(bc, 0); /* csp type -- unknown */
418 419 420 421 422 423 424
        break;
    default:
        break;
    }
    return 0;
}

425
static int add_info(ByteIOContext *bc, const char *type, const char *value){
Michael Niedermayer's avatar
Michael Niedermayer committed
426 427 428 429 430 431
    put_str(bc, type);
    put_s(bc, -1);
    put_str(bc, value);
    return 1;
}

432
static int write_globalinfo(NUTContext *nut, ByteIOContext *bc){
Michael Niedermayer's avatar
Michael Niedermayer committed
433
    AVFormatContext *s= nut->avf;
434
    AVMetadataTag *t = NULL;
435
    ByteIOContext *dyn_bc;
Michael Niedermayer's avatar
Michael Niedermayer committed
436 437
    uint8_t *dyn_buf=NULL;
    int count=0, dyn_size;
438 439 440
    int ret = url_open_dyn_buf(&dyn_bc);
    if(ret < 0)
        return ret;
Michael Niedermayer's avatar
Michael Niedermayer committed
441

442 443
    while ((t = av_metadata_get(s->metadata, "", t, AV_METADATA_IGNORE_SUFFIX)))
        count += add_info(dyn_bc, t->key, t->value);
Michael Niedermayer's avatar
Michael Niedermayer committed
444

445 446 447 448
    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
449

450
    ff_put_v(bc, count);
Michael Niedermayer's avatar
Michael Niedermayer committed
451

452
    dyn_size= url_close_dyn_buf(dyn_bc, &dyn_buf);
Michael Niedermayer's avatar
Michael Niedermayer committed
453 454
    put_buffer(bc, dyn_buf, dyn_size);
    av_free(dyn_buf);
455
    return 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
456 457
}

458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
static int write_streaminfo(NUTContext *nut, ByteIOContext *bc, int stream_id){
    AVFormatContext *s= nut->avf;
    AVStream* st = s->streams[stream_id];
    ByteIOContext *dyn_bc;
    uint8_t *dyn_buf=NULL;
    int count=0, dyn_size, i;
    int ret = url_open_dyn_buf(&dyn_bc);
    if(ret < 0)
        return ret;

    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);
    }
    dyn_size = url_close_dyn_buf(dyn_bc, &dyn_buf);

    if (count) {
475 476 477 478
        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
479

480
        ff_put_v(bc, count);
481 482 483 484 485 486 487 488

        put_buffer(bc, dyn_buf, dyn_size);
    }

    av_free(dyn_buf);
    return count;
}

489 490
static int write_headers(AVFormatContext *avctx, ByteIOContext *bc){
    NUTContext *nut = avctx->priv_data;
491 492
    ByteIOContext *dyn_bc;
    int i, ret;
493

494 495 496 497 498
    ret = url_open_dyn_buf(&dyn_bc);
    if(ret < 0)
        return ret;
    write_mainheader(nut, dyn_bc);
    put_packet(nut, bc, dyn_bc, 1, MAIN_STARTCODE);
499 500

    for (i=0; i < nut->avf->nb_streams; i++){
501 502 503
        ret = url_open_dyn_buf(&dyn_bc);
        if(ret < 0)
            return ret;
504 505
        if ((ret = write_streamheader(avctx, dyn_bc, nut->avf->streams[i], i)) < 0)
            return ret;
506
        put_packet(nut, bc, dyn_bc, 1, STREAM_STARTCODE);
507
    }
Michael Niedermayer's avatar
Michael Niedermayer committed
508

509 510 511 512 513
    ret = url_open_dyn_buf(&dyn_bc);
    if(ret < 0)
        return ret;
    write_globalinfo(nut, dyn_bc);
    put_packet(nut, bc, dyn_bc, 1, INFO_STARTCODE);
Michael Niedermayer's avatar
Michael Niedermayer committed
514

515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
    for (i = 0; i < nut->avf->nb_streams; i++) {
        ret = url_open_dyn_buf(&dyn_bc);
        if(ret < 0)
            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 {
            uint8_t* buf;
            url_close_dyn_buf(dyn_bc, &buf);
            av_free(buf);
        }
    }

Michael Niedermayer's avatar
Michael Niedermayer committed
531 532
    nut->last_syncpoint_pos= INT_MIN;
    nut->header_count++;
533
    return 0;
534 535
}

536 537
static int write_header(AVFormatContext *s){
    NUTContext *nut = s->priv_data;
538
    ByteIOContext *bc = s->pb;
539
    int i, j, ret;
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563

    nut->avf= s;

    nut->stream   = av_mallocz(sizeof(StreamContext)*s->nb_streams);
    nut->time_base= av_mallocz(sizeof(AVRational   )*s->nb_streams);

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

        av_set_pts_info(st, 64, time_base.num, time_base.den);

        for(j=0; j<nut->time_base_count; j++){
            if(!memcmp(&time_base, &nut->time_base[j], sizeof(AVRational))){
                break;
            }
        }
        nut->time_base[j]= time_base;
        nut->stream[i].time_base= &nut->time_base[j];
        if(j==nut->time_base_count)
            nut->time_base_count++;

564
        if(INT64_C(1000) * time_base.num >= time_base.den)
565 566 567
            nut->stream[i].msb_pts_shift = 7;
        else
            nut->stream[i].msb_pts_shift = 14;
568
        nut->stream[i].max_pts_distance= FFMAX(time_base.den, time_base.num) / time_base.num;
569 570
    }

571
    nut->max_distance = MAX_DISTANCE;
572
    build_elision_headers(s);
573 574 575 576 577 578
    build_frame_code(s);
    assert(nut->frame_code['N'].flags == FLAG_INVALID);

    put_buffer(bc, ID_STRING, strlen(ID_STRING));
    put_byte(bc, 0);

579 580
    if ((ret = write_headers(s, bc)) < 0)
        return ret;
Michael Niedermayer's avatar
Michael Niedermayer committed
581

582 583
    put_flush_packet(bc);

Michael Niedermayer's avatar
Michael Niedermayer committed
584
    //FIXME index
585 586 587 588

    return 0;
}

589 590 591
static int get_needed_flags(NUTContext *nut, StreamContext *nus, FrameCode *fc, AVPacket *pkt){
    int flags= 0;

592
    if(pkt->flags & AV_PKT_FLAG_KEY             ) flags |= FLAG_KEY;
593 594 595 596 597 598
    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;
    if(pkt->size > 2*nut->max_distance          ) flags |= FLAG_CHECKSUM;
    if(FFABS(pkt->pts - nus->last_pts)
                         > nus->max_pts_distance) flags |= FLAG_CHECKSUM;
599 600 601 602
    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;
603

Michael Niedermayer's avatar
Michael Niedermayer committed
604
    return flags | (fc->flags & FLAG_CODED);
605 606
}

607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
static int find_best_header_idx(NUTContext *nut, AVPacket *pkt){
    int i;
    int best_i  = 0;
    int best_len= 0;

    if(pkt->size > 4096)
        return 0;

    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];
        }
    }
    return best_i;
}

626
static int write_packet(AVFormatContext *s, AVPacket *pkt){
627 628
    NUTContext *nut = s->priv_data;
    StreamContext *nus= &nut->stream[pkt->stream_index];
629
    ByteIOContext *bc = s->pb, *dyn_bc;
630 631
    FrameCode *fc;
    int64_t coded_pts;
632
    int best_length, frame_code, flags, needed_flags, i, header_idx, best_header_idx;
633
    int key_frame = !!(pkt->flags & AV_PKT_FLAG_KEY);
634
    int store_sp=0;
635
    int ret;
636

637 638 639
    if(pkt->pts < 0)
        return -1;

Michael Niedermayer's avatar
Michael Niedermayer committed
640
    if(1LL<<(20+3*nut->header_count) <= url_ftell(bc))
641
        write_headers(s, bc);
Michael Niedermayer's avatar
Michael Niedermayer committed
642

643
    if(key_frame && !(nus->last_flags & FLAG_KEY))
644 645 646 647 648
        store_sp= 1;

    if(pkt->size + 30/*FIXME check*/ + url_ftell(bc) >= nut->last_syncpoint_pos + nut->max_distance)
        store_sp= 1;

Diego Biurrun's avatar
Diego Biurrun committed
649
//FIXME: Ensure store_sp is 1 in the first place.
650 651

    if(store_sp){
652
        Syncpoint *sp, dummy= {.pos= INT64_MAX};
Michael Niedermayer's avatar
Michael Niedermayer committed
653

654
        ff_nut_reset_ts(nut, *nus->time_base, pkt->dts);
Michael Niedermayer's avatar
Michael Niedermayer committed
655 656
        for(i=0; i<s->nb_streams; i++){
            AVStream *st= s->streams[i];
657 658 659 660 661
            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);
            int index= av_index_search_timestamp(st, dts_tb, AVSEEK_FLAG_BACKWARD);
662
            if(index>=0) dummy.pos= FFMIN(dummy.pos, st->index_entries[index].pos);
Michael Niedermayer's avatar
Michael Niedermayer committed
663
        }
664 665
        if(dummy.pos == INT64_MAX)
            dummy.pos= 0;
Vitor Sessak's avatar
Vitor Sessak committed
666 667
        sp= av_tree_find(nut->syncpoints, &dummy, (void *) ff_nut_sp_pos_cmp,
                         NULL);
668 669

        nut->last_syncpoint_pos= url_ftell(bc);
670 671 672
        ret = url_open_dyn_buf(&dyn_bc);
        if(ret < 0)
            return ret;
673
        put_tt(nut, nus, dyn_bc, pkt->dts);
674
        ff_put_v(dyn_bc, sp ? (nut->last_syncpoint_pos - sp->pos)>>4 : 0);
675
        put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE);
Michael Niedermayer's avatar
Michael Niedermayer committed
676 677

        ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0/*unused*/, pkt->dts);
678 679 680 681 682 683 684
    }
    assert(nus->last_pts != AV_NOPTS_VALUE);

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

685 686
    best_header_idx= find_best_header_idx(nut, pkt);

687 688 689 690 691 692 693 694 695 696 697 698 699
    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;

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

        if(flags & FLAG_CODED){
            length++;
Michael Niedermayer's avatar
Michael Niedermayer committed
700
            flags = needed_flags;
701 702 703 704 705 706 707 708 709
        }

        if((flags & needed_flags) != needed_flags)
            continue;

        if((flags ^ needed_flags) & FLAG_KEY)
            continue;

        if(flags & FLAG_STREAM_ID)
710
            length+= ff_get_v_length(pkt->stream_index);
711 712 713 714

        if(pkt->size % fc->size_mul != fc->size_lsb)
            continue;
        if(flags & FLAG_SIZE_MSB)
715
            length += ff_get_v_length(pkt->size / fc->size_mul);
716 717 718 719 720

        if(flags & FLAG_CHECKSUM)
            length+=4;

        if(flags & FLAG_CODED_PTS)
721
            length += ff_get_v_length(coded_pts);
722

723 724 725 726 727 728 729 730 731 732 733
        if(   (flags & FLAG_CODED)
           && nut->header_len[best_header_idx] > nut->header_len[fc->header_idx]+1){
            flags |= FLAG_HEADER_IDX;
        }

        if(flags & FLAG_HEADER_IDX){
            length += 1 - nut->header_len[best_header_idx];
        }else{
            length -= nut->header_len[fc->header_idx];
        }

734 735 736 737 738 739 740 741 742 743 744 745 746
        length*=4;
        length+= !(flags & FLAG_CODED_PTS);
        length+= !(flags & FLAG_CHECKSUM);

        if(length < best_length){
            best_length= length;
            frame_code=i;
        }
    }
    assert(frame_code != -1);
    fc= &nut->frame_code[frame_code];
    flags= fc->flags;
    needed_flags= get_needed_flags(nut, nus, fc, pkt);
747
    header_idx= fc->header_idx;
748

749
    init_checksum(bc, ff_crc04C11DB7_update, 0);
750 751
    put_byte(bc, frame_code);
    if(flags & FLAG_CODED){
752
        ff_put_v(bc, (flags^needed_flags) & ~(FLAG_CODED));
753 754
        flags = needed_flags;
    }
755 756 757 758
    if(flags & FLAG_STREAM_ID)  ff_put_v(bc, pkt->stream_index);
    if(flags & FLAG_CODED_PTS)  ff_put_v(bc, coded_pts);
    if(flags & FLAG_SIZE_MSB)   ff_put_v(bc, pkt->size / fc->size_mul);
    if(flags & FLAG_HEADER_IDX) ff_put_v(bc, header_idx= best_header_idx);
759 760 761 762

    if(flags & FLAG_CHECKSUM)   put_le32(bc, get_checksum(bc));
    else                        get_checksum(bc);

763
    put_buffer(bc, pkt->data + nut->header_len[header_idx], pkt->size - nut->header_len[header_idx]);
764
    nus->last_flags= flags;
765
    nus->last_pts= pkt->pts;
Michael Niedermayer's avatar
Michael Niedermayer committed
766 767 768 769 770 771 772 773 774 775 776

    //FIXME just store one per syncpoint
    if(flags & FLAG_KEY)
        av_add_index_entry(
            s->streams[pkt->stream_index],
            nut->last_syncpoint_pos,
            pkt->pts,
            0,
            0,
            AVINDEX_KEYFRAME);

777 778 779
    return 0;
}

780 781
static int write_trailer(AVFormatContext *s){
    NUTContext *nut= s->priv_data;
782
    ByteIOContext *bc= s->pb;
783

Michael Niedermayer's avatar
Michael Niedermayer committed
784
    while(nut->header_count<3)
785
        write_headers(s, bc);
786
    put_flush_packet(bc);
787
    ff_nut_free_sp(nut);
788 789
    av_freep(&nut->stream);
    av_freep(&nut->time_base);
790 791 792 793

    return 0;
}

794 795
AVOutputFormat nut_muxer = {
    "nut",
796
    NULL_IF_CONFIG_SMALL("NUT format"),
797 798 799
    "video/x-nut",
    "nut",
    sizeof(NUTContext),
800
#if   CONFIG_LIBVORBIS
801
    CODEC_ID_VORBIS,
802
#elif CONFIG_LIBMP3LAME
803 804
    CODEC_ID_MP3,
#else
805
    CODEC_ID_MP2,
806 807 808 809
#endif
    CODEC_ID_MPEG4,
    write_header,
    write_packet,
810
    write_trailer,
811
    .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS,
812
    .codec_tag = (const AVCodecTag * const []){ ff_codec_bmp_tags, ff_nut_video_tags, ff_codec_wav_tags, ff_nut_subtitle_tags, 0 },
813
    .metadata_conv = ff_nut_metadata_conv,
814
};