Add RTP depacketization of VP8
Patch by Josh Allmann, joshua dot allmann at gmail Originally committed as revision 24798 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
		
							parent
							
								
									7b18d94cb3
								
							
						
					
					
						commit
						51291e6005
					
				| @ -29,6 +29,7 @@ version <next>: | |||||||
| - ffprobe -show_packets option added | - ffprobe -show_packets option added | ||||||
| - RTP packetization of Theora and Vorbis | - RTP packetization of Theora and Vorbis | ||||||
| - RTP depacketization of MP4A-LATM | - RTP depacketization of MP4A-LATM | ||||||
|  | - RTP packetization and depacketization of VP8 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| version 0.6: | version 0.6: | ||||||
|  | |||||||
| @ -236,6 +236,7 @@ OBJS-$(CONFIG_SDP_DEMUXER)               += rtsp.o        \ | |||||||
|                                             rtpdec_mpeg4.o \
 |                                             rtpdec_mpeg4.o \
 | ||||||
|                                             rtpdec_qdm2.o \
 |                                             rtpdec_qdm2.o \
 | ||||||
|                                             rtpdec_svq3.o \
 |                                             rtpdec_svq3.o \
 | ||||||
|  |                                             rtpdec_vp8.o  \
 | ||||||
|                                             rtpdec_xiph.o |                                             rtpdec_xiph.o | ||||||
| OBJS-$(CONFIG_SEGAFILM_DEMUXER)          += segafilm.o | OBJS-$(CONFIG_SEGAFILM_DEMUXER)          += segafilm.o | ||||||
| OBJS-$(CONFIG_SHORTEN_DEMUXER)           += raw.o | OBJS-$(CONFIG_SHORTEN_DEMUXER)           += raw.o | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ | |||||||
| 
 | 
 | ||||||
| #define LIBAVFORMAT_VERSION_MAJOR 52 | #define LIBAVFORMAT_VERSION_MAJOR 52 | ||||||
| #define LIBAVFORMAT_VERSION_MINOR 78 | #define LIBAVFORMAT_VERSION_MINOR 78 | ||||||
| #define LIBAVFORMAT_VERSION_MICRO  2 | #define LIBAVFORMAT_VERSION_MICRO  3 | ||||||
| 
 | 
 | ||||||
| #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | ||||||
|                                                LIBAVFORMAT_VERSION_MINOR, \ |                                                LIBAVFORMAT_VERSION_MINOR, \ | ||||||
|  | |||||||
| @ -66,6 +66,7 @@ void av_register_rtp_dynamic_payload_handlers(void) | |||||||
|     ff_register_dynamic_payload_handler(&ff_qdm2_dynamic_handler); |     ff_register_dynamic_payload_handler(&ff_qdm2_dynamic_handler); | ||||||
|     ff_register_dynamic_payload_handler(&ff_svq3_dynamic_handler); |     ff_register_dynamic_payload_handler(&ff_svq3_dynamic_handler); | ||||||
|     ff_register_dynamic_payload_handler(&ff_mp4a_latm_dynamic_handler); |     ff_register_dynamic_payload_handler(&ff_mp4a_latm_dynamic_handler); | ||||||
|  |     ff_register_dynamic_payload_handler(&ff_vp8_dynamic_handler); | ||||||
| 
 | 
 | ||||||
|     ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfv_handler); |     ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfv_handler); | ||||||
|     ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfa_handler); |     ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfa_handler); | ||||||
|  | |||||||
| @ -45,5 +45,6 @@ extern RTPDynamicProtocolHandler ff_qdm2_dynamic_handler; | |||||||
| extern RTPDynamicProtocolHandler ff_svq3_dynamic_handler; | extern RTPDynamicProtocolHandler ff_svq3_dynamic_handler; | ||||||
| extern RTPDynamicProtocolHandler ff_theora_dynamic_handler; | extern RTPDynamicProtocolHandler ff_theora_dynamic_handler; | ||||||
| extern RTPDynamicProtocolHandler ff_vorbis_dynamic_handler; | extern RTPDynamicProtocolHandler ff_vorbis_dynamic_handler; | ||||||
|  | extern RTPDynamicProtocolHandler ff_vp8_dynamic_handler; | ||||||
| 
 | 
 | ||||||
| #endif /* AVFORMAT_RTPDEC_FORMATS_H */ | #endif /* AVFORMAT_RTPDEC_FORMATS_H */ | ||||||
|  | |||||||
							
								
								
									
										153
									
								
								libavformat/rtpdec_vp8.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								libavformat/rtpdec_vp8.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,153 @@ | |||||||
