write frames and syncpoints
[ffmpeg.git] / libavformat / nutenc.c
index 3a97b7e..0efb223 100644 (file)
@@ -375,8 +375,120 @@ static int write_header(AVFormatContext *s){
     return 0;
 }
 
+static int get_needed_flags(NUTContext *nut, StreamContext *nus, FrameCode *fc, AVPacket *pkt){
+    int flags= 0;
+
+    if(pkt->flags & PKT_FLAG_KEY                ) flags |= FLAG_KEY;
+    if(pkt->stream_index != fc->stream_id       ) flags |= FLAG_STREAM_ID;
+    if(pkt->size / fc->size_mul                 ) flags |= FLAG_SIZE_MSB;
+    if(pkt->pts - nus->last_pts != fc->pts_delta) flags |= FLAG_CODED_PTS;
+    if(pkt->size > 2*nut->max_distance          ) flags |= FLAG_CHECKSUM;
+    if(FFABS(pkt->pts - nus->last_pts)
+                         > nus->max_pts_distance) flags |= FLAG_CHECKSUM;
+
+    return flags;
+}
+
 static int write_packet(AVFormatContext *s, AVPacket *pkt){
-    //FIXME
+    NUTContext *nut = s->priv_data;
+    StreamContext *nus= &nut->stream[pkt->stream_index];
+    ByteIOContext *bc = &s->pb, dyn_bc;
+    FrameCode *fc;
+    int64_t coded_pts;
+    int best_length, frame_code, flags, needed_flags, i;
+    int key_frame = !!(pkt->flags & PKT_FLAG_KEY);
+    int store_sp=0;
+
+    if(key_frame && !!(nus->last_flags & FLAG_KEY))
+        store_sp= 1;
+
+    if(pkt->size + 30/*FIXME check*/ + url_ftell(bc) >= nut->last_syncpoint_pos + nut->max_distance)
+        store_sp= 1;
+
+//FIXME ensure store_sp is 1 for the first thing
+
+    if(store_sp){
+        ff_nut_reset_ts(nut, *nus->time_base, pkt->dts);
+
+        nut->last_syncpoint_pos= url_ftell(bc);
+        put_be64(bc, SYNCPOINT_STARTCODE);
+        url_open_dyn_buf(&dyn_bc);
+        put_t(nut, nus, &dyn_bc, pkt->dts);
+        put_v(&dyn_bc, 0); //FIXME back_ptr_div16
+        put_packet(nut, bc, &dyn_bc, 1);
+    }
+    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);
+
+    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++;
+            flags &= ~needed_flags;
+            flags |=  needed_flags;
+        }
+
+        if((flags & needed_flags) != needed_flags)
+            continue;
+
+        if((flags ^ needed_flags) & FLAG_KEY)
+            continue;
+
+        if(flags & FLAG_STREAM_ID)
+            length+= get_length(pkt->stream_index);
+
+        if(pkt->size % fc->size_mul != fc->size_lsb)
+            continue;
+        if(flags & FLAG_SIZE_MSB)
+            length += get_length(pkt->size / fc->size_mul);
+
+        if(flags & FLAG_CHECKSUM)
+            length+=4;
+
+        if(flags & FLAG_CODED_PTS)
+            length += get_length(coded_pts);
+
+        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);
+
+    init_checksum(bc, av_crc04C11DB7_update, 0);
+    put_byte(bc, frame_code);
+    if(flags & FLAG_CODED){
+        put_v(bc, (flags^needed_flags) & ~(FLAG_CODED));
+        flags = needed_flags;
+    }
+    if(flags & FLAG_STREAM_ID)  put_v(bc, pkt->stream_index);
+    if(flags & FLAG_CODED_PTS)  put_v(bc, coded_pts);
+    if(flags & FLAG_SIZE_MSB)   put_v(bc, pkt->size / fc->size_mul);
+
+    if(flags & FLAG_CHECKSUM)   put_le32(bc, get_checksum(bc));
+    else                        get_checksum(bc);
+
+    put_buffer(bc, pkt->data, pkt->size);
+    nus->last_flags= flags;
     return 0;
 }