summaryrefslogtreecommitdiff
path: root/libavformat/rtpdec_hevc.c
diff options
context:
space:
mode:
authorMartin Storsjö <martin@martin.st>2014-10-03 21:40:13 +0300
committerMartin Storsjö <martin@martin.st>2014-10-15 12:12:02 +0300
commit9b7f932ee568cadfc0f556a061fcc00cb63f9780 (patch)
tree30746f305d6ec6815cfc7e8c35bc882cf749c3bd /libavformat/rtpdec_hevc.c
parent557d4c4ecae080729e68df54ed2bd8420d0f037a (diff)
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>
Diffstat (limited to 'libavformat/rtpdec_hevc.c')
-rw-r--r--libavformat/rtpdec_hevc.c99
1 files changed, 97 insertions, 2 deletions
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;