mirror of
				https://github.com/nyanmisaka/ffmpeg-rockchip.git
				synced 2025-10-31 20:42:49 +08:00 
			
		
		
		
	libavformat: add robust MPEG audio depacketization (RFC 5219)
Signed-off-by: Martin Storsjö <martin@martin.st>
This commit is contained in:
		 Gilles Chanteperdrix
					Gilles Chanteperdrix
				
			
				
					committed by
					
						 Martin Storsjö
						Martin Storsjö
					
				
			
			
				
	
			
			
			 Martin Storsjö
						Martin Storsjö
					
				
			
						parent
						
							5cbae5651d
						
					
				
				
					commit
					96084251e5
				
			| @@ -17,6 +17,7 @@ version <next>: | ||||
| - Intel QSV-accelerated H.264 decoding | ||||
| - DSS SP decoder and DSS demuxer | ||||
| - RTP depacketizer for AC3 payload format (RFC 4184) | ||||
| - RTP depacketizer for loss tolerant payload format for MP3 audio (RFC 5219) | ||||
|  | ||||
|  | ||||
| version 11: | ||||
|   | ||||
| @@ -40,6 +40,7 @@ OBJS-$(CONFIG_RTPDEC)                    += rdt.o                       \ | ||||
|                                             rtpdec_ilbc.o               \ | ||||
|                                             rtpdec_jpeg.o               \ | ||||
|                                             rtpdec_latm.o               \ | ||||
|                                             rtpdec_mpa_robust.o         \ | ||||
|                                             rtpdec_mpeg12.o             \ | ||||
|                                             rtpdec_mpeg4.o              \ | ||||
|                                             rtpdec_mpegts.o             \ | ||||
|   | ||||
| @@ -78,6 +78,7 @@ void ff_register_rtp_dynamic_payload_handlers(void) | ||||
|     ff_register_dynamic_payload_handler(&ff_mp4a_latm_dynamic_handler); | ||||
|     ff_register_dynamic_payload_handler(&ff_mp4v_es_dynamic_handler); | ||||
|     ff_register_dynamic_payload_handler(&ff_mpeg_audio_dynamic_handler); | ||||
|     ff_register_dynamic_payload_handler(&ff_mpeg_audio_robust_dynamic_handler); | ||||
|     ff_register_dynamic_payload_handler(&ff_mpeg_video_dynamic_handler); | ||||
|     ff_register_dynamic_payload_handler(&ff_mpeg4_generic_dynamic_handler); | ||||
|     ff_register_dynamic_payload_handler(&ff_mpegts_dynamic_handler); | ||||
|   | ||||
| @@ -61,6 +61,7 @@ extern RTPDynamicProtocolHandler ff_jpeg_dynamic_handler; | ||||
| extern RTPDynamicProtocolHandler ff_mp4a_latm_dynamic_handler; | ||||
| extern RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler; | ||||
| extern RTPDynamicProtocolHandler ff_mpeg_audio_dynamic_handler; | ||||
| extern RTPDynamicProtocolHandler ff_mpeg_audio_robust_dynamic_handler; | ||||
| extern RTPDynamicProtocolHandler ff_mpeg_video_dynamic_handler; | ||||
| extern RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler; | ||||
| extern RTPDynamicProtocolHandler ff_mpegts_dynamic_handler; | ||||
|   | ||||
							
								
								
									
										224
									
								
								libavformat/rtpdec_mpa_robust.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								libavformat/rtpdec_mpa_robust.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,224 @@ | ||||
| /* | ||||
|  * RTP parser for loss tolerant payload format for MP3 audio (RFC 5219) | ||||
|  * Copyright (c) 2015 Gilles Chanteperdrix <gch@xenomai.org> | ||||
|  * | ||||
|  * This file is part of Libav. | ||||
|  * | ||||
|  * Libav 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. | ||||
|  * | ||||
|  * Libav 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 Libav; if not, write to the Free Software | ||||
|  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include "libavutil/attributes.h" | ||||
| #include "libavutil/intreadwrite.h" | ||||
|  | ||||
| #include "rtpdec_formats.h" | ||||
|  | ||||
| struct PayloadContext { | ||||
|     unsigned adu_size; | ||||
|     unsigned cur_size; | ||||
|     uint32_t timestamp; | ||||
|     uint8_t *split_buf; | ||||
|     int split_pos, split_buf_size, split_pkts; | ||||
|     AVIOContext *fragment; | ||||
| }; | ||||
|  | ||||
| static av_cold int mpa_robust_init(AVFormatContext *ctx, int st_index, | ||||
|                                    PayloadContext *data) | ||||
| { | ||||
|     if (st_index < 0) | ||||
|         return 0; | ||||
|     ctx->streams[st_index]->need_parsing = AVSTREAM_PARSE_HEADERS; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static PayloadContext *mpa_robust_new_context(void) | ||||
| { | ||||
|     return av_mallocz(sizeof(PayloadContext)); | ||||
| } | ||||
|  | ||||
| static inline void free_fragment(PayloadContext *data) | ||||
| { | ||||
|     if (data->fragment) { | ||||
|         uint8_t *p; | ||||
|         avio_close_dyn_buf(data->fragment, &p); | ||||
|         av_free(p); | ||||
|         data->fragment = NULL; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void mpa_robust_free_context(PayloadContext *data) | ||||
| { | ||||
|     free_fragment(data); | ||||
|     av_free(data->split_buf); | ||||
|     av_free(data); | ||||
| } | ||||
|  | ||||
| static int mpa_robust_parse_rtp_header(AVFormatContext *ctx, | ||||
|                                        const uint8_t *buf, int len, | ||||
|                                        unsigned *adu_size, unsigned *cont) | ||||
| { | ||||
|     unsigned header_size; | ||||
|  | ||||
|     if (len < 2) { | ||||
|         av_log(ctx, AV_LOG_ERROR, "Invalid %d bytes packet\n", len); | ||||
|         return AVERROR_INVALIDDATA; | ||||
|     } | ||||
|  | ||||
|     *cont = !!(buf[0] & 0x80); | ||||
|     if (!(buf[0] & 0x40)) { | ||||
|         header_size = 1; | ||||
|         *adu_size = buf[0] & ~0xc0; | ||||
|     } else { | ||||
|         header_size = 2; | ||||
|         *adu_size = AV_RB16(buf) & ~0xc000; | ||||
|     } | ||||
|  | ||||
|     return header_size; | ||||
| } | ||||
|  | ||||
| static int mpa_robust_parse_packet(AVFormatContext *ctx, PayloadContext *data, | ||||
|                                    AVStream *st, AVPacket *pkt, | ||||
|                                    uint32_t *timestamp, const uint8_t *buf, | ||||
|                                    int len, uint16_t seq, int flags) | ||||
| { | ||||
|     unsigned adu_size, continuation; | ||||
|     int err, header_size; | ||||
|  | ||||
|     if (!buf) { | ||||
|         buf = &data->split_buf[data->split_pos]; | ||||
|         len = data->split_buf_size - data->split_pos; | ||||
|  | ||||
|         header_size = mpa_robust_parse_rtp_header(ctx, buf, len, &adu_size, | ||||
|                                                   &continuation); | ||||
|         if (header_size < 0) { | ||||
|             av_freep(&data->split_buf); | ||||
|             return header_size; | ||||
|         } | ||||
|         buf += header_size; | ||||
|         len -= header_size; | ||||
|  | ||||
|         if (continuation || adu_size > len) { | ||||
|             av_freep(&data->split_buf); | ||||
|             av_log(ctx, AV_LOG_ERROR, "Invalid frame\n"); | ||||
|             return AVERROR_INVALIDDATA; | ||||
|         } | ||||
|  | ||||
|         if (av_new_packet(pkt, adu_size)) { | ||||
|             av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); | ||||
|             return AVERROR(ENOMEM); | ||||
|         } | ||||
|  | ||||
|         pkt->stream_index = st->index; | ||||
|         memcpy(pkt->data, buf, adu_size); | ||||
|  | ||||
|         data->split_pos += adu_size; | ||||
|  | ||||
|         if (data->split_pos == data->split_buf_size) { | ||||
|             av_freep(&data->split_buf); | ||||
|             return 0; | ||||
|         } | ||||
|  | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     header_size = mpa_robust_parse_rtp_header(ctx, buf, len, &adu_size, | ||||
|                                               &continuation); | ||||
|     if (header_size < 0) | ||||
|         return header_size; | ||||
|  | ||||
|     buf += header_size; | ||||
|     len -= header_size; | ||||
|  | ||||
|     if (!continuation && adu_size <= len) { | ||||
|         /* One or more complete frames */ | ||||
|  | ||||
|         if (av_new_packet(pkt, adu_size)) { | ||||
|             av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); | ||||
|             return AVERROR(ENOMEM); | ||||
|         } | ||||
|  | ||||
|         pkt->stream_index = st->index; | ||||
|         memcpy(pkt->data, buf, adu_size); | ||||
|  | ||||
|         buf += adu_size; | ||||
|         len -= adu_size; | ||||
|         if (len) { | ||||
|             data->split_buf_size = len; | ||||
|             data->split_buf = av_malloc(data->split_buf_size); | ||||
|             data->split_pos = 0; | ||||
|             if (!data->split_buf) { | ||||
|                 av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); | ||||
|                 av_free_packet(pkt); | ||||
|                 return AVERROR(ENOMEM); | ||||
|             } | ||||
|             memcpy(data->split_buf, buf, data->split_buf_size); | ||||
|             return 1; | ||||
|         } | ||||
|         return 0; | ||||
|     } else if (!continuation) { /* && adu_size > len */ | ||||
|         /* First fragment */ | ||||
|         free_fragment(data); | ||||
|  | ||||
|         data->adu_size = adu_size; | ||||
|         data->cur_size = len; | ||||
|         data->timestamp = *timestamp; | ||||
|  | ||||
|         err = avio_open_dyn_buf(&data->fragment); | ||||
|         if (err < 0) | ||||
|             return err; | ||||
|  | ||||
|         avio_write(data->fragment, buf, len); | ||||
|         return AVERROR(EAGAIN); | ||||
|     } | ||||
|     /* else continuation == 1 */ | ||||
|  | ||||
|     /* Fragment other than first */ | ||||
|     if (!data->fragment) { | ||||
|         av_log(ctx, AV_LOG_WARNING, | ||||
|             "Received packet without a start fragment; dropping.\n"); | ||||
|         return AVERROR(EAGAIN); | ||||
|     } | ||||
|     if (adu_size = data->adu_size || | ||||
|         data->timestamp != *timestamp) { | ||||
|         free_fragment(data); | ||||
|         av_log(ctx, AV_LOG_ERROR, "Invalid packet received\n"); | ||||
|         return AVERROR_INVALIDDATA; | ||||
|     } | ||||
|  | ||||
|     avio_write(data->fragment, buf, len); | ||||
|     data->cur_size += len; | ||||
|  | ||||
|     if (data->cur_size < data->adu_size) | ||||
|         return AVERROR(EAGAIN); | ||||
|  | ||||
|     err = ff_rtp_finalize_packet(pkt, &data->fragment, st->index); | ||||
|     if (err < 0) { | ||||
|         av_log(ctx, AV_LOG_ERROR, | ||||
|                "Error occurred when getting fragment buffer.\n"); | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| RTPDynamicProtocolHandler ff_mpeg_audio_robust_dynamic_handler = { | ||||
|     .codec_type        = AVMEDIA_TYPE_AUDIO, | ||||
|     .codec_id          = AV_CODEC_ID_MP3ADU, | ||||
|     .init              = mpa_robust_init, | ||||
|     .alloc             = mpa_robust_new_context, | ||||
|     .free              = mpa_robust_free_context, | ||||
|     .parse_packet      = mpa_robust_parse_packet, | ||||
|     .enc_name          = "mpa-robust", | ||||
| }; | ||||
| @@ -30,7 +30,7 @@ | ||||
| #include "libavutil/version.h" | ||||
|  | ||||
| #define LIBAVFORMAT_VERSION_MAJOR 56 | ||||
| #define LIBAVFORMAT_VERSION_MINOR 13 | ||||
| #define LIBAVFORMAT_VERSION_MINOR 14 | ||||
| #define LIBAVFORMAT_VERSION_MICRO  0 | ||||
|  | ||||
| #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user