rtpdec_hevc: Parse out of band vps/sps/pps/sei from fmtp lines

These are assembled into extradata in the order vps/sps/pps/sei.

Signed-off-by: Martin Storsjö <martin@martin.st>
This commit is contained in:
Martin Storsjö 2014-10-03 21:40:13 +03:00
parent 557d4c4eca
commit 9b7f932ee5
1 changed files with 97 additions and 2 deletions

View File

@ -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;