Libav 0.7.1
|
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 };