libavformat/rtpdec_vp8.c
Go to the documentation of this file.
00001 /*
00002  * RTP VP8 Depacketizer
00003  * Copyright (c) 2010 Josh Allmann
00004  *
00005  * This file is part of Libav.
00006  *
00007  * Libav is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * Libav is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with Libav; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00029 #include "libavcodec/bytestream.h"
00030 
00031 #include "rtpdec_formats.h"
00032 
00033 struct PayloadContext {
00034     AVIOContext *data;
00035     uint32_t       timestamp;
00036     int is_keyframe;
00037 };
00038 
00039 static void prepare_packet(AVPacket *pkt, PayloadContext *vp8, int stream)
00040 {
00041     av_init_packet(pkt);
00042     pkt->stream_index = stream;
00043     pkt->flags        = vp8->is_keyframe ? AV_PKT_FLAG_KEY : 0;
00044     pkt->size         = avio_close_dyn_buf(vp8->data, &pkt->data);
00045     pkt->destruct     = av_destruct_packet;
00046     vp8->data         = NULL;
00047 }
00048 
00049 static int vp8_handle_packet(AVFormatContext *ctx,
00050                              PayloadContext *vp8,
00051                              AVStream *st,
00052                              AVPacket *pkt,
00053                              uint32_t *timestamp,
00054                              const uint8_t *buf,
00055                              int len, int flags)
00056 {
00057     int start_packet, end_packet, has_au, ret = AVERROR(EAGAIN);
00058 
00059     if (!buf) {
00060         // only called when vp8_handle_packet returns 1
00061         if (!vp8->data) {
00062             av_log(ctx, AV_LOG_ERROR, "Invalid VP8 data passed\n");
00063             return AVERROR_INVALIDDATA;
00064         }
00065         prepare_packet(pkt, vp8, st->index);
00066         *timestamp = vp8->timestamp;
00067         return 0;
00068     }
00069 
00070     start_packet = *buf & 1;
00071     end_packet   = flags & RTP_FLAG_MARKER;
00072     has_au       = *buf & 2;
00073     buf++;
00074     len--;
00075 
00076     if (start_packet) {
00077         int res;
00078         uint32_t ts = *timestamp;
00079         if (vp8->data) {
00080             // missing end marker; return old frame anyway. untested
00081             prepare_packet(pkt, vp8, st->index);
00082             *timestamp = vp8->timestamp; // reset timestamp from old frame
00083 
00084             // if current frame fits into one rtp packet, need to hold
00085             // that for the next av_get_packet call
00086             ret = end_packet ? 1 : 0;
00087         }
00088         if ((res = avio_open_dyn_buf(&vp8->data)) < 0)
00089             return res;
00090         vp8->is_keyframe = *buf & 1;
00091         vp8->timestamp   = ts;
00092      }
00093 
00094     if (!vp8->data || vp8->timestamp != *timestamp && ret == AVERROR(EAGAIN)) {
00095         av_log(ctx, AV_LOG_WARNING,
00096                "Received no start marker; dropping frame\n");
00097         return AVERROR(EAGAIN);
00098     }
00099 
00100     // cycle through VP8AU headers if needed
00101     // not tested with actual VP8AUs
00102     while (len) {
00103         int au_len = len;
00104         if (has_au && len > 2) {
00105             au_len = AV_RB16(buf);
00106             buf += 2;
00107             len -= 2;
00108             if (buf + au_len > buf + len) {
00109                 av_log(ctx, AV_LOG_ERROR, "Invalid VP8AU length\n");
00110                 return AVERROR_INVALIDDATA;
00111             }
00112         }
00113 
00114         avio_write(vp8->data, buf, au_len);
00115         buf += au_len;
00116         len -= au_len;
00117     }
00118 
00119     if (ret != AVERROR(EAGAIN)) // did we miss a end marker?
00120         return ret;
00121 
00122     if (end_packet) {
00123         prepare_packet(pkt, vp8, st->index);
00124         return 0;
00125     }
00126 
00127     return AVERROR(EAGAIN);
00128 }
00129 
00130 static PayloadContext *vp8_new_context(void)
00131 {
00132     av_log(NULL, AV_LOG_ERROR, "RTP VP8 payload implementation is incompatible "
00133                                "with the latest spec drafts.\n");
00134     return av_mallocz(sizeof(PayloadContext));
00135 }
00136 
00137 static void vp8_free_context(PayloadContext *vp8)
00138 {
00139     if (vp8->data) {
00140         uint8_t *tmp;
00141         avio_close_dyn_buf(vp8->data, &tmp);
00142         av_free(tmp);
00143     }
00144     av_free(vp8);
00145 }
00146 
00147 RTPDynamicProtocolHandler ff_vp8_dynamic_handler = {
00148     .enc_name       = "VP8",
00149     .codec_type     = AVMEDIA_TYPE_VIDEO,
00150     .codec_id       = CODEC_ID_VP8,
00151     .alloc          = vp8_new_context,
00152     .free           = vp8_free_context,
00153     .parse_packet   = vp8_handle_packet,
00154 };