From 9b7f932ee568cadfc0f556a061fcc00cb63f9780 Mon Sep 17 00:00:00 2001 From: Martin Storsjö Date: Fri, 3 Oct 2014 21:40:13 +0300 Subject: rtpdec_hevc: Parse out of band vps/sps/pps/sei from fmtp lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are assembled into extradata in the order vps/sps/pps/sei. Signed-off-by: Martin Storsjö --- libavformat/rtpdec_hevc.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 2 deletions(-) (limited to 'libavformat/rtpdec_hevc.c') diff --git a/libavformat/rtpdec_hevc.c b/libavformat/rtpdec_hevc.c index 0ff30e22eb..1bf3c1ac25 100644 --- a/libavformat/rtpdec_hevc.c +++ b/libavformat/rtpdec_hevc.c @@ -21,6 +21,7 @@ */ #include "libavutil/avstring.h" +#include "libavutil/base64.h" #include "avformat.h" #include "rtpdec.h" @@ -34,6 +35,8 @@ struct PayloadContext { int using_donl_field; int profile_id; + uint8_t *sps, *pps, *vps, *sei; + int sps_size, pps_size, vps_size, sei_size; }; static const uint8_t start_sequence[] = { 0x00, 0x00, 0x00, 0x01 }; @@ -85,6 +88,65 @@ static av_cold int hevc_sdp_parse_fmtp_config(AVFormatContext *s, /* sprop-sps: [base64] */ /* sprop-pps: [base64] */ /* sprop-sei: [base64] */ + if (!strcmp(attr, "sprop-vps") || !strcmp(attr, "sprop-sps") || + !strcmp(attr, "sprop-pps") || !strcmp(attr, "sprop-sei")) { + uint8_t **data_ptr; + int *size_ptr; + if (!strcmp(attr, "sprop-vps")) { + data_ptr = &hevc_data->vps; + size_ptr = &hevc_data->vps_size; + } else if (!strcmp(attr, "sprop-sps")) { + data_ptr = &hevc_data->sps; + size_ptr = &hevc_data->sps_size; + } else if (!strcmp(attr, "sprop-pps")) { + data_ptr = &hevc_data->pps; + size_ptr = &hevc_data->pps_size; + } else if (!strcmp(attr, "sprop-sei")) { + data_ptr = &hevc_data->sei; + size_ptr = &hevc_data->sei_size; + } + + while (*value) { + char base64packet[1024]; + uint8_t decoded_packet[1024]; + int packet_size; + char *dst = base64packet; + + while (*value && *value != ',' && + (dst - base64packet) < sizeof(base64packet) - 1) { + *dst++ = *value++; + } + *dst++ = '\0'; + + if (*value == ',') + value++; + + packet_size = av_base64_decode(decoded_packet, base64packet, + sizeof(decoded_packet)); + if (packet_size > 0) { + uint8_t *dest = av_malloc(packet_size + sizeof(start_sequence) + + *size_ptr); + if (!dest) { + av_log(s, AV_LOG_ERROR, + "Unable to allocate memory for extradata!\n"); + return AVERROR(ENOMEM); + } + if (*size_ptr) { + memcpy(dest, *data_ptr, *size_ptr); + av_free(*data_ptr); + } + + memcpy(dest + *size_ptr, start_sequence, + sizeof(start_sequence)); + memcpy(dest + *size_ptr + sizeof(start_sequence), + decoded_packet, packet_size); + + *data_ptr = dest; + *size_ptr += sizeof(start_sequence) + packet_size; + } + } + } + /* max-lsr, max-lps, max-cpb, max-dpb, max-br, max-tr, max-tc */ /* max-fps */ @@ -162,8 +224,41 @@ static av_cold int hevc_parse_sdp_line(AVFormatContext *ctx, int st_index, /* jump beyond the "-" and determine the height value */ codec->height = atoi(sdp_line_ptr + 1); } else if (av_strstart(sdp_line_ptr, "fmtp:", &sdp_line_ptr)) { - return ff_parse_fmtp(ctx, current_stream, hevc_data, sdp_line_ptr, - hevc_sdp_parse_fmtp_config); + int ret = ff_parse_fmtp(ctx, current_stream, hevc_data, sdp_line_ptr, + hevc_sdp_parse_fmtp_config); + if (hevc_data->vps_size || hevc_data->sps_size || + hevc_data->pps_size || hevc_data->sei_size) { + av_freep(&codec->extradata); + codec->extradata_size = hevc_data->vps_size + hevc_data->sps_size + + hevc_data->pps_size + hevc_data->sei_size; + codec->extradata = av_malloc(codec->extradata_size + + FF_INPUT_BUFFER_PADDING_SIZE); + if (!codec->extradata) { + ret = AVERROR(ENOMEM); + codec->extradata_size = 0; + } else { + int pos = 0; + memcpy(codec->extradata + pos, hevc_data->vps, hevc_data->vps_size); + pos += hevc_data->vps_size; + memcpy(codec->extradata + pos, hevc_data->sps, hevc_data->sps_size); + pos += hevc_data->sps_size; + memcpy(codec->extradata + pos, hevc_data->pps, hevc_data->pps_size); + pos += hevc_data->pps_size; + memcpy(codec->extradata + pos, hevc_data->sei, hevc_data->sei_size); + pos += hevc_data->sei_size; + memset(codec->extradata + pos, 0, FF_INPUT_BUFFER_PADDING_SIZE); + } + + av_freep(&hevc_data->vps); + av_freep(&hevc_data->sps); + av_freep(&hevc_data->pps); + av_freep(&hevc_data->sei); + hevc_data->vps_size = 0; + hevc_data->sps_size = 0; + hevc_data->pps_size = 0; + hevc_data->sei_size = 0; + } + return ret; } return 0; -- cgit v1.2.3