Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * RTP parser for DV payload format (RFC 6469)
  3.  * Copyright (c) 2015 Thomas Volkert <thomas@homer-conferencing.com>
  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 "libavutil/avstring.h"
  23.  
  24. #include "libavcodec/bytestream.h"
  25.  
  26. #include "avio_internal.h"
  27. #include "rtpdec_formats.h"
  28.  
  29. struct PayloadContext {
  30.     AVIOContext *buf;
  31.     uint32_t    timestamp;
  32.     int         bundled_audio;
  33. };
  34.  
  35. static av_cold void dv_close_context(PayloadContext *data)
  36. {
  37.     ffio_free_dyn_buf(&data->buf);
  38. }
  39.  
  40. static av_cold int dv_sdp_parse_fmtp_config(AVFormatContext *s,
  41.                                             AVStream *stream,
  42.                                             PayloadContext *dv_data,
  43.                                             const char *attr, const char *value)
  44. {
  45.     /* does the DV stream include audio? */
  46.     if (!strcmp(attr, "audio") && !strcmp(value, "bundled"))
  47.         dv_data->bundled_audio = 1;
  48.  
  49.     /* extract the DV profile */
  50.     if (!strcmp(attr, "encode")) {
  51.         /* SD-VCR/525-60 */
  52.         /* SD-VCR/625-50 */
  53.         /* HD-VCR/1125-60 */
  54.         /* HD-VCR/1250-50 */
  55.         /* SDL-VCR/525-60 */
  56.         /* SDL-VCR/625-50 */
  57.         /* 314M-25/525-60 */
  58.         /* 314M-25/625-50 */
  59.         /* 314M-50/525-60 */
  60.         /* 314M-50/625-50 */
  61.         /* 370M/1080-60i */
  62.         /* 370M/1080-50i */
  63.         /* 370M/720-60p */
  64.         /* 370M/720-50p */
  65.         /* 306M/525-60 (for backward compatibility) */
  66.         /* 306M/625-50 (for backward compatibility) */
  67.     }
  68.  
  69.     return 0;
  70. }
  71.  
  72. static av_cold int dv_parse_sdp_line(AVFormatContext *ctx, int st_index,
  73.                                      PayloadContext *dv_data, const char *line)
  74. {
  75.     AVStream *current_stream;
  76.     const char *sdp_line_ptr = line;
  77.  
  78.     if (st_index < 0)
  79.         return 0;
  80.  
  81.     current_stream = ctx->streams[st_index];
  82.  
  83.     if (av_strstart(sdp_line_ptr, "fmtp:", &sdp_line_ptr)) {
  84.         return ff_parse_fmtp(ctx, current_stream, dv_data, sdp_line_ptr,
  85.                              dv_sdp_parse_fmtp_config);
  86.     }
  87.  
  88.     return 0;
  89. }
  90.  
  91. static int dv_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_dv_ctx,
  92.                             AVStream *st, AVPacket *pkt, uint32_t *timestamp,
  93.                             const uint8_t *buf, int len, uint16_t seq,
  94.                             int flags)
  95. {
  96.     int res = 0;
  97.  
  98.     /* drop data of previous packets in case of non-continuous (lossy) packet stream */
  99.     if (rtp_dv_ctx->buf && rtp_dv_ctx->timestamp != *timestamp) {
  100.         ffio_free_dyn_buf(&rtp_dv_ctx->buf);
  101.     }
  102.  
  103.     /* sanity check for size of input packet: 1 byte payload at least */
  104.     if (len < 1) {
  105.         av_log(ctx, AV_LOG_ERROR, "Too short RTP/DV packet, got %d bytes\n", len);
  106.         return AVERROR_INVALIDDATA;
  107.     }
  108.  
  109.     /* start frame buffering with new dynamic buffer */
  110.     if (!rtp_dv_ctx->buf) {
  111.         res = avio_open_dyn_buf(&rtp_dv_ctx->buf);
  112.         if (res < 0)
  113.             return res;
  114.         /* update the timestamp in the frame packet with the one from the RTP packet */
  115.         rtp_dv_ctx->timestamp = *timestamp;
  116.     }
  117.  
  118.     /* write the fragment to the dyn. buffer */
  119.     avio_write(rtp_dv_ctx->buf, buf, len);
  120.  
  121.     /* RTP marker bit means: last fragment of current frame was received;
  122.        otherwise, an additional fragment is needed for the current frame */
  123.     if (!(flags & RTP_FLAG_MARKER))
  124.         return AVERROR(EAGAIN);
  125.  
  126.     /* close frame buffering and create resulting A/V packet */
  127.     res = ff_rtp_finalize_packet(pkt, &rtp_dv_ctx->buf, st->index);
  128.     if (res < 0)
  129.         return res;
  130.  
  131.     return 0;
  132. }
  133.  
  134. RTPDynamicProtocolHandler ff_dv_dynamic_handler = {
  135.     .enc_name         = "DV",
  136.     .codec_type       = AVMEDIA_TYPE_VIDEO,
  137.     .codec_id         = AV_CODEC_ID_DVVIDEO,
  138.     .need_parsing     = AVSTREAM_PARSE_FULL,
  139.     .parse_sdp_a_line = dv_parse_sdp_line,
  140.     .priv_data_size   = sizeof(PayloadContext),
  141.     .close             = dv_close_context,
  142.     .parse_packet     = dv_handle_packet,
  143. };
  144.