static int sdp_parse_fmtp_config_h264(AVStream *stream,
PayloadContext *h264_data,
char *attr, char *value)
{
AVCodecContext *codec = stream->codec;
assert(codec->codec_id == AV_CODEC_ID_H264);
assert(h264_data != NULL);
if (!strcmp(attr, "packetization-mode")) { // parse packetation-mode in fmtp, please see notes below, it is clear that ffmpeg not support interleaved mode.
av_log(codec, AV_LOG_DEBUG, "RTP Packetization Mode: %d\n", atoi(value));
h264_data->packetization_mode = atoi(value);
/*
* Packetization Mode:
* 0 or not present: Single NAL mode (Only nals from 1-23 are allowed)
* 1: Non-interleaved Mode: 1-23, 24 (STAP-A), 28 (FU-A) are allowed.
* 2: Interleaved Mode: 25 (STAP-B), 26 (MTAP16), 27 (MTAP24), 28 (FU-A),
* and 29 (FU-B) are allowed.
*/
if (h264_data->packetization_mode > 1)
av_log(codec, AV_LOG_ERROR,
"Interleaved RTP mode is not supported yet.\n");
} else if (!strcmp(attr, "profile-level-id")) { // parse profile and level of h264
if (strlen(value) == 6) {
char buffer[3];
// 6 characters=3 bytes, in hex.
uint8_t profile_idc;
uint8_t profile_iop;
uint8_t level_idc;
buffer[0] = value[0];
buffer[1] = value[1];
buffer[2] = '\0';
profile_idc = strtol(buffer, NULL, 16);
buffer[0] = value[2];
buffer[1] = value[3];
profile_iop = strtol(buffer, NULL, 16);
buffer[0] = value[4];
buffer[1] = value[5];
level_idc = strtol(buffer, NULL, 16);
av_log(codec, AV_LOG_DEBUG,
"RTP Profile IDC: %x Profile IOP: %x Level: %x\n",
profile_idc, profile_iop, level_idc);
h264_data->profile_idc = profile_idc;
h264_data->profile_iop = profile_iop;
h264_data->level_idc = level_idc;
}
} else if (!strcmp(attr, "sprop-parameter-sets")) { // parse sps of h264
codec->extradata_size = 0;
av_freep(&codec->extradata);
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) +
codec->extradata_size +
FF_INPUT_BUFFER_PADDING_SIZE);
if (!dest) {
av_log(codec, AV_LOG_ERROR,
"Unable to allocate memory for extradata!\n");
return AVERROR(ENOMEM);
}
if (codec->extradata_size) {
memcpy(dest, codec->extradata, codec->extradata_size);
av_free(codec->extradata);
}
memcpy(dest + codec->extradata_size, start_sequence,
sizeof(start_sequence));
memcpy(dest + codec->extradata_size + sizeof(start_sequence),
decoded_packet, packet_size);
memset(dest + codec->extradata_size + sizeof(start_sequence) +
packet_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
codec->extradata = dest;
codec->extradata_size += sizeof(start_sequence) + packet_size;
}
}
av_log(codec, AV_LOG_DEBUG, "Extradata set to %p (size: %d)!\n",
codec->extradata, codec->extradata_size);
}
return 0;
}
PayloadContext *h264_data,
char *attr, char *value)
{
AVCodecContext *codec = stream->codec;
assert(codec->codec_id == AV_CODEC_ID_H264);
assert(h264_data != NULL);
if (!strcmp(attr, "packetization-mode")) { // parse packetation-mode in fmtp, please see notes below, it is clear that ffmpeg not support interleaved mode.
av_log(codec, AV_LOG_DEBUG, "RTP Packetization Mode: %d\n", atoi(value));
h264_data->packetization_mode = atoi(value);
/*
* Packetization Mode:
* 0 or not present: Single NAL mode (Only nals from 1-23 are allowed)
* 1: Non-interleaved Mode: 1-23, 24 (STAP-A), 28 (FU-A) are allowed.
* 2: Interleaved Mode: 25 (STAP-B), 26 (MTAP16), 27 (MTAP24), 28 (FU-A),
* and 29 (FU-B) are allowed.
*/
if (h264_data->packetization_mode > 1)
av_log(codec, AV_LOG_ERROR,
"Interleaved RTP mode is not supported yet.\n");
} else if (!strcmp(attr, "profile-level-id")) { // parse profile and level of h264
if (strlen(value) == 6) {
char buffer[3];
// 6 characters=3 bytes, in hex.
uint8_t profile_idc;
uint8_t profile_iop;
uint8_t level_idc;
buffer[0] = value[0];
buffer[1] = value[1];
buffer[2] = '\0';
profile_idc = strtol(buffer, NULL, 16);
buffer[0] = value[2];
buffer[1] = value[3];
profile_iop = strtol(buffer, NULL, 16);
buffer[0] = value[4];
buffer[1] = value[5];
level_idc = strtol(buffer, NULL, 16);
av_log(codec, AV_LOG_DEBUG,
"RTP Profile IDC: %x Profile IOP: %x Level: %x\n",
profile_idc, profile_iop, level_idc);
h264_data->profile_idc = profile_idc;
h264_data->profile_iop = profile_iop;
h264_data->level_idc = level_idc;
}
} else if (!strcmp(attr, "sprop-parameter-sets")) { // parse sps of h264
codec->extradata_size = 0;
av_freep(&codec->extradata);
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) +
codec->extradata_size +
FF_INPUT_BUFFER_PADDING_SIZE);
if (!dest) {
av_log(codec, AV_LOG_ERROR,
"Unable to allocate memory for extradata!\n");
return AVERROR(ENOMEM);
}
if (codec->extradata_size) {
memcpy(dest, codec->extradata, codec->extradata_size);
av_free(codec->extradata);
}
memcpy(dest + codec->extradata_size, start_sequence,
sizeof(start_sequence));
memcpy(dest + codec->extradata_size + sizeof(start_sequence),
decoded_packet, packet_size);
memset(dest + codec->extradata_size + sizeof(start_sequence) +
packet_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
codec->extradata = dest;
codec->extradata_size += sizeof(start_sequence) + packet_size;
}
}
av_log(codec, AV_LOG_DEBUG, "Extradata set to %p (size: %d)!\n",
codec->extradata, codec->extradata_size);
}
return 0;
}