1/* 2 * MOV, 3GP, MP4 muxer RTP hinting 3 * Copyright (c) 2010 Martin Storsjo 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include "movenc.h" 23#include "libavutil/intreadwrite.h" 24#include "mux.h" 25#include "rtpenc_chain.h" 26#include "avio_internal.h" 27#include "rtp.h" 28 29int ff_mov_init_hinting(AVFormatContext *s, int index, int src_index) 30{ 31 MOVMuxContext *mov = s->priv_data; 32 MOVTrack *track = &mov->tracks[index]; 33 MOVTrack *src_track = &mov->tracks[src_index]; 34 AVStream *src_st = s->streams[src_index]; 35 int ret = AVERROR(ENOMEM); 36 37 track->tag = MKTAG('r','t','p',' '); 38 track->src_track = src_index; 39 40 track->par = avcodec_parameters_alloc(); 41 if (!track->par) 42 goto fail; 43 track->par->codec_type = AVMEDIA_TYPE_DATA; 44 track->par->codec_tag = track->tag; 45 46 ret = ff_rtp_chain_mux_open(&track->rtp_ctx, s, src_st, NULL, 47 RTP_MAX_PACKET_SIZE, src_index); 48 if (ret < 0) 49 goto fail; 50 51 /* Copy the RTP AVStream timebase back to the hint AVStream */ 52 track->timescale = track->rtp_ctx->streams[0]->time_base.den; 53 54 /* Mark the hinted track that packets written to it should be 55 * sent to this track for hinting. */ 56 src_track->hint_track = index; 57 return 0; 58fail: 59 av_log(s, AV_LOG_WARNING, 60 "Unable to initialize hinting of stream %d\n", src_index); 61 avcodec_parameters_free(&track->par); 62 /* Set a default timescale, to avoid crashes in av_dump_format */ 63 track->timescale = 90000; 64 return ret; 65} 66 67/** 68 * Remove the first sample from the sample queue. 69 */ 70static void sample_queue_pop(HintSampleQueue *queue) 71{ 72 if (queue->len <= 0) 73 return; 74 if (queue->samples[0].own_data) 75 av_freep(&queue->samples[0].data); 76 queue->len--; 77 memmove(queue->samples, queue->samples + 1, sizeof(HintSample)*queue->len); 78} 79 80/** 81 * Empty the sample queue, releasing all memory. 82 */ 83static void sample_queue_free(HintSampleQueue *queue) 84{ 85 int i; 86 for (i = 0; i < queue->len; i++) 87 if (queue->samples[i].own_data) 88 av_freep(&queue->samples[i].data); 89 av_freep(&queue->samples); 90 queue->len = 0; 91 queue->size = 0; 92} 93 94/** 95 * Add a reference to the sample data to the sample queue. The data is 96 * not copied. sample_queue_retain should be called before pkt->data 97 * is reused/freed. 98 */ 99static void sample_queue_push(HintSampleQueue *queue, const uint8_t *data, int size, 100 int sample) 101{ 102 /* No need to keep track of smaller samples, since describing them 103 * with immediates is more efficient. */ 104 if (size <= 14) 105 return; 106 if (!queue->samples || queue->len >= queue->size) { 107 HintSample *samples; 108 samples = av_realloc_array(queue->samples, queue->size + 10, sizeof(HintSample)); 109 if (!samples) 110 return; 111 queue->size += 10; 112 queue->samples = samples; 113 } 114 queue->samples[queue->len].data = data; 115 queue->samples[queue->len].size = size; 116 queue->samples[queue->len].sample_number = sample; 117 queue->samples[queue->len].offset = 0; 118 queue->samples[queue->len].own_data = 0; 119 queue->len++; 120} 121 122/** 123 * Make local copies of all referenced sample data in the queue. 124 */ 125static void sample_queue_retain(HintSampleQueue *queue) 126{ 127 int i; 128 for (i = 0; i < queue->len; ) { 129 HintSample *sample = &queue->samples[i]; 130 if (!sample->own_data) { 131 uint8_t *ptr = av_malloc(sample->size); 132 if (!ptr) { 133 /* Unable to allocate memory for this one, remove it */ 134 memmove(queue->samples + i, queue->samples + i + 1, 135 sizeof(HintSample)*(queue->len - i - 1)); 136 queue->len--; 137 continue; 138 } 139 memcpy(ptr, sample->data, sample->size); 140 sample->data = ptr; 141 sample->own_data = 1; 142 } 143 i++; 144 } 145} 146 147/** 148 * Find matches of needle[n_pos ->] within haystack. If a sufficiently 149 * large match is found, matching bytes before n_pos are included 150 * in the match, too (within the limits of the arrays). 151 * 152 * @param haystack buffer that may contain parts of needle 153 * @param h_len length of the haystack buffer 154 * @param needle buffer containing source data that have been used to 155 * construct haystack 156 * @param n_pos start position in needle used for looking for matches 157 * @param n_len length of the needle buffer 158 * @param match_h_offset_ptr offset of the first matching byte within haystack 159 * @param match_n_offset_ptr offset of the first matching byte within needle 160 * @param match_len_ptr length of the matched segment 161 * @return 0 if a match was found, < 0 if no match was found 162 */ 163static int match_segments(const uint8_t *haystack, int h_len, 164 const uint8_t *needle, int n_pos, int n_len, 165 int *match_h_offset_ptr, int *match_n_offset_ptr, 166 int *match_len_ptr) 167{ 168 int h_pos; 169 for (h_pos = 0; h_pos < h_len; h_pos++) { 170 int match_len = 0; 171 int match_h_pos, match_n_pos; 172 173 /* Check how many bytes match at needle[n_pos] and haystack[h_pos] */ 174 while (h_pos + match_len < h_len && n_pos + match_len < n_len && 175 needle[n_pos + match_len] == haystack[h_pos + match_len]) 176 match_len++; 177 if (match_len <= 8) 178 continue; 179 180 /* If a sufficiently large match was found, try to expand 181 * the matched segment backwards. */ 182 match_h_pos = h_pos; 183 match_n_pos = n_pos; 184 while (match_n_pos > 0 && match_h_pos > 0 && 185 needle[match_n_pos - 1] == haystack[match_h_pos - 1]) { 186 match_n_pos--; 187 match_h_pos--; 188 match_len++; 189 } 190 if (match_len <= 14) 191 continue; 192 *match_h_offset_ptr = match_h_pos; 193 *match_n_offset_ptr = match_n_pos; 194 *match_len_ptr = match_len; 195 return 0; 196 } 197 return -1; 198} 199 200/** 201 * Look for segments in samples in the sample queue matching the data 202 * in ptr. Samples not matching are removed from the queue. If a match 203 * is found, the next time it will look for matches starting from the 204 * end of the previous matched segment. 205 * 206 * @param data data to find matches for in the sample queue 207 * @param len length of the data buffer 208 * @param queue samples used for looking for matching segments 209 * @param pos the offset in data of the matched segment 210 * @param match_sample the number of the sample that contained the match 211 * @param match_offset the offset of the matched segment within the sample 212 * @param match_len the length of the matched segment 213 * @return 0 if a match was found, < 0 if no match was found 214 */ 215static int find_sample_match(const uint8_t *data, int len, 216 HintSampleQueue *queue, int *pos, 217 int *match_sample, int *match_offset, 218 int *match_len) 219{ 220 while (queue->len > 0) { 221 HintSample *sample = &queue->samples[0]; 222 /* If looking for matches in a new sample, skip the first 5 bytes, 223 * since they often may be modified/removed in the output packet. */ 224 if (sample->offset == 0 && sample->size > 5) 225 sample->offset = 5; 226 227 if (match_segments(data, len, sample->data, sample->offset, 228 sample->size, pos, match_offset, match_len) == 0) { 229 *match_sample = sample->sample_number; 230 /* Next time, look for matches at this offset, with a little 231 * margin to this match. */ 232 sample->offset = *match_offset + *match_len + 5; 233 if (sample->offset + 10 >= sample->size) 234 sample_queue_pop(queue); /* Not enough useful data left */ 235 return 0; 236 } 237 238 if (sample->offset < 10 && sample->size > 20) { 239 /* No match found from the start of the sample, 240 * try from the middle of the sample instead. */ 241 sample->offset = sample->size/2; 242 } else { 243 /* No match for this sample, remove it */ 244 sample_queue_pop(queue); 245 } 246 } 247 return -1; 248} 249 250static void output_immediate(const uint8_t *data, int size, 251 AVIOContext *out, int *entries) 252{ 253 while (size > 0) { 254 int len = size; 255 if (len > 14) 256 len = 14; 257 avio_w8(out, 1); /* immediate constructor */ 258 avio_w8(out, len); /* amount of valid data */ 259 avio_write(out, data, len); 260 data += len; 261 size -= len; 262 263 ffio_fill(out, 0, 14 - len); 264 265 (*entries)++; 266 } 267} 268 269static void output_match(AVIOContext *out, int match_sample, 270 int match_offset, int match_len, int *entries) 271{ 272 avio_w8(out, 2); /* sample constructor */ 273 avio_w8(out, 0); /* track reference */ 274 avio_wb16(out, match_len); 275 avio_wb32(out, match_sample); 276 avio_wb32(out, match_offset); 277 avio_wb16(out, 1); /* bytes per block */ 278 avio_wb16(out, 1); /* samples per block */ 279 (*entries)++; 280} 281 282static void describe_payload(const uint8_t *data, int size, 283 AVIOContext *out, int *entries, 284 HintSampleQueue *queue) 285{ 286 /* Describe the payload using different constructors */ 287 while (size > 0) { 288 int match_sample, match_offset, match_len, pos; 289 if (find_sample_match(data, size, queue, &pos, &match_sample, 290 &match_offset, &match_len) < 0) 291 break; 292 output_immediate(data, pos, out, entries); 293 data += pos; 294 size -= pos; 295 output_match(out, match_sample, match_offset, match_len, entries); 296 data += match_len; 297 size -= match_len; 298 } 299 output_immediate(data, size, out, entries); 300} 301 302/** 303 * Write an RTP hint (that may contain one or more RTP packets) 304 * for the packets in data. data contains one or more packets with a 305 * BE32 size header. 306 * 307 * @param out buffer where the hints are written 308 * @param data buffer containing RTP packets 309 * @param size the size of the data buffer 310 * @param trk the MOVTrack for the hint track 311 * @param dts pointer where the timestamp for the written RTP hint is stored 312 * @return the number of RTP packets in the written hint 313 */ 314static int write_hint_packets(AVIOContext *out, const uint8_t *data, 315 int size, MOVTrack *trk, int64_t *dts) 316{ 317 int64_t curpos; 318 int64_t count_pos, entries_pos; 319 int count = 0, entries; 320 321 count_pos = avio_tell(out); 322 /* RTPsample header */ 323 avio_wb16(out, 0); /* packet count */ 324 avio_wb16(out, 0); /* reserved */ 325 326 while (size > 4) { 327 uint32_t packet_len = AV_RB32(data); 328 uint16_t seq; 329 uint32_t ts; 330 int32_t ts_diff; 331 332 data += 4; 333 size -= 4; 334 if (packet_len > size || packet_len <= 12) 335 break; 336 if (RTP_PT_IS_RTCP(data[1])) { 337 /* RTCP packet, just skip */ 338 data += packet_len; 339 size -= packet_len; 340 continue; 341 } 342 343 if (packet_len > trk->max_packet_size) 344 trk->max_packet_size = packet_len; 345 346 seq = AV_RB16(&data[2]); 347 ts = AV_RB32(&data[4]); 348 349 if (trk->prev_rtp_ts == 0) 350 trk->prev_rtp_ts = ts; 351 /* Unwrap the 32-bit RTP timestamp that wraps around often 352 * into a not (as often) wrapping 64-bit timestamp. */ 353 ts_diff = ts - trk->prev_rtp_ts; 354 if (ts_diff > 0) { 355 trk->cur_rtp_ts_unwrapped += ts_diff; 356 trk->prev_rtp_ts = ts; 357 ts_diff = 0; 358 } 359 if (*dts == AV_NOPTS_VALUE) 360 *dts = trk->cur_rtp_ts_unwrapped; 361 362 count++; 363 /* RTPpacket header */ 364 avio_wb32(out, 0); /* relative_time */ 365 avio_write(out, data, 2); /* RTP header */ 366 avio_wb16(out, seq); /* RTPsequenceseed */ 367 avio_wb16(out, ts_diff ? 4 : 0); /* reserved + flags (extra_flag) */ 368 entries_pos = avio_tell(out); 369 avio_wb16(out, 0); /* entry count */ 370 if (ts_diff) { /* if extra_flag is set */ 371 avio_wb32(out, 16); /* extra_information_length */ 372 avio_wb32(out, 12); /* rtpoffsetTLV box */ 373 avio_write(out, "rtpo", 4); 374 avio_wb32(out, ts_diff); 375 } 376 377 data += 12; 378 size -= 12; 379 packet_len -= 12; 380 381 entries = 0; 382 /* Write one or more constructors describing the payload data */ 383 describe_payload(data, packet_len, out, &entries, &trk->sample_queue); 384 data += packet_len; 385 size -= packet_len; 386 387 curpos = avio_tell(out); 388 avio_seek(out, entries_pos, SEEK_SET); 389 avio_wb16(out, entries); 390 avio_seek(out, curpos, SEEK_SET); 391 } 392 393 curpos = avio_tell(out); 394 avio_seek(out, count_pos, SEEK_SET); 395 avio_wb16(out, count); 396 avio_seek(out, curpos, SEEK_SET); 397 return count; 398} 399 400int ff_mov_add_hinted_packet(AVFormatContext *s, AVPacket *pkt, 401 int track_index, int sample, 402 uint8_t *sample_data, int sample_size) 403{ 404 MOVMuxContext *mov = s->priv_data; 405 MOVTrack *trk = &mov->tracks[track_index]; 406 AVFormatContext *rtp_ctx = trk->rtp_ctx; 407 uint8_t *buf = NULL; 408 int size; 409 AVIOContext *hintbuf = NULL; 410 AVPacket *hint_pkt = mov->pkt; 411 int ret = 0, count; 412 413 if (!rtp_ctx) 414 return AVERROR(ENOENT); 415 if (!rtp_ctx->pb) 416 return AVERROR(ENOMEM); 417 418 if (sample_data) 419 sample_queue_push(&trk->sample_queue, sample_data, sample_size, sample); 420 else 421 sample_queue_push(&trk->sample_queue, pkt->data, pkt->size, sample); 422 423 /* Feed the packet to the RTP muxer */ 424 ff_write_chained(rtp_ctx, 0, pkt, s, 0); 425 426 /* Fetch the output from the RTP muxer, open a new output buffer 427 * for next time. */ 428 size = avio_close_dyn_buf(rtp_ctx->pb, &buf); 429 if ((ret = ffio_open_dyn_packet_buf(&rtp_ctx->pb, 430 RTP_MAX_PACKET_SIZE)) < 0) 431 goto done; 432 433 if (size <= 0) 434 goto done; 435 436 /* Open a buffer for writing the hint */ 437 if ((ret = avio_open_dyn_buf(&hintbuf)) < 0) 438 goto done; 439 av_packet_unref(hint_pkt); 440 count = write_hint_packets(hintbuf, buf, size, trk, &hint_pkt->dts); 441 av_freep(&buf); 442 443 /* Write the hint data into the hint track */ 444 hint_pkt->size = size = avio_close_dyn_buf(hintbuf, &buf); 445 hint_pkt->data = buf; 446 hint_pkt->pts = hint_pkt->dts; 447 hint_pkt->stream_index = track_index; 448 if (pkt->flags & AV_PKT_FLAG_KEY) 449 hint_pkt->flags |= AV_PKT_FLAG_KEY; 450 if (count > 0) 451 ff_mov_write_packet(s, hint_pkt); 452done: 453 av_free(buf); 454 av_packet_unref(hint_pkt); 455 sample_queue_retain(&trk->sample_queue); 456 return ret; 457} 458 459void ff_mov_close_hinting(MOVTrack *track) 460{ 461 AVFormatContext *rtp_ctx = track->rtp_ctx; 462 463 avcodec_parameters_free(&track->par); 464 sample_queue_free(&track->sample_queue); 465 if (!rtp_ctx) 466 return; 467 if (rtp_ctx->pb) { 468 av_write_trailer(rtp_ctx); 469 ffio_free_dyn_buf(&rtp_ctx->pb); 470 } 471 avformat_free_context(rtp_ctx); 472} 473