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
00026 int ff_mov_init_hinting(AVFormatContext *s, int index, int src_index)
00027 {
00028 MOVMuxContext *mov = s->priv_data;
00029 MOVTrack *track = &mov->tracks[index];
00030 MOVTrack *src_track = &mov->tracks[src_index];
00031 AVStream *src_st = s->streams[src_index];
00032 int ret = AVERROR(ENOMEM);
00033 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
00034
00035 track->tag = MKTAG('r','t','p',' ');
00036 track->src_track = src_index;
00037
00038 if (!rtp_format) {
00039 ret = AVERROR(ENOENT);
00040 goto fail;
00041 }
00042
00043 track->enc = avcodec_alloc_context();
00044 if (!track->enc)
00045 goto fail;
00046 track->enc->codec_type = AVMEDIA_TYPE_DATA;
00047 track->enc->codec_tag = track->tag;
00048
00049 track->rtp_ctx = avformat_alloc_context();
00050 if (!track->rtp_ctx)
00051 goto fail;
00052 track->rtp_ctx->oformat = rtp_format;
00053 if (!av_new_stream(track->rtp_ctx, 0))
00054 goto fail;
00055
00056
00057 track->rtp_ctx->streams[0]->sample_aspect_ratio =
00058 src_st->sample_aspect_ratio;
00059
00060
00061
00062 av_free(track->rtp_ctx->streams[0]->codec);
00063 track->rtp_ctx->streams[0]->codec = src_st->codec;
00064
00065 if ((ret = url_open_dyn_packet_buf(&track->rtp_ctx->pb,
00066 RTP_MAX_PACKET_SIZE)) < 0)
00067 goto fail;
00068 ret = av_write_header(track->rtp_ctx);
00069 if (ret)
00070 goto fail;
00071
00072
00073 track->timescale = track->rtp_ctx->streams[0]->time_base.den;
00074
00075
00076
00077 src_track->hint_track = index;
00078 return 0;
00079 fail:
00080 av_log(s, AV_LOG_WARNING,
00081 "Unable to initialize hinting of stream %d\n", src_index);
00082 if (track->rtp_ctx && track->rtp_ctx->pb) {
00083 uint8_t *buf;
00084 url_close_dyn_buf(track->rtp_ctx->pb, &buf);
00085 av_free(buf);
00086 }
00087 if (track->rtp_ctx && track->rtp_ctx->streams[0]) {
00088 av_metadata_free(&track->rtp_ctx->streams[0]->metadata);
00089 av_free(track->rtp_ctx->streams[0]);
00090 }
00091 if (track->rtp_ctx) {
00092 av_metadata_free(&track->rtp_ctx->metadata);
00093 av_free(track->rtp_ctx->priv_data);
00094 av_freep(&track->rtp_ctx);
00095 }
00096 av_freep(&track->enc);
00097
00098 track->timescale = 90000;
00099 return ret;
00100 }
00101
00105 static void sample_queue_pop(HintSampleQueue *queue)
00106 {
00107 if (queue->len <= 0)
00108 return;
00109 if (queue->samples[0].own_data)
00110 av_free(queue->samples[0].data);
00111 queue->len--;
00112 memmove(queue->samples, queue->samples + 1, sizeof(HintSample)*queue->len);
00113 }
00114
00118 static void sample_queue_free(HintSampleQueue *queue)
00119 {
00120 int i;
00121 for (i = 0; i < queue->len; i++)
00122 if (queue->samples[i].own_data)
00123 av_free(queue->samples[i].data);
00124 av_freep(&queue->samples);
00125 queue->len = 0;
00126 queue->size = 0;
00127 }
00128
00134 static void sample_queue_push(HintSampleQueue *queue, AVPacket *pkt, int sample)
00135 {
00136
00137
00138 if (pkt->size <= 14)
00139 return;
00140 if (!queue->samples || queue->len >= queue->size) {
00141 HintSample* samples;
00142 queue->size += 10;
00143 samples = av_realloc(queue->samples, sizeof(HintSample)*queue->size);
00144 if (!samples)
00145 return;
00146 queue->samples = samples;
00147 }
00148 queue->samples[queue->len].data = pkt->data;
00149 queue->samples[queue->len].size = pkt->size;
00150 queue->samples[queue->len].sample_number = sample;
00151 queue->samples[queue->len].offset = 0;
00152 queue->samples[queue->len].own_data = 0;
00153 queue->len++;
00154 }
00155
00159 static void sample_queue_retain(HintSampleQueue *queue)
00160 {
00161 int i;
00162 for (i = 0; i < queue->len; ) {
00163 HintSample *sample = &queue->samples[i];
00164 if (!sample->own_data) {
00165 uint8_t* ptr = av_malloc(sample->size);
00166 if (!ptr) {
00167
00168 memmove(queue->samples + i, queue->samples + i + 1,
00169 sizeof(HintSample)*(queue->len - i - 1));
00170 queue->len--;
00171 continue;
00172 }
00173 memcpy(ptr, sample->data, sample->size);
00174 sample->data = ptr;
00175 sample->own_data = 1;
00176 }
00177 i++;
00178 }
00179 }
00180
00197 static int match_segments(const uint8_t *haystack, int h_len,
00198 const uint8_t *needle, int n_pos, int n_len,
00199 int *match_h_offset_ptr, int *match_n_offset_ptr,
00200 int *match_len_ptr)
00201 {
00202 int h_pos;
00203 for (h_pos = 0; h_pos < h_len; h_pos++) {
00204 int match_len = 0;
00205 int match_h_pos, match_n_pos;
00206
00207
00208 while (h_pos + match_len < h_len && n_pos + match_len < n_len &&
00209 needle[n_pos + match_len] == haystack[h_pos + match_len])
00210 match_len++;
00211 if (match_len <= 8)
00212 continue;
00213
00214
00215
00216 match_h_pos = h_pos;
00217 match_n_pos = n_pos;
00218 while (match_n_pos > 0 && match_h_pos > 0 &&
00219 needle[match_n_pos - 1] == haystack[match_h_pos - 1]) {
00220 match_n_pos--;
00221 match_h_pos--;
00222 match_len++;
00223 }
00224 if (match_len <= 14)
00225 continue;
00226 *match_h_offset_ptr = match_h_pos;
00227 *match_n_offset_ptr = match_n_pos;
00228 *match_len_ptr = match_len;
00229 return 0;
00230 }
00231 return -1;
00232 }
00233
00249 static int find_sample_match(const uint8_t *data, int len,
00250 HintSampleQueue *queue, int *pos,
00251 int *match_sample, int *match_offset,
00252 int *match_len)
00253 {
00254 while (queue->len > 0) {
00255 HintSample *sample = &queue->samples[0];
00256
00257
00258 if (sample->offset == 0 && sample->size > 5)
00259 sample->offset = 5;
00260
00261 if (match_segments(data, len, sample->data, sample->offset,
00262 sample->size, pos, match_offset, match_len) == 0) {
00263 *match_sample = sample->sample_number;
00264
00265
00266 sample->offset = *match_offset + *match_len + 5;
00267 if (sample->offset + 10 >= sample->size)
00268 sample_queue_pop(queue);
00269 return 0;
00270 }
00271
00272 if (sample->offset < 10 && sample->size > 20) {
00273
00274
00275 sample->offset = sample->size/2;
00276 } else {
00277
00278 sample_queue_pop(queue);
00279 }
00280 }
00281 return -1;
00282 }
00283
00284 static void output_immediate(const uint8_t *data, int size,
00285 ByteIOContext *out, int *entries)
00286 {
00287 while (size > 0) {
00288 int len = size;
00289 if (len > 14)
00290 len = 14;
00291 put_byte(out, 1);
00292 put_byte(out, len);
00293 put_buffer(out, data, len);
00294 data += len;
00295 size -= len;
00296
00297 for (; len < 14; len++)
00298 put_byte(out, 0);
00299
00300 (*entries)++;
00301 }
00302 }
00303
00304 static void output_match(ByteIOContext *out, int match_sample,
00305 int match_offset, int match_len, int *entries)
00306 {
00307 put_byte(out, 2);
00308 put_byte(out, 0);
00309 put_be16(out, match_len);
00310 put_be32(out, match_sample);
00311 put_be32(out, match_offset);
00312 put_be16(out, 1);
00313 put_be16(out, 1);
00314 (*entries)++;
00315 }
00316
00317 static void describe_payload(const uint8_t *data, int size,
00318 ByteIOContext *out, int *entries,
00319 HintSampleQueue *queue)
00320 {
00321
00322 while (size > 0) {
00323 int match_sample, match_offset, match_len, pos;
00324 if (find_sample_match(data, size, queue, &pos, &match_sample,
00325 &match_offset, &match_len) < 0)
00326 break;
00327 output_immediate(data, pos, out, entries);
00328 data += pos;
00329 size -= pos;
00330 output_match(out, match_sample, match_offset, match_len, entries);
00331 data += match_len;
00332 size -= match_len;
00333 }
00334 output_immediate(data, size, out, entries);
00335 }
00336
00349 static int write_hint_packets(ByteIOContext *out, const uint8_t *data,
00350 int size, MOVTrack *trk, int64_t *pts)
00351 {
00352 int64_t curpos;
00353 int64_t count_pos, entries_pos;
00354 int count = 0, entries;
00355
00356 count_pos = url_ftell(out);
00357
00358 put_be16(out, 0);
00359 put_be16(out, 0);
00360
00361 while (size > 4) {
00362 uint32_t packet_len = AV_RB32(data);
00363 uint16_t seq;
00364 uint32_t ts;
00365
00366 data += 4;
00367 size -= 4;
00368 if (packet_len > size || packet_len <= 12)
00369 break;
00370 if (data[1] >= 200 && data[1] <= 204) {
00371
00372 data += packet_len;
00373 size -= packet_len;
00374 continue;
00375 }
00376
00377 if (packet_len > trk->max_packet_size)
00378 trk->max_packet_size = packet_len;
00379
00380 seq = AV_RB16(&data[2]);
00381 ts = AV_RB32(&data[4]);
00382
00383 if (trk->prev_rtp_ts == 0)
00384 trk->prev_rtp_ts = ts;
00385
00386
00387 trk->cur_rtp_ts_unwrapped += (int32_t) (ts - trk->prev_rtp_ts);
00388 trk->prev_rtp_ts = ts;
00389 if (*pts == AV_NOPTS_VALUE)
00390 *pts = trk->cur_rtp_ts_unwrapped;
00391
00392 count++;
00393
00394 put_be32(out, 0);
00395 put_buffer(out, data, 2);
00396 put_be16(out, seq);
00397 put_be16(out, 0);
00398 entries_pos = url_ftell(out);
00399 put_be16(out, 0);
00400
00401 data += 12;
00402 size -= 12;
00403 packet_len -= 12;
00404
00405 entries = 0;
00406
00407 describe_payload(data, packet_len, out, &entries, &trk->sample_queue);
00408 data += packet_len;
00409 size -= packet_len;
00410
00411 curpos = url_ftell(out);
00412 url_fseek(out, entries_pos, SEEK_SET);
00413 put_be16(out, entries);
00414 url_fseek(out, curpos, SEEK_SET);
00415 }
00416
00417 curpos = url_ftell(out);
00418 url_fseek(out, count_pos, SEEK_SET);
00419 put_be16(out, count);
00420 url_fseek(out, curpos, SEEK_SET);
00421 return count;
00422 }
00423
00424 int ff_mov_add_hinted_packet(AVFormatContext *s, AVPacket *pkt,
00425 int track_index, int sample)
00426 {
00427 MOVMuxContext *mov = s->priv_data;
00428 MOVTrack *trk = &mov->tracks[track_index];
00429 AVFormatContext *rtp_ctx = trk->rtp_ctx;
00430 uint8_t *buf = NULL;
00431 int size;
00432 ByteIOContext *hintbuf = NULL;
00433 AVPacket hint_pkt;
00434 int ret = 0, count;
00435
00436 if (!rtp_ctx)
00437 return AVERROR(ENOENT);
00438 if (!rtp_ctx->pb)
00439 return AVERROR(ENOMEM);
00440
00441 sample_queue_push(&trk->sample_queue, pkt, sample);
00442
00443
00444 ff_write_chained(rtp_ctx, 0, pkt, s);
00445
00446
00447
00448 size = url_close_dyn_buf(rtp_ctx->pb, &buf);
00449 if ((ret = url_open_dyn_packet_buf(&rtp_ctx->pb,
00450 RTP_MAX_PACKET_SIZE)) < 0)
00451 goto done;
00452
00453 if (size <= 0)
00454 goto done;
00455
00456
00457 if ((ret = url_open_dyn_buf(&hintbuf)) < 0)
00458 goto done;
00459 av_init_packet(&hint_pkt);
00460 count = write_hint_packets(hintbuf, buf, size, trk, &hint_pkt.dts);
00461 av_freep(&buf);
00462
00463
00464 hint_pkt.size = size = url_close_dyn_buf(hintbuf, &buf);
00465 hint_pkt.data = buf;
00466 hint_pkt.pts = hint_pkt.dts;
00467 hint_pkt.stream_index = track_index;
00468 if (pkt->flags & AV_PKT_FLAG_KEY)
00469 hint_pkt.flags |= AV_PKT_FLAG_KEY;
00470 if (count > 0)
00471 ff_mov_write_packet(s, &hint_pkt);
00472 done:
00473 av_free(buf);
00474 sample_queue_retain(&trk->sample_queue);
00475 return ret;
00476 }
00477
00478 void ff_mov_close_hinting(MOVTrack *track) {
00479 AVFormatContext* rtp_ctx = track->rtp_ctx;
00480 uint8_t *ptr;
00481
00482 av_freep(&track->enc);
00483 sample_queue_free(&track->sample_queue);
00484 if (!rtp_ctx)
00485 return;
00486 if (rtp_ctx->pb) {
00487 av_write_trailer(rtp_ctx);
00488 url_close_dyn_buf(rtp_ctx->pb, &ptr);
00489 av_free(ptr);
00490 }
00491 av_metadata_free(&rtp_ctx->streams[0]->metadata);
00492 av_metadata_free(&rtp_ctx->metadata);
00493 av_free(rtp_ctx->streams[0]);
00494 av_freep(&rtp_ctx);
00495 }
00496