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