LCOV - code coverage report
Current view: top level - libavformat - rtpdec_asf.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 146 0.0 %
Date: 2017-12-10 21:22:29 Functions: 0 7 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Microsoft RTP/ASF support.
       3             :  * Copyright (c) 2008 Ronald S. Bultje
       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             : /**
      23             :  * @file
      24             :  * @brief Microsoft RTP/ASF support
      25             :  * @author Ronald S. Bultje <rbultje@ronald.bitfreak.net>
      26             :  */
      27             : 
      28             : #include "libavutil/avassert.h"
      29             : #include "libavutil/base64.h"
      30             : #include "libavutil/avstring.h"
      31             : #include "libavutil/intreadwrite.h"
      32             : #include "rtp.h"
      33             : #include "rtpdec_formats.h"
      34             : #include "rtsp.h"
      35             : #include "asf.h"
      36             : #include "avio_internal.h"
      37             : #include "internal.h"
      38             : 
      39             : /**
      40             :  * From MSDN 2.2.1.4, we learn that ASF data packets over RTP should not
      41             :  * contain any padding. Unfortunately, the header min/max_pktsize are not
      42             :  * updated (thus making min_pktsize invalid). Here, we "fix" these faulty
      43             :  * min_pktsize values in the ASF file header.
      44             :  * @return 0 on success, <0 on failure (currently -1).
      45             :  */
      46           0 : static int rtp_asf_fix_header(uint8_t *buf, int len)
      47             : {
      48           0 :     uint8_t *p = buf, *end = buf + len;
      49             : 
      50           0 :     if (len < sizeof(ff_asf_guid) * 2 + 22 ||
      51           0 :         memcmp(p, ff_asf_header, sizeof(ff_asf_guid))) {
      52           0 :         return -1;
      53             :     }
      54           0 :     p += sizeof(ff_asf_guid) + 14;
      55             :     do {
      56           0 :         uint64_t chunksize = AV_RL64(p + sizeof(ff_asf_guid));
      57           0 :         int skip = 6 * 8 + 3 * 4 + sizeof(ff_asf_guid) * 2;
      58           0 :         if (memcmp(p, ff_asf_file_header, sizeof(ff_asf_guid))) {
      59           0 :             if (chunksize > end - p)
      60           0 :                 return -1;
      61           0 :             p += chunksize;
      62           0 :             continue;
      63             :         }
      64             : 
      65           0 :         if (end - p < 8 + skip)
      66           0 :             break;
      67             :         /* skip most of the file header, to min_pktsize */
      68           0 :         p += skip;
      69           0 :         if (AV_RL32(p) == AV_RL32(p + 4)) {
      70             :             /* and set that to zero */
      71           0 :             AV_WL32(p, 0);
      72           0 :             return 0;
      73             :         }
      74           0 :         break;
      75           0 :     } while (end - p >= sizeof(ff_asf_guid) + 8);
      76             : 
      77           0 :     return -1;
      78             : }
      79             : 
      80             : /**
      81             :  * The following code is basically a buffered AVIOContext,
      82             :  * with the added benefit of returning -EAGAIN (instead of 0)
      83             :  * on packet boundaries, such that the ASF demuxer can return
      84             :  * safely and resume business at the next packet.
      85             :  */
      86           0 : static int packetizer_read(void *opaque, uint8_t *buf, int buf_size)
      87             : {
      88           0 :     return AVERROR(EAGAIN);
      89             : }
      90             : 
      91           0 : static void init_packetizer(AVIOContext *pb, uint8_t *buf, int len)
      92             : {
      93           0 :     ffio_init_context(pb, buf, len, 0, NULL, packetizer_read, NULL, NULL);
      94             : 
      95             :     /* this "fills" the buffer with its current content */
      96           0 :     pb->pos     = len;
      97           0 :     pb->buf_end = buf + len;
      98           0 : }
      99             : 
     100           0 : int ff_wms_parse_sdp_a_line(AVFormatContext *s, const char *p)
     101             : {
     102           0 :     int ret = 0;
     103           0 :     if (av_strstart(p, "pgmpu:data:application/vnd.ms.wms-hdr.asfv1;base64,", &p)) {
     104           0 :         AVIOContext pb = { 0 };
     105           0 :         RTSPState *rt = s->priv_data;
     106           0 :         AVDictionary *opts = NULL;
     107           0 :         int len = strlen(p) * 6 / 8;
     108           0 :         char *buf = av_mallocz(len);
     109             :         AVInputFormat *iformat;
     110             : 
     111           0 :         if (!buf)
     112           0 :             return AVERROR(ENOMEM);
     113           0 :         av_base64_decode(buf, p, len);
     114             : 
     115           0 :         if (rtp_asf_fix_header(buf, len) < 0)
     116           0 :             av_log(s, AV_LOG_ERROR,
     117             :                    "Failed to fix invalid RTSP-MS/ASF min_pktsize\n");
     118           0 :         init_packetizer(&pb, buf, len);
     119           0 :         if (rt->asf_ctx) {
     120           0 :             avformat_close_input(&rt->asf_ctx);
     121             :         }
     122             : 
     123           0 :         if (!(iformat = av_find_input_format("asf")))
     124           0 :             return AVERROR_DEMUXER_NOT_FOUND;
     125             : 
     126           0 :         rt->asf_ctx = avformat_alloc_context();
     127           0 :         if (!rt->asf_ctx) {
     128           0 :             av_free(buf);
     129           0 :             return AVERROR(ENOMEM);
     130             :         }
     131           0 :         rt->asf_ctx->pb      = &pb;
     132           0 :         av_dict_set(&opts, "no_resync_search", "1", 0);
     133             : 
     134           0 :         if ((ret = ff_copy_whiteblacklists(rt->asf_ctx, s)) < 0) {
     135           0 :             av_dict_free(&opts);
     136           0 :             return ret;
     137             :         }
     138             : 
     139           0 :         ret = avformat_open_input(&rt->asf_ctx, "", iformat, &opts);
     140           0 :         av_dict_free(&opts);
     141           0 :         if (ret < 0) {
     142           0 :             av_free(pb.buffer);
     143           0 :             return ret;
     144             :         }
     145           0 :         av_dict_copy(&s->metadata, rt->asf_ctx->metadata, 0);
     146           0 :         rt->asf_pb_pos = avio_tell(&pb);
     147           0 :         av_free(pb.buffer);
     148           0 :         rt->asf_ctx->pb = NULL;
     149             :     }
     150           0 :     return ret;
     151             : }
     152             : 
     153           0 : static int asfrtp_parse_sdp_line(AVFormatContext *s, int stream_index,
     154             :                                  PayloadContext *asf, const char *line)
     155             : {
     156           0 :     if (stream_index < 0)
     157           0 :         return 0;
     158           0 :     if (av_strstart(line, "stream:", &line)) {
     159           0 :         RTSPState *rt = s->priv_data;
     160             : 
     161           0 :         s->streams[stream_index]->id = strtol(line, NULL, 10);
     162             : 
     163           0 :         if (rt->asf_ctx) {
     164             :             int i;
     165             : 
     166           0 :             for (i = 0; i < rt->asf_ctx->nb_streams; i++) {
     167           0 :                 if (s->streams[stream_index]->id == rt->asf_ctx->streams[i]->id) {
     168           0 :                     avcodec_parameters_copy(s->streams[stream_index]->codecpar,
     169           0 :                                             rt->asf_ctx->streams[i]->codecpar);
     170           0 :                     s->streams[stream_index]->need_parsing =
     171           0 :                         rt->asf_ctx->streams[i]->need_parsing;
     172           0 :                     avpriv_set_pts_info(s->streams[stream_index], 32, 1, 1000);
     173             :                 }
     174             :            }
     175             :         }
     176             :     }
     177             : 
     178           0 :     return 0;
     179             : }
     180             : 
     181             : struct PayloadContext {
     182             :     AVIOContext *pktbuf, pb;
     183             :     uint8_t *buf;
     184             : };
     185             : 
     186             : /**
     187             :  * @return 0 when a packet was written into /p pkt, and no more data is left;
     188             :  *         1 when a packet was written into /p pkt, and more packets might be left;
     189             :  *        <0 when not enough data was provided to return a full packet, or on error.
     190             :  */
     191           0 : static int asfrtp_parse_packet(AVFormatContext *s, PayloadContext *asf,
     192             :                                AVStream *st, AVPacket *pkt,
     193             :                                uint32_t *timestamp,
     194             :                                const uint8_t *buf, int len, uint16_t seq,
     195             :                                int flags)
     196             : {
     197           0 :     AVIOContext *pb = &asf->pb;
     198             :     int res, mflags, len_off;
     199           0 :     RTSPState *rt = s->priv_data;
     200             : 
     201           0 :     if (!rt->asf_ctx)
     202           0 :         return -1;
     203             : 
     204           0 :     if (len > 0) {
     205           0 :         int off, out_len = 0;
     206             : 
     207           0 :         if (len < 4)
     208           0 :             return -1;
     209             : 
     210           0 :         av_freep(&asf->buf);
     211             : 
     212           0 :         ffio_init_context(pb, (uint8_t *)buf, len, 0, NULL, NULL, NULL, NULL);
     213             : 
     214           0 :         while (avio_tell(pb) + 4 < len) {
     215           0 :             int start_off = avio_tell(pb);
     216             : 
     217           0 :             mflags = avio_r8(pb);
     218           0 :             len_off = avio_rb24(pb);
     219           0 :             if (mflags & 0x20)   /**< relative timestamp */
     220           0 :                 avio_skip(pb, 4);
     221           0 :             if (mflags & 0x10)   /**< has duration */
     222           0 :                 avio_skip(pb, 4);
     223           0 :             if (mflags & 0x8)    /**< has location ID */
     224           0 :                 avio_skip(pb, 4);
     225           0 :             off = avio_tell(pb);
     226             : 
     227           0 :             if (!(mflags & 0x40)) {
     228             :                 /**
     229             :                  * If 0x40 is not set, the len_off field specifies an offset
     230             :                  * of this packet's payload data in the complete (reassembled)
     231             :                  * ASF packet. This is used to spread one ASF packet over
     232             :                  * multiple RTP packets.
     233             :                  */
     234           0 :                 if (asf->pktbuf && len_off != avio_tell(asf->pktbuf)) {
     235           0 :                     ffio_free_dyn_buf(&asf->pktbuf);
     236             :                 }
     237           0 :                 if (!len_off && !asf->pktbuf &&
     238           0 :                     (res = avio_open_dyn_buf(&asf->pktbuf)) < 0)
     239           0 :                     return res;
     240           0 :                 if (!asf->pktbuf)
     241           0 :                     return AVERROR(EIO);
     242             : 
     243           0 :                 avio_write(asf->pktbuf, buf + off, len - off);
     244           0 :                 avio_skip(pb, len - off);
     245           0 :                 if (!(flags & RTP_FLAG_MARKER))
     246           0 :                     return -1;
     247           0 :                 out_len     = avio_close_dyn_buf(asf->pktbuf, &asf->buf);
     248           0 :                 asf->pktbuf = NULL;
     249             :             } else {
     250             :                 /**
     251             :                  * If 0x40 is set, the len_off field specifies the length of
     252             :                  * the next ASF packet that can be read from this payload
     253             :                  * data alone. This is commonly the same as the payload size,
     254             :                  * but could be less in case of packet splitting (i.e.
     255             :                  * multiple ASF packets in one RTP packet).
     256             :                  */
     257             : 
     258           0 :                 int cur_len = start_off + len_off - off;
     259           0 :                 int prev_len = out_len;
     260           0 :                 out_len += cur_len;
     261           0 :                 if (FFMIN(cur_len, len - off) < 0)
     262           0 :                     return -1;
     263           0 :                 if ((res = av_reallocp(&asf->buf, out_len)) < 0)
     264           0 :                     return res;
     265           0 :                 memcpy(asf->buf + prev_len, buf + off,
     266           0 :                        FFMIN(cur_len, len - off));
     267           0 :                 avio_skip(pb, cur_len);
     268             :             }
     269             :         }
     270             : 
     271           0 :         init_packetizer(pb, asf->buf, out_len);
     272           0 :         pb->pos += rt->asf_pb_pos;
     273           0 :         pb->eof_reached = 0;
     274           0 :         rt->asf_ctx->pb = pb;
     275             :     }
     276             : 
     277           0 :     for (;;) {
     278             :         int i;
     279             : 
     280           0 :         res = ff_read_packet(rt->asf_ctx, pkt);
     281           0 :         rt->asf_pb_pos = avio_tell(pb);
     282           0 :         if (res != 0)
     283           0 :             break;
     284           0 :         for (i = 0; i < s->nb_streams; i++) {
     285           0 :             if (s->streams[i]->id == rt->asf_ctx->streams[pkt->stream_index]->id) {
     286           0 :                 pkt->stream_index = i;
     287           0 :                 return 1; // FIXME: return 0 if last packet
     288             :             }
     289             :         }
     290           0 :         av_packet_unref(pkt);
     291             :     }
     292             : 
     293           0 :     return res == 1 ? -1 : res;
     294             : }
     295             : 
     296           0 : static void asfrtp_close_context(PayloadContext *asf)
     297             : {
     298           0 :     ffio_free_dyn_buf(&asf->pktbuf);
     299           0 :     av_freep(&asf->buf);
     300           0 : }
     301             : 
     302             : #define RTP_ASF_HANDLER(n, s, t) \
     303             : RTPDynamicProtocolHandler ff_ms_rtp_ ## n ## _handler = { \
     304             :     .enc_name         = s, \
     305             :     .codec_type       = t, \
     306             :     .codec_id         = AV_CODEC_ID_NONE, \
     307             :     .priv_data_size   = sizeof(PayloadContext), \
     308             :     .parse_sdp_a_line = asfrtp_parse_sdp_line, \
     309             :     .close            = asfrtp_close_context, \
     310             :     .parse_packet     = asfrtp_parse_packet,   \
     311             : }
     312             : 
     313             : RTP_ASF_HANDLER(asf_pfv, "x-asf-pf",  AVMEDIA_TYPE_VIDEO);
     314             : RTP_ASF_HANDLER(asf_pfa, "x-asf-pf",  AVMEDIA_TYPE_AUDIO);

Generated by: LCOV version 1.13