LCOV - code coverage report
Current view: top level - libavformat - movenchint.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 191 244 78.3 %
Date: 2017-12-15 02:19:58 Functions: 13 13 100.0 %

          Line data    Source code
       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 "internal.h"
      25             : #include "rtpenc_chain.h"
      26             : #include "avio_internal.h"
      27             : #include "rtp.h"
      28             : 
      29           2 : int ff_mov_init_hinting(AVFormatContext *s, int index, int src_index)
      30             : {
      31           2 :     MOVMuxContext *mov  = s->priv_data;
      32           2 :     MOVTrack *track     = &mov->tracks[index];
      33           2 :     MOVTrack *src_track = &mov->tracks[src_index];
      34           2 :     AVStream *src_st    = s->streams[src_index];
      35           2 :     int ret = AVERROR(ENOMEM);
      36             : 
      37           2 :     track->tag = MKTAG('r','t','p',' ');
      38           2 :     track->src_track = src_index;
      39             : 
      40           2 :     track->par = avcodec_parameters_alloc();
      41           2 :     if (!track->par)
      42           0 :         goto fail;
      43           2 :     track->par->codec_type = AVMEDIA_TYPE_DATA;
      44           2 :     track->par->codec_tag  = track->tag;
      45             : 
      46           2 :     ret = ff_rtp_chain_mux_open(&track->rtp_ctx, s, src_st, NULL,
      47             :                                 RTP_MAX_PACKET_SIZE, src_index);
      48           2 :     if (ret < 0)
      49           0 :         goto fail;
      50             : 
      51             :     /* Copy the RTP AVStream timebase back to the hint AVStream */
      52           2 :     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           2 :     src_track->hint_track = index;
      57           2 :     return 0;
      58           0 : fail:
      59           0 :     av_log(s, AV_LOG_WARNING,
      60             :            "Unable to initialize hinting of stream %d\n", src_index);
      61           0 :     avcodec_parameters_free(&track->par);
      62             :     /* Set a default timescale, to avoid crashes in av_dump_format */
      63           0 :     track->timescale = 90000;
      64           0 :     return ret;
      65             : }
      66             : 
      67             : /**
      68             :  * Remove the first sample from the sample queue.
      69             :  */
      70          69 : static void sample_queue_pop(HintSampleQueue *queue)
      71             : {
      72          69 :     if (queue->len <= 0)
      73           0 :         return;
      74          69 :     if (queue->samples[0].own_data)
      75           0 :         av_freep(&queue->samples[0].data);
      76          69 :     queue->len--;
      77          69 :     memmove(queue->samples, queue->samples + 1, sizeof(HintSample)*queue->len);
      78             : }
      79             : 
      80             : /**
      81             :  * Empty the sample queue, releasing all memory.
      82             :  */
      83           2 : static void sample_queue_free(HintSampleQueue *queue)
      84             : {
      85             :     int i;
      86           2 :     for (i = 0; i < queue->len; i++)
      87           0 :         if (queue->samples[i].own_data)
      88           0 :             av_freep(&queue->samples[i].data);
      89           2 :     av_freep(&queue->samples);
      90           2 :     queue->len  = 0;
      91           2 :     queue->size = 0;
      92           2 : }
      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             :  */
      99          69 : static void sample_queue_push(HintSampleQueue *queue, 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          69 :     if (size <= 14)
     105           0 :         return;
     106          69 :     if (!queue->samples || queue->len >= queue->size) {
     107             :         HintSample *samples;
     108           2 :         samples = av_realloc_array(queue->samples, queue->size + 10, sizeof(HintSample));
     109           2 :         if (!samples)
     110           0 :             return;
     111           2 :         queue->size += 10;
     112           2 :         queue->samples = samples;
     113             :     }
     114          69 :     queue->samples[queue->len].data = data;
     115          69 :     queue->samples[queue->len].size = size;
     116          69 :     queue->samples[queue->len].sample_number = sample;
     117          69 :     queue->samples[queue->len].offset   = 0;
     118          69 :     queue->samples[queue->len].own_data = 0;
     119          69 :     queue->len++;
     120             : }
     121             : 
     122             : /**
     123             :  * Make local copies of all referenced sample data in the queue.
     124             :  */
     125          69 : static void sample_queue_retain(HintSampleQueue *queue)
     126             : {
     127             :     int i;
     128         138 :     for (i = 0; i < queue->len; ) {
     129           0 :         HintSample *sample = &queue->samples[i];
     130           0 :         if (!sample->own_data) {
     131           0 :             uint8_t *ptr = av_malloc(sample->size);
     132           0 :             if (!ptr) {
     133             :                 /* Unable to allocate memory for this one, remove it */
     134           0 :                 memmove(queue->samples + i, queue->samples + i + 1,
     135           0 :                         sizeof(HintSample)*(queue->len - i - 1));
     136           0 :                 queue->len--;
     137           0 :                 continue;
     138             :             }
     139           0 :             memcpy(ptr, sample->data, sample->size);
     140           0 :             sample->data = ptr;
     141           0 :             sample->own_data = 1;
     142             :         }
     143           0 :         i++;
     144             :     }
     145          69 : }
     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             :  */
     163         274 : static 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        1644 :     for (h_pos = 0; h_pos < h_len; h_pos++) {
     170        1644 :         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      712412 :         while (h_pos + match_len < h_len && n_pos + match_len < n_len &&
     175      355247 :                needle[n_pos + match_len] == haystack[h_pos + match_len])
     176      353877 :             match_len++;
     177        1644 :         if (match_len <= 8)
     178        1370 :             continue;
     179             : 
     180             :         /* If a sufficiently large match was found, try to expand
     181             :          * the matched segment backwards. */
     182         274 :         match_h_pos = h_pos;
     183         274 :         match_n_pos = n_pos;
     184        3288 :         while (match_n_pos > 0 && match_h_pos > 0 &&
     185        1370 :                needle[match_n_pos - 1] == haystack[match_h_pos - 1]) {
     186        1370 :             match_n_pos--;
     187        1370 :             match_h_pos--;
     188        1370 :             match_len++;
     189             :         }
     190         274 :         if (match_len <= 14)
     191           0 :             continue;
     192         274 :         *match_h_offset_ptr = match_h_pos;
     193         274 :         *match_n_offset_ptr = match_n_pos;
     194         274 :         *match_len_ptr = match_len;
     195         274 :         return 0;
     196             :     }
     197           0 :     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             :  */
     215         274 : static 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         548 :     while (queue->len > 0) {
     221         274 :         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         274 :         if (sample->offset == 0 && sample->size > 5)
     225          69 :             sample->offset = 5;
     226             : 
     227         274 :         if (match_segments(data, len, sample->data, sample->offset,
     228             :                            sample->size, pos, match_offset, match_len) == 0) {
     229         274 :             *match_sample = sample->sample_number;
     230             :             /* Next time, look for matches at this offset, with a little
     231             :              * margin to this match. */
     232         274 :             sample->offset = *match_offset + *match_len + 5;
     233         274 :             if (sample->offset + 10 >= sample->size)
     234          69 :                 sample_queue_pop(queue); /* Not enough useful data left */
     235         274 :             return 0;
     236             :         }
     237             : 
     238           0 :         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           0 :             sample->offset = sample->size/2;
     242             :         } else {
     243             :             /* No match for this sample, remove it */
     244           0 :             sample_queue_pop(queue);
     245             :         }
     246             :     }
     247           0 :     return -1;
     248             : }
     249             : 
     250         548 : static void output_immediate(const uint8_t *data, int size,
     251             :                              AVIOContext *out, int *entries)
     252             : {
     253        1096 :     while (size > 0) {
     254           0 :         int len = size;
     255           0 :         if (len > 14)
     256           0 :             len = 14;
     257           0 :         avio_w8(out, 1); /* immediate constructor */
     258           0 :         avio_w8(out, len); /* amount of valid data */
     259           0 :         avio_write(out, data, len);
     260           0 :         data += len;
     261           0 :         size -= len;
     262             : 
     263           0 :         for (; len < 14; len++)
     264           0 :             avio_w8(out, 0);
     265             : 
     266           0 :         (*entries)++;
     267             :     }
     268         548 : }
     269             : 
     270         274 : static void output_match(AVIOContext *out, int match_sample,
     271             :                          int match_offset, int match_len, int *entries)
     272             : {
     273         274 :     avio_w8(out, 2); /* sample constructor */
     274         274 :     avio_w8(out, 0); /* track reference */
     275         274 :     avio_wb16(out, match_len);
     276         274 :     avio_wb32(out, match_sample);
     277         274 :     avio_wb32(out, match_offset);
     278         274 :     avio_wb16(out, 1); /* bytes per block */
     279         274 :     avio_wb16(out, 1); /* samples per block */
     280         274 :     (*entries)++;
     281         274 : }
     282             : 
     283         274 : static void describe_payload(const uint8_t *data, int size,
     284             :                              AVIOContext *out, int *entries,
     285             :                              HintSampleQueue *queue)
     286             : {
     287             :     /* Describe the payload using different constructors */
     288         822 :     while (size > 0) {
     289             :         int match_sample, match_offset, match_len, pos;
     290         274 :         if (find_sample_match(data, size, queue, &pos, &match_sample,
     291             :                               &match_offset, &match_len) < 0)
     292           0 :             break;
     293         274 :         output_immediate(data, pos, out, entries);
     294         274 :         data += pos;
     295         274 :         size -= pos;
     296         274 :         output_match(out, match_sample, match_offset, match_len, entries);
     297         274 :         data += match_len;
     298         274 :         size -= match_len;
     299             :     }
     300         274 :     output_immediate(data, size, out, entries);
     301         274 : }
     302             : 
     303             : /**
     304             :  * Write an RTP hint (that may contain one or more RTP packets)
     305             :  * for the packets in data. data contains one or more packets with a
     306             :  * BE32 size header.
     307             :  *
     308             :  * @param out buffer where the hints are written
     309             :  * @param data buffer containing RTP packets
     310             :  * @param size the size of the data buffer
     311             :  * @param trk the MOVTrack for the hint track
     312             :  * @param dts pointer where the timestamp for the written RTP hint is stored
     313             :  * @return the number of RTP packets in the written hint
     314             :  */
     315          69 : static int write_hint_packets(AVIOContext *out, const uint8_t *data,
     316             :                               int size, MOVTrack *trk, int64_t *dts)
     317             : {
     318             :     int64_t curpos;
     319             :     int64_t count_pos, entries_pos;
     320          69 :     int count = 0, entries;
     321             : 
     322          69 :     count_pos = avio_tell(out);
     323             :     /* RTPsample header */
     324          69 :     avio_wb16(out, 0); /* packet count */
     325          69 :     avio_wb16(out, 0); /* reserved */
     326             : 
     327         414 :     while (size > 4) {
     328         276 :         uint32_t packet_len = AV_RB32(data);
     329             :         uint16_t seq;
     330             :         uint32_t ts;
     331             :         int32_t  ts_diff;
     332             : 
     333         276 :         data += 4;
     334         276 :         size -= 4;
     335         276 :         if (packet_len > size || packet_len <= 12)
     336             :             break;
     337         276 :         if (RTP_PT_IS_RTCP(data[1])) {
     338             :             /* RTCP packet, just skip */
     339           2 :             data += packet_len;
     340           2 :             size -= packet_len;
     341           2 :             continue;
     342             :         }
     343             : 
     344         274 :         if (packet_len > trk->max_packet_size)
     345           2 :             trk->max_packet_size = packet_len;
     346             : 
     347         274 :         seq = AV_RB16(&data[2]);
     348         274 :         ts  = AV_RB32(&data[4]);
     349             : 
     350         274 :         if (trk->prev_rtp_ts == 0)
     351           2 :             trk->prev_rtp_ts = ts;
     352             :         /* Unwrap the 32-bit RTP timestamp that wraps around often
     353             :          * into a not (as often) wrapping 64-bit timestamp. */
     354         274 :         ts_diff = ts - trk->prev_rtp_ts;
     355         274 :         if (ts_diff > 0) {
     356          67 :             trk->cur_rtp_ts_unwrapped += ts_diff;
     357          67 :             trk->prev_rtp_ts = ts;
     358          67 :             ts_diff = 0;
     359             :         }
     360         274 :         if (*dts == AV_NOPTS_VALUE)
     361          69 :             *dts = trk->cur_rtp_ts_unwrapped;
     362             : 
     363         274 :         count++;
     364             :         /* RTPpacket header */
     365         274 :         avio_wb32(out, 0); /* relative_time */
     366         274 :         avio_write(out, data, 2); /* RTP header */
     367         274 :         avio_wb16(out, seq); /* RTPsequenceseed */
     368         274 :         avio_wb16(out, ts_diff ? 4 : 0); /* reserved + flags (extra_flag) */
     369         274 :         entries_pos = avio_tell(out);
     370         274 :         avio_wb16(out, 0); /* entry count */
     371         274 :         if (ts_diff) { /* if extra_flag is set */
     372           0 :             avio_wb32(out, 16); /* extra_information_length */
     373           0 :             avio_wb32(out, 12); /* rtpoffsetTLV box */
     374           0 :             avio_write(out, "rtpo", 4);
     375           0 :             avio_wb32(out, ts_diff);
     376             :         }
     377             : 
     378         274 :         data += 12;
     379         274 :         size -= 12;
     380         274 :         packet_len -= 12;
     381             : 
     382         274 :         entries = 0;
     383             :         /* Write one or more constructors describing the payload data */
     384         274 :         describe_payload(data, packet_len, out, &entries, &trk->sample_queue);
     385         274 :         data += packet_len;
     386         274 :         size -= packet_len;
     387             : 
     388         274 :         curpos = avio_tell(out);
     389         274 :         avio_seek(out, entries_pos, SEEK_SET);
     390         274 :         avio_wb16(out, entries);
     391         274 :         avio_seek(out, curpos, SEEK_SET);
     392             :     }
     393             : 
     394          69 :     curpos = avio_tell(out);
     395          69 :     avio_seek(out, count_pos, SEEK_SET);
     396          69 :     avio_wb16(out, count);
     397          69 :     avio_seek(out, curpos, SEEK_SET);
     398          69 :     return count;
     399             : }
     400             : 
     401         142 : int ff_mov_add_hinted_packet(AVFormatContext *s, AVPacket *pkt,
     402             :                              int track_index, int sample,
     403             :                              uint8_t *sample_data, int sample_size)
     404             : {
     405         142 :     MOVMuxContext *mov = s->priv_data;
     406         142 :     MOVTrack *trk = &mov->tracks[track_index];
     407         142 :     AVFormatContext *rtp_ctx = trk->rtp_ctx;
     408         142 :     uint8_t *buf = NULL;
     409             :     int size;
     410         142 :     AVIOContext *hintbuf = NULL;
     411             :     AVPacket hint_pkt;
     412         142 :     int ret = 0, count;
     413             : 
     414         142 :     if (!rtp_ctx)
     415          73 :         return AVERROR(ENOENT);
     416          69 :     if (!rtp_ctx->pb)
     417           0 :         return AVERROR(ENOMEM);
     418             : 
     419          69 :     if (sample_data)
     420           0 :         sample_queue_push(&trk->sample_queue, sample_data, sample_size, sample);
     421             :     else
     422          69 :         sample_queue_push(&trk->sample_queue, pkt->data, pkt->size, sample);
     423             : 
     424             :     /* Feed the packet to the RTP muxer */
     425          69 :     ff_write_chained(rtp_ctx, 0, pkt, s, 0);
     426             : 
     427             :     /* Fetch the output from the RTP muxer, open a new output buffer
     428             :      * for next time. */
     429          69 :     size = avio_close_dyn_buf(rtp_ctx->pb, &buf);
     430          69 :     if ((ret = ffio_open_dyn_packet_buf(&rtp_ctx->pb,
     431             :                                         RTP_MAX_PACKET_SIZE)) < 0)
     432           0 :         goto done;
     433             : 
     434          69 :     if (size <= 0)
     435           0 :         goto done;
     436             : 
     437             :     /* Open a buffer for writing the hint */
     438          69 :     if ((ret = avio_open_dyn_buf(&hintbuf)) < 0)
     439           0 :         goto done;
     440          69 :     av_init_packet(&hint_pkt);
     441          69 :     count = write_hint_packets(hintbuf, buf, size, trk, &hint_pkt.dts);
     442          69 :     av_freep(&buf);
     443             : 
     444             :     /* Write the hint data into the hint track */
     445          69 :     hint_pkt.size = size = avio_close_dyn_buf(hintbuf, &buf);
     446          69 :     hint_pkt.data = buf;
     447          69 :     hint_pkt.pts  = hint_pkt.dts;
     448          69 :     hint_pkt.stream_index = track_index;
     449          69 :     if (pkt->flags & AV_PKT_FLAG_KEY)
     450          47 :         hint_pkt.flags |= AV_PKT_FLAG_KEY;
     451          69 :     if (count > 0)
     452          69 :         ff_mov_write_packet(s, &hint_pkt);
     453          69 : done:
     454          69 :     av_free(buf);
     455          69 :     sample_queue_retain(&trk->sample_queue);
     456          69 :     return ret;
     457             : }
     458             : 
     459           2 : void ff_mov_close_hinting(MOVTrack *track)
     460             : {
     461           2 :     AVFormatContext *rtp_ctx = track->rtp_ctx;
     462             : 
     463           2 :     avcodec_parameters_free(&track->par);
     464           2 :     sample_queue_free(&track->sample_queue);
     465           2 :     if (!rtp_ctx)
     466           0 :         return;
     467           2 :     if (rtp_ctx->pb) {
     468           2 :         av_write_trailer(rtp_ctx);
     469           2 :         ffio_free_dyn_buf(&rtp_ctx->pb);
     470             :     }
     471           2 :     avformat_free_context(rtp_ctx);
     472             : }

Generated by: LCOV version 1.13