X-Git-Url: https://git.piment-noir.org/?p=deb_ffmpeg.git;a=blobdiff_plain;f=ffmpeg%2Flibavformat%2Frtpdec_hevc.c;h=ac4c7656d4abb714af81c024d3b5540c388cfb8f;hp=60a97e4bac19dc36311f3d8aa77f6c3e36b3e6cf;hb=f6fa7814ccfe3e76514b36cf04f5cd3cb657c8cf;hpb=2ba45a602cbfa7b771effba9b11bb4245c21bc00 diff --git a/ffmpeg/libavformat/rtpdec_hevc.c b/ffmpeg/libavformat/rtpdec_hevc.c index 60a97e4..ac4c765 100644 --- a/ffmpeg/libavformat/rtpdec_hevc.c +++ b/ffmpeg/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,61 @@ 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 decoded_packet_size; + char *dst = base64packet; + + while (*value && *value != ',' && + (dst - base64packet) < sizeof(base64packet) - 1) { + *dst++ = *value++; + } + *dst++ = '\0'; + + if (*value == ',') + value++; + + decoded_packet_size = av_base64_decode(decoded_packet, base64packet, + sizeof(decoded_packet)); + if (decoded_packet_size > 0) { + uint8_t *tmp = av_realloc(*data_ptr, decoded_packet_size + + sizeof(start_sequence) + *size_ptr); + if (!tmp) { + av_log(s, AV_LOG_ERROR, + "Unable to allocate memory for extradata!\n"); + return AVERROR(ENOMEM); + } + *data_ptr = tmp; + + memcpy(*data_ptr + *size_ptr, start_sequence, + sizeof(start_sequence)); + memcpy(*data_ptr + *size_ptr + sizeof(start_sequence), + decoded_packet, decoded_packet_size); + + *size_ptr += sizeof(start_sequence) + decoded_packet_size; + } + } + } + /* max-lsr, max-lps, max-cpb, max-dpb, max-br, max-tr, max-tc */ /* max-fps */ @@ -162,8 +220,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; @@ -270,8 +361,6 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx buf += RTP_HEVC_PAYLOAD_HEADER_SIZE; len -= RTP_HEVC_PAYLOAD_HEADER_SIZE; - if (len < 1) - return AVERROR_INVALIDDATA; /* decode the FU header @@ -300,6 +389,7 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx av_dlog(ctx, " FU type %d with %d bytes\n", fu_type, len); + /* sanity check for size of input packet: 1 byte payload at least */ if (len > 0) { new_nal_header[0] = (rtp_pl[0] & 0x81) | (fu_type << 1); new_nal_header[1] = rtp_pl[1]; @@ -328,11 +418,14 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx memcpy(pkt->data, buf, len); } } else { - /* sanity check for size of input packet: 1 byte payload at least */ - av_log(ctx, AV_LOG_ERROR, - "Too short RTP/HEVC packet, got %d bytes of NAL unit type %d\n", - len, nal_type); - res = AVERROR_INVALIDDATA; + if (len < 0) { + av_log(ctx, AV_LOG_ERROR, + "Too short RTP/HEVC packet, got %d bytes of NAL unit type %d\n", + len, nal_type); + res = AVERROR_INVALIDDATA; + } else { + res = AVERROR(EAGAIN); + } } break; @@ -350,17 +443,6 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx } RTPDynamicProtocolHandler ff_hevc_dynamic_handler = { - .enc_name = "HEVC", - .codec_type = AVMEDIA_TYPE_VIDEO, - .codec_id = AV_CODEC_ID_HEVC, - .init = hevc_init, - .parse_sdp_a_line = hevc_parse_sdp_line, - .alloc = hevc_new_context, - .free = hevc_free_context, - .parse_packet = hevc_handle_packet -}; - -RTPDynamicProtocolHandler ff_h265_dynamic_handler = { .enc_name = "H265", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_HEVC,