|  | /*
 | ||||||
|  |  * RTP VP8 Depacketizer | ||||||
|  |  * Copyright (c) 2010 Josh Allmann | ||||||
|  |  * | ||||||
|  |  * This file is part of FFmpeg. | ||||||
|  |  * | ||||||
|  |  * FFmpeg is free software; you can redistribute it and/or | ||||||
|  |  * modify it under the terms of the GNU Lesser General Public | ||||||
|  |  * License as published by the Free Software Foundation; either | ||||||
|  |  * version 2.1 of the License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * FFmpeg is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||||
|  |  * Lesser General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Lesser General Public | ||||||
|  |  * License along with FFmpeg; if not, write to the Free Software | ||||||
|  |  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @file | ||||||
|  |  * @brief RTP support for the VP8 payload | ||||||
|  |  * @author Josh Allmann <joshua.allmann@gmail.com> | ||||||
|  |  * ( http://www.webmproject.org/code/specs/rtp/ )
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include "libavcodec/bytestream.h" | ||||||
|  | 
 | ||||||
|  | #include "rtpdec_formats.h" | ||||||
|  | 
 | ||||||
|  | struct PayloadContext { | ||||||
|  |     ByteIOContext *data; | ||||||
|  |     uint32_t       timestamp; | ||||||
|  |     int is_keyframe; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void prepare_packet(AVPacket *pkt, PayloadContext *vp8, int stream) | ||||||
|  | { | ||||||
|  |     av_init_packet(pkt); | ||||||
|  |     pkt->stream_index = stream; | ||||||
|  |     pkt->flags        = vp8->is_keyframe ? AV_PKT_FLAG_KEY : 0; | ||||||
|  |     pkt->size         = url_close_dyn_buf(vp8->data, &pkt->data); | ||||||
|  |     pkt->destruct     = av_destruct_packet; | ||||||
|  |     vp8->data         = NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int vp8_handle_packet(AVFormatContext *ctx, | ||||||
|  |                              PayloadContext *vp8, | ||||||
|  |                              AVStream *st, | ||||||
|  |                              AVPacket *pkt, | ||||||
|  |                              uint32_t *timestamp, | ||||||
|  |                              const uint8_t *buf, | ||||||
|  |                              int len, int flags) | ||||||
|  | { | ||||||
|  |     int start_packet, end_packet, has_au, ret = AVERROR(EAGAIN); | ||||||
|  | 
 | ||||||
|  |     if (!buf) { | ||||||
|  |         // only called when vp8_handle_packet returns 1
 | ||||||
|  |         if (!vp8->data) { | ||||||
|  |             av_log(ctx, AV_LOG_ERROR, "Invalid VP8 data passed\n"); | ||||||
|  |             return AVERROR_INVALIDDATA; | ||||||
|  |         } | ||||||
|  |         prepare_packet(pkt, vp8, st->index); | ||||||
|  |         *timestamp = vp8->timestamp; | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     start_packet = *buf & 1; | ||||||
|  |     end_packet   = flags & RTP_FLAG_MARKER; | ||||||
|  |     has_au       = *buf & 2; | ||||||
|  |     buf++; | ||||||
|  |     len--; | ||||||
|  | 
 | ||||||
|  |     if (start_packet) { | ||||||
|  |         int res; | ||||||
|  |         uint32_t ts = *timestamp; | ||||||
|  |         if (vp8->data) { | ||||||
|  |             // missing end marker; return old frame anyway. untested
 | ||||||
|  |             prepare_packet(pkt, vp8, st->index); | ||||||
|  |             *timestamp = vp8->timestamp; // reset timestamp from old frame
 | ||||||
|  | 
 | ||||||
|  |             // if current frame fits into one rtp packet, need to hold
 | ||||||
|  |             // that for the next av_get_packet call
 | ||||||
|  |             ret = end_packet ? 1 : 0; | ||||||
|  |         } | ||||||
|  |         if ((res = url_open_dyn_buf(&vp8->data)) < 0) | ||||||
|  |             return res; | ||||||
|  |         vp8->is_keyframe = *buf & 1; | ||||||
|  |         vp8->timestamp   = ts; | ||||||
|  |      } | ||||||
|  | 
 | ||||||
|  |     if (!vp8->data || vp8->timestamp != *timestamp && ret == AVERROR(EAGAIN)) { | ||||||
|  |         av_log(ctx, AV_LOG_WARNING, | ||||||
|  |                "Received no start marker; dropping frame\n"); | ||||||
|  |         return AVERROR(EAGAIN); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // cycle through VP8AU headers if needed
 | ||||||
|  |     // not tested with actual VP8AUs
 | ||||||
|  |     while (len) { | ||||||
|  |         int au_len = len; | ||||||
|  |         if (has_au && len > 2) { | ||||||
|  |             au_len = AV_RB16(buf); | ||||||
|  |             buf += 2; | ||||||
|  |             len -= 2; | ||||||
|  |             if (buf + au_len > buf + len) { | ||||||
|  |                 av_log(ctx, AV_LOG_ERROR, "Invalid VP8AU length\n"); | ||||||
|  |                 return AVERROR_INVALIDDATA; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         put_buffer(vp8->data, buf, au_len); | ||||||
|  |         buf += au_len; | ||||||
|  |         len -= au_len; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (ret != AVERROR(EAGAIN)) // did we miss a end marker?
 | ||||||
|  |         return ret; | ||||||
|  | 
 | ||||||
|  |     if (end_packet) { | ||||||
|  |         prepare_packet(pkt, vp8, st->index); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return AVERROR(EAGAIN); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static PayloadContext *vp8_new_context(void) | ||||||
|  | { | ||||||
|  |     av_log(NULL, AV_LOG_WARNING, "RTP VP8 payload is still experimental\n"); | ||||||
|  |     return av_mallocz(sizeof(PayloadContext)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void vp8_free_context(PayloadContext *vp8) | ||||||
|  | { | ||||||
|  |     if (vp8->data) { | ||||||
|  |         uint8_t *tmp; | ||||||
|  |         url_close_dyn_buf(vp8->data, &tmp); | ||||||
|  |         av_free(tmp); | ||||||
|  |     } | ||||||
|  |     av_free(vp8); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | RTPDynamicProtocolHandler ff_vp8_dynamic_handler = { | ||||||
|  |     .enc_name       = "VP8", | ||||||
|  |     .codec_type     = AVMEDIA_TYPE_VIDEO, | ||||||
|  |     .codec_id       = CODEC_ID_VP8, | ||||||
|  |     .open           = vp8_new_context, | ||||||
|  |     .close          = vp8_free_context, | ||||||
|  |     .parse_packet   = vp8_handle_packet, | ||||||
|  | }; | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user