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