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