00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 #include "movenc.h"
00023 #include "libavutil/intreadwrite.h"
00024 #include "internal.h"
00025 #include "rtpenc_chain.h"
00026 #include "avio_internal.h"
00027 #include "rtp.h"
00028 
00029 int ff_mov_init_hinting(AVFormatContext *s, int index, int src_index)
00030 {
00031     MOVMuxContext *mov  = s->priv_data;
00032     MOVTrack *track     = &mov->tracks[index];
00033     MOVTrack *src_track = &mov->tracks[src_index];
00034     AVStream *src_st    = s->streams[src_index];
00035     int ret = AVERROR(ENOMEM);
00036 
00037     track->tag = MKTAG('r','t','p',' ');
00038     track->src_track = src_index;
00039 
00040     track->enc = avcodec_alloc_context3(NULL);
00041     if (!track->enc)
00042         goto fail;
00043     track->enc->codec_type = AVMEDIA_TYPE_DATA;
00044     track->enc->codec_tag  = track->tag;
00045 
00046     ret = ff_rtp_chain_mux_open(&track->rtp_ctx, s, src_st, NULL,
00047                                 RTP_MAX_PACKET_SIZE);
00048     if (ret < 0)
00049         goto fail;
00050 
00051     
00052     track->timescale = track->rtp_ctx->streams[0]->time_base.den;
00053 
00054     
00055 
00056     src_track->hint_track = index;
00057     return 0;
00058 fail:
00059     av_log(s, AV_LOG_WARNING,
00060            "Unable to initialize hinting of stream %d\n", src_index);
00061     av_freep(&track->enc);
00062     
00063     track->timescale = 90000;
00064     return ret;
00065 }
00066 
00070 static void sample_queue_pop(HintSampleQueue *queue)
00071 {
00072     if (queue->len <= 0)
00073         return;
00074     if (queue->samples[0].own_data)
00075         av_free(queue->samples[0].data);
00076     queue->len--;
00077     memmove(queue->samples, queue->samples + 1, sizeof(HintSample)*queue->len);
00078 }
00079 
00083 static void sample_queue_free(HintSampleQueue *queue)
00084 {
00085     int i;
00086     for (i = 0; i < queue->len; i++)
00087         if (queue->samples[i].own_data)
00088             av_free(queue->samples[i].data);
00089     av_freep(&queue->samples);
00090     queue->len = 0;
00091     queue->size = 0;
00092 }
00093 
00099 static void sample_queue_push(HintSampleQueue *queue, uint8_t *data, int size,
00100                               int sample)
00101 {
00102     
00103 
00104     if (size <= 14)
00105         return;
00106     if (!queue->samples || queue->len >= queue->size) {
00107         HintSample* samples;
00108         queue->size += 10;
00109         samples = av_realloc(queue->samples, sizeof(HintSample)*queue->size);
00110         if (!samples)
00111             return;
00112         queue->samples = samples;
00113     }
00114     queue->samples[queue->len].data = data;
00115     queue->samples[queue->len].size = size;
00116     queue->samples[queue->len].sample_number = sample;
00117     queue->samples[queue->len].offset = 0;
00118     queue->samples[queue->len].own_data = 0;
00119     queue->len++;
00120 }
00121 
00125 static void sample_queue_retain(HintSampleQueue *queue)
00126 {
00127     int i;
00128     for (i = 0; i < queue->len; ) {
00129         HintSample *sample = &queue->samples[i];
00130         if (!sample->own_data) {
00131             uint8_t* ptr = av_malloc(sample->size);
00132             if (!ptr) {
00133                 
00134                 memmove(queue->samples + i, queue->samples + i + 1,
00135                         sizeof(HintSample)*(queue->len - i - 1));
00136                 queue->len--;
00137                 continue;
00138             }
00139             memcpy(ptr, sample->data, sample->size);
00140             sample->data = ptr;
00141             sample->own_data = 1;
00142         }
00143         i++;
00144     }
00145 }
00146 
00163 static int match_segments(const uint8_t *haystack, int h_len,
00164                           const uint8_t *needle, int n_pos, int n_len,
00165                           int *match_h_offset_ptr, int *match_n_offset_ptr,
00166                           int *match_len_ptr)
00167 {
00168     int h_pos;
00169     for (h_pos = 0; h_pos < h_len; h_pos++) {
00170         int match_len = 0;
00171         int match_h_pos, match_n_pos;
00172 
00173         
00174         while (h_pos + match_len < h_len && n_pos + match_len < n_len &&
00175                needle[n_pos + match_len] == haystack[h_pos + match_len])
00176             match_len++;
00177         if (match_len <= 8)
00178             continue;
00179 
00180         
00181 
00182         match_h_pos = h_pos;
00183         match_n_pos = n_pos;
00184         while (match_n_pos > 0 && match_h_pos > 0 &&
00185                needle[match_n_pos - 1] == haystack[match_h_pos - 1]) {
00186             match_n_pos--;
00187             match_h_pos--;
00188             match_len++;
00189         }
00190         if (match_len <= 14)
00191             continue;
00192         *match_h_offset_ptr = match_h_pos;
00193         *match_n_offset_ptr = match_n_pos;
00194         *match_len_ptr = match_len;
00195         return 0;
00196     }
00197     return -1;
00198 }
00199 
00215 static int find_sample_match(const uint8_t *data, int len,
00216                              HintSampleQueue *queue, int *pos,
00217                              int *match_sample, int *match_offset,
00218                              int *match_len)
00219 {
00220     while (queue->len > 0) {
00221         HintSample *sample = &queue->samples[0];
00222         
00223 
00224         if (sample->offset == 0 && sample->size > 5)
00225             sample->offset = 5;
00226 
00227         if (match_segments(data, len, sample->data, sample->offset,
00228                            sample->size, pos, match_offset, match_len) == 0) {
00229             *match_sample = sample->sample_number;
00230             
00231 
00232             sample->offset = *match_offset + *match_len + 5;
00233             if (sample->offset + 10 >= sample->size)
00234                 sample_queue_pop(queue); 
00235             return 0;
00236         }
00237 
00238         if (sample->offset < 10 && sample->size > 20) {
00239             
00240 
00241             sample->offset = sample->size/2;
00242         } else {
00243             
00244             sample_queue_pop(queue);
00245         }
00246     }
00247     return -1;
00248 }
00249 
00250 static void output_immediate(const uint8_t *data, int size,
00251                              AVIOContext *out, int *entries)
00252 {
00253     while (size > 0) {
00254         int len = size;
00255         if (len > 14)
00256             len = 14;
00257         avio_w8(out, 1); 
00258         avio_w8(out, len); 
00259         avio_write(out, data, len);
00260         data += len;
00261         size -= len;
00262 
00263         for (; len < 14; len++)
00264             avio_w8(out, 0);
00265 
00266         (*entries)++;
00267     }
00268 }
00269 
00270 static void output_match(AVIOContext *out, int match_sample,
00271                          int match_offset, int match_len, int *entries)
00272 {
00273     avio_w8(out, 2); 
00274     avio_w8(out, 0); 
00275     avio_wb16(out, match_len);
00276     avio_wb32(out, match_sample);
00277     avio_wb32(out, match_offset);
00278     avio_wb16(out, 1); 
00279     avio_wb16(out, 1); 
00280     (*entries)++;
00281 }
00282 
00283 static void describe_payload(const uint8_t *data, int size,
00284                              AVIOContext *out, int *entries,
00285                              HintSampleQueue *queue)
00286 {
00287     
00288     while (size > 0) {
00289         int match_sample, match_offset, match_len, pos;
00290         if (find_sample_match(data, size, queue, &pos, &match_sample,
00291                               &match_offset, &match_len) < 0)
00292             break;
00293         output_immediate(data, pos, out, entries);
00294         data += pos;
00295         size -= pos;
00296         output_match(out, match_sample, match_offset, match_len, entries);
00297         data += match_len;
00298         size -= match_len;
00299     }
00300     output_immediate(data, size, out, entries);
00301 }
00302 
00315 static int write_hint_packets(AVIOContext *out, const uint8_t *data,
00316                               int size, MOVTrack *trk, int64_t *pts)
00317 {
00318     int64_t curpos;
00319     int64_t count_pos, entries_pos;
00320     int count = 0, entries;
00321 
00322     count_pos = avio_tell(out);
00323     
00324     avio_wb16(out, 0); 
00325     avio_wb16(out, 0); 
00326 
00327     while (size > 4) {
00328         uint32_t packet_len = AV_RB32(data);
00329         uint16_t seq;
00330         uint32_t ts;
00331 
00332         data += 4;
00333         size -= 4;
00334         if (packet_len > size || packet_len <= 12)
00335             break;
00336         if (RTP_PT_IS_RTCP(data[1])) {
00337             
00338             data += packet_len;
00339             size -= packet_len;
00340             continue;
00341         }
00342 
00343         if (packet_len > trk->max_packet_size)
00344             trk->max_packet_size = packet_len;
00345 
00346         seq = AV_RB16(&data[2]);
00347         ts = AV_RB32(&data[4]);
00348 
00349         if (trk->prev_rtp_ts == 0)
00350             trk->prev_rtp_ts = ts;
00351         
00352 
00353         trk->cur_rtp_ts_unwrapped += (int32_t) (ts - trk->prev_rtp_ts);
00354         trk->prev_rtp_ts = ts;
00355         if (*pts == AV_NOPTS_VALUE)
00356             *pts = trk->cur_rtp_ts_unwrapped;
00357 
00358         count++;
00359         
00360         avio_wb32(out, 0); 
00361         avio_write(out, data, 2); 
00362         avio_wb16(out, seq); 
00363         avio_wb16(out, 0); 
00364         entries_pos = avio_tell(out);
00365         avio_wb16(out, 0); 
00366 
00367         data += 12;
00368         size -= 12;
00369         packet_len -= 12;
00370 
00371         entries = 0;
00372         
00373         describe_payload(data, packet_len, out, &entries, &trk->sample_queue);
00374         data += packet_len;
00375         size -= packet_len;
00376 
00377         curpos = avio_tell(out);
00378         avio_seek(out, entries_pos, SEEK_SET);
00379         avio_wb16(out, entries);
00380         avio_seek(out, curpos, SEEK_SET);
00381     }
00382 
00383     curpos = avio_tell(out);
00384     avio_seek(out, count_pos, SEEK_SET);
00385     avio_wb16(out, count);
00386     avio_seek(out, curpos, SEEK_SET);
00387     return count;
00388 }
00389 
00390 int ff_mov_add_hinted_packet(AVFormatContext *s, AVPacket *pkt,
00391                              int track_index, int sample,
00392                              uint8_t *sample_data, int sample_size)
00393 {
00394     MOVMuxContext *mov = s->priv_data;
00395     MOVTrack *trk = &mov->tracks[track_index];
00396     AVFormatContext *rtp_ctx = trk->rtp_ctx;
00397     uint8_t *buf = NULL;
00398     int size;
00399     AVIOContext *hintbuf = NULL;
00400     AVPacket hint_pkt;
00401     int ret = 0, count;
00402 
00403     if (!rtp_ctx)
00404         return AVERROR(ENOENT);
00405     if (!rtp_ctx->pb)
00406         return AVERROR(ENOMEM);
00407 
00408     if (sample_data)
00409         sample_queue_push(&trk->sample_queue, sample_data, sample_size, sample);
00410     else
00411         sample_queue_push(&trk->sample_queue, pkt->data, pkt->size, sample);
00412 
00413     
00414     ff_write_chained(rtp_ctx, 0, pkt, s);
00415 
00416     
00417 
00418     size = avio_close_dyn_buf(rtp_ctx->pb, &buf);
00419     if ((ret = ffio_open_dyn_packet_buf(&rtp_ctx->pb,
00420                                        RTP_MAX_PACKET_SIZE)) < 0)
00421         goto done;
00422 
00423     if (size <= 0)
00424         goto done;
00425 
00426     
00427     if ((ret = avio_open_dyn_buf(&hintbuf)) < 0)
00428         goto done;
00429     av_init_packet(&hint_pkt);
00430     count = write_hint_packets(hintbuf, buf, size, trk, &hint_pkt.dts);
00431     av_freep(&buf);
00432 
00433     
00434     hint_pkt.size = size = avio_close_dyn_buf(hintbuf, &buf);
00435     hint_pkt.data = buf;
00436     hint_pkt.pts  = hint_pkt.dts;
00437     hint_pkt.stream_index = track_index;
00438     if (pkt->flags & AV_PKT_FLAG_KEY)
00439         hint_pkt.flags |= AV_PKT_FLAG_KEY;
00440     if (count > 0)
00441         ff_mov_write_packet(s, &hint_pkt);
00442 done:
00443     av_free(buf);
00444     sample_queue_retain(&trk->sample_queue);
00445     return ret;
00446 }
00447 
00448 void ff_mov_close_hinting(MOVTrack *track) {
00449     AVFormatContext* rtp_ctx = track->rtp_ctx;
00450     uint8_t *ptr;
00451 
00452     av_freep(&track->enc);
00453     sample_queue_free(&track->sample_queue);
00454     if (!rtp_ctx)
00455         return;
00456     if (rtp_ctx->pb) {
00457         av_write_trailer(rtp_ctx);
00458         avio_close_dyn_buf(rtp_ctx->pb, &ptr);
00459         av_free(ptr);
00460     }
00461     avformat_free_context(rtp_ctx);
00462 }