diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2014-09-03 14:56:12 +0200 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2014-09-03 14:56:53 +0200 |
commit | 4bc4f6f17079f6861da9a5df336c18e66cdc3848 (patch) | |
tree | 64e838060cff26173940d5999a0894a4eb602b35 | |
parent | dc81c0a0dc7b3f766e5a511a7fab47d61f8a9c03 (diff) | |
parent | 95e177eeb21f3e968aa9353bc69d1946966cc835 (diff) | |
download | ffmpeg-4bc4f6f17079f6861da9a5df336c18e66cdc3848.tar.gz |
Merge commit '95e177eeb21f3e968aa9353bc69d1946966cc835'
* commit '95e177eeb21f3e968aa9353bc69d1946966cc835':
rtpdec: HEVC/H.265 support
Conflicts:
Changelog
libavformat/rtpdec_hevc.c
libavformat/version.h
See: 96b2ba68c4aef4e92b3e9de87d1fb94f2fb659f0
Merged-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r-- | Changelog | 2 | ||||
-rw-r--r-- | libavformat/rtpdec_hevc.c | 165 | ||||
-rw-r--r-- | libavformat/version.h | 2 |
3 files changed, 67 insertions, 102 deletions
@@ -9,7 +9,7 @@ version <next>: - support for using metadata in stream specifiers in fftools - LZMA compression support in TIFF decoder - support for H.261 RTP payload format (RFC 4587) -- support for HEVC/H.265 RTP payload format (draft v6) - depacketizing +- HEVC/H.265 RTP payload format (draft v6) depacketizer - added codecview filter to visualize information exported by some codecs - matroska 3d support thorugh side data diff --git a/libavformat/rtpdec_hevc.c b/libavformat/rtpdec_hevc.c index 4504e1202c..60a97e4bac 100644 --- a/libavformat/rtpdec_hevc.c +++ b/libavformat/rtpdec_hevc.c @@ -17,61 +17,41 @@ * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * */ #include "libavutil/avstring.h" + #include "avformat.h" #include "rtpdec.h" -#define RTP_HEVC_PAYLOAD_HEADER_SIZE 2 -#define RTP_HEVC_FU_HEADER_SIZE 1 -#define RTP_HEVC_DONL_FIELDS_SIZE 2 -#define HEVC_SPECIFIED_NAL_UNIT_TYPES 48 +#define RTP_HEVC_PAYLOAD_HEADER_SIZE 2 +#define RTP_HEVC_FU_HEADER_SIZE 1 +#define RTP_HEVC_DONL_FIELD_SIZE 2 +#define HEVC_SPECIFIED_NAL_UNIT_TYPES 48 +/* SDP out-of-band signaling data */ struct PayloadContext { - /* SDP out-of-band signaling data */ int using_donl_field; int profile_id; - /* debugging */ -#ifdef DEBUG - int packets_received[HEVC_SPECIFIED_NAL_UNIT_TYPES]; -#endif }; -#ifdef DEBUG -#define COUNT_HEVC_NAL_TYPE(data, nal_type) if (nal_type < HEVC_SPECIFIED_NAL_UNIT_TYPES) data->packets_received[(nal_type)]++ -#else -#define COUNT_HEVC_NAL_TYPE(data, nal_type) do { } while (0) -#endif - static const uint8_t start_sequence[] = { 0x00, 0x00, 0x00, 0x01 }; -static PayloadContext *hevc_new_context(void) +static av_cold PayloadContext *hevc_new_context(void) { return av_mallocz(sizeof(PayloadContext)); } static av_cold void hevc_free_context(PayloadContext *data) { -#ifdef DEBUG - int i; - - for (i = 0; i < HEVC_SPECIFIED_NAL_UNIT_TYPES; i++) { - if (data->packets_received[i]) - av_log(NULL, AV_LOG_DEBUG, "Received %d packets of NAL unit type %d\n", - data->packets_received[i], i); - } -#endif - av_free(data); } static av_cold int hevc_init(AVFormatContext *ctx, int st_index, PayloadContext *data) { -#ifdef DEBUG - av_log(ctx, AV_LOG_DEBUG, "hevc_init() for stream %d\n", st_index); -#endif + av_dlog(ctx, "hevc_init() for stream %d\n", st_index); if (st_index < 0) return 0; @@ -82,23 +62,15 @@ static av_cold int hevc_init(AVFormatContext *ctx, int st_index, } static av_cold int hevc_sdp_parse_fmtp_config(AVFormatContext *s, - AVStream *stream, - PayloadContext *hevc_data, - char *attr, char *value) + AVStream *stream, + PayloadContext *hevc_data, + char *attr, char *value) { - -#ifdef DEBUG - av_log(s, AV_LOG_DEBUG, "SDP: fmtp value %s is %s\n", attr, value); -#endif - /* profile-space: 0-3 */ /* profile-id: 0-31 */ if (!strcmp(attr, "profile-id")) { hevc_data->profile_id = atoi(value); - -#ifdef DEBUG - av_log(s, AV_LOG_DEBUG, "SDP: found profile-id: %d\n", hevc_data->profile_id); -#endif + av_dlog(s, "SDP: found profile-id: %d\n", hevc_data->profile_id); } /* tier-flag: 0-1 */ @@ -124,22 +96,18 @@ static av_cold int hevc_sdp_parse_fmtp_config(AVFormatContext *s, value MUST be greater than 0. */ if (!strcmp(attr, "sprop-max-don-diff")) { - if(atoi(value) > 0) + if (atoi(value) > 0) hevc_data->using_donl_field = 1; - -#ifdef DEBUG - av_log(s, AV_LOG_DEBUG, "SDP: found sprop-max-don-diff in SDP, DON field usage is: %d\n", hevc_data->using_donl_field); -#endif + av_dlog(s, "Found sprop-max-don-diff in SDP, DON field usage is: %d\n", + hevc_data->using_donl_field); } /* sprop-depack-buf-nalus: 0-32767 */ if (!strcmp(attr, "sprop-depack-buf-nalus")) { - if(atoi(value) > 0) + if (atoi(value) > 0) hevc_data->using_donl_field = 1; - -#ifdef DEBUG - av_log(s, AV_LOG_DEBUG, "SDP: found sprop-depack-buf-nalus in SDP, DON field usage is: %d\n", hevc_data->using_donl_field); -#endif + av_dlog(s, "Found sprop-depack-buf-nalus in SDP, DON field usage is: %d\n", + hevc_data->using_donl_field); } /* sprop-depack-buf-bytes: 0-4294967295 */ @@ -153,16 +121,12 @@ static av_cold int hevc_sdp_parse_fmtp_config(AVFormatContext *s, } static av_cold int hevc_parse_sdp_line(AVFormatContext *ctx, int st_index, - PayloadContext *hevc_data, const char *line) + PayloadContext *hevc_data, const char *line) { AVStream *current_stream; AVCodecContext *codec; const char *sdp_line_ptr = line; -#ifdef DEBUG - av_log(ctx, AV_LOG_DEBUG, "parse_hevc_sdp_line() got SDP line %s\n", line); -#endif - if (st_index < 0) return 0; @@ -173,9 +137,10 @@ static av_cold int hevc_parse_sdp_line(AVFormatContext *ctx, int st_index, char str_video_width[50]; char *str_video_width_ptr = str_video_width; - /** + /* * parse "a=framesize:96 320-240" */ + /* ignore spaces */ while (*sdp_line_ptr && *sdp_line_ptr == ' ') sdp_line_ptr++; @@ -186,19 +151,19 @@ static av_cold int hevc_parse_sdp_line(AVFormatContext *ctx, int st_index, while (*sdp_line_ptr && *sdp_line_ptr == ' ') sdp_line_ptr++; /* extract the actual video resolution description */ - while (*sdp_line_ptr && *sdp_line_ptr != '-' && (str_video_width_ptr - str_video_width) < sizeof(str_video_width) - 1) + while (*sdp_line_ptr && *sdp_line_ptr != '-' && + (str_video_width_ptr - str_video_width) < sizeof(str_video_width) - 1) *str_video_width_ptr++ = *sdp_line_ptr++; /* add trailing zero byte */ *str_video_width_ptr = '\0'; /* determine the width value */ codec->width = atoi(str_video_width); - // jump beyond the "-" and determine the height value + /* 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); - } else if (av_strstart(sdp_line_ptr, "cliprect:", &sdp_line_ptr)) { - // could use this if we wanted. + return ff_parse_fmtp(ctx, current_stream, hevc_data, sdp_line_ptr, + hevc_sdp_parse_fmtp_config); } return 0; @@ -213,10 +178,10 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx int tid, lid, nal_type; int first_fragment, last_fragment, fu_type; uint8_t new_nal_header[2]; - int res=0; + int res = 0; - /* sanity check for size of input packet */ - if (len < 3 /* 2 bytes header and 1 byte payload at least */) { + /* sanity check for size of input packet: 1 byte payload at least */ + if (len < RTP_HEVC_PAYLOAD_HEADER_SIZE + 1) { av_log(ctx, AV_LOG_ERROR, "Too short RTP/HEVC packet, got %d bytes\n", len); return AVERROR_INVALIDDATA; } @@ -240,40 +205,35 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx tid = buf[1] & 0x07; /* sanity check for correct layer ID */ - if(lid){ + if (lid) { /* future scalable or 3D video coding extensions */ - av_log(ctx, AV_LOG_ERROR, "Multi-layer HEVC coding is not supported yet, a patch is welcome\n"); + avpriv_report_missing_feature(ctx, "Multi-layer HEVC coding\n"); return AVERROR_PATCHWELCOME; } /* sanity check for correct temporal ID */ - if(!tid){ + if (!tid) { av_log(ctx, AV_LOG_ERROR, "Illegal temporal ID in RTP/HEVC packet\n"); return AVERROR_INVALIDDATA; } /* sanity check for correct NAL unit type */ - if (nal_type > 50){ + if (nal_type > 50) { av_log(ctx, AV_LOG_ERROR, "Unsupported (HEVC) NAL type (%d)\n", nal_type); return AVERROR_INVALIDDATA; } -#ifdef DEBUG - av_log(ctx, AV_LOG_DEBUG, "hevc_handle_packet() got NAL type %d with %d bytes\n", nal_type, len); -#endif - - switch(nal_type) - { + switch (nal_type) { /* aggregated packets (AP) */ case 48: /* pass the HEVC payload header */ buf += RTP_HEVC_PAYLOAD_HEADER_SIZE; len -= RTP_HEVC_PAYLOAD_HEADER_SIZE; - /* pass the HEVC DONL fields */ - if(rtp_hevc_ctx->using_donl_field){ - buf += RTP_HEVC_DONL_FIELDS_SIZE; - len -= RTP_HEVC_DONL_FIELDS_SIZE; + /* pass the HEVC DONL field */ + if (rtp_hevc_ctx->using_donl_field) { + buf += RTP_HEVC_DONL_FIELD_SIZE; + len -= RTP_HEVC_DONL_FIELD_SIZE; } /* fall-through */ @@ -287,6 +247,14 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx case 39: /* single NAL unit packet */ default: + /* sanity check for size of input packet: 1 byte payload at least */ + if (len < 1) { + av_log(ctx, AV_LOG_ERROR, + "Too short RTP/HEVC packet, got %d bytes of NAL unit type %d\n", + len, nal_type); + return AVERROR_INVALIDDATA; + } + /* create A/V packet */ if ((res = av_new_packet(pkt, sizeof(start_sequence) + len)) < 0) return res; @@ -295,8 +263,6 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx /* A/V packet: copy NAL unit data */ memcpy(pkt->data + sizeof(start_sequence), buf, len); - COUNT_HEVC_NAL_TYPE(rtp_hevc_ctx, nal_type); - break; /* fragmentation unit (FU) */ case 49: @@ -304,7 +270,9 @@ 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 0 1 2 3 4 5 6 7 @@ -317,22 +285,20 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx FuType: 6 bits */ first_fragment = buf[0] & 0x80; - last_fragment = buf[0] & 0x40; - fu_type = buf[0] & 0x3f; + last_fragment = buf[0] & 0x40; + fu_type = buf[0] & 0x3f; /* pass the HEVC FU header */ buf += RTP_HEVC_FU_HEADER_SIZE; len -= RTP_HEVC_FU_HEADER_SIZE; - /* pass the HEVC DONL fields */ - if(rtp_hevc_ctx->using_donl_field){ - buf += RTP_HEVC_DONL_FIELDS_SIZE; - len -= RTP_HEVC_DONL_FIELDS_SIZE; + /* pass the HEVC DONL field */ + if (rtp_hevc_ctx->using_donl_field) { + buf += RTP_HEVC_DONL_FIELD_SIZE; + len -= RTP_HEVC_DONL_FIELD_SIZE; } -#ifdef DEBUG - av_log(ctx, AV_LOG_DEBUG, " FU type %d with %d bytes\n", fu_type, len); -#endif + av_dlog(ctx, " FU type %d with %d bytes\n", fu_type, len); if (len > 0) { new_nal_header[0] = (rtp_pl[0] & 0x81) | (fu_type << 1); @@ -340,7 +306,7 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx /* start fragment vs. subsequent fragments */ if (first_fragment) { - if(!last_fragment){ + if (!last_fragment) { /* create A/V packet which is big enough */ if ((res = av_new_packet(pkt, sizeof(start_sequence) + sizeof(new_nal_header) + len)) < 0) return res; @@ -350,7 +316,7 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx memcpy(pkt->data + sizeof(start_sequence), new_nal_header, sizeof(new_nal_header)); /* A/V packet: copy NAL unit data */ memcpy(pkt->data + sizeof(start_sequence) + sizeof(new_nal_header), buf, len); - }else{ + } else { av_log(ctx, AV_LOG_ERROR, "Illegal combination of S and E bit in RTP/HEVC packet\n"); res = AVERROR_INVALIDDATA; } @@ -362,19 +328,18 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx memcpy(pkt->data, buf, len); } } else { - av_log(ctx, AV_LOG_ERROR, "Too short data for (HEVC) NAL unit, got %d bytes\n", len); + /* 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(!res){ - COUNT_HEVC_NAL_TYPE(rtp_hevc_ctx, fu_type); - } - break; /* PACI packet */ case 50: /* Temporal scalability control information (TSCI) */ - av_log(ctx, AV_LOG_ERROR, "PACI packets for RTP/HEVC are not supported yet, a patch is welcome\n"); + avpriv_report_missing_feature(ctx, "PACI packets for RTP/HEVC\n"); res = AVERROR_PATCHWELCOME; break; } @@ -398,7 +363,7 @@ RTPDynamicProtocolHandler ff_hevc_dynamic_handler = { RTPDynamicProtocolHandler ff_h265_dynamic_handler = { .enc_name = "H265", .codec_type = AVMEDIA_TYPE_VIDEO, - .codec_id = AV_CODEC_ID_H265, + .codec_id = AV_CODEC_ID_HEVC, .init = hevc_init, .parse_sdp_a_line = hevc_parse_sdp_line, .alloc = hevc_new_context, diff --git a/libavformat/version.h b/libavformat/version.h index b802bbbaa8..44810a2272 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -30,7 +30,7 @@ #include "libavutil/version.h" #define LIBAVFORMAT_VERSION_MAJOR 56 -#define LIBAVFORMAT_VERSION_MINOR 3 +#define LIBAVFORMAT_VERSION_MINOR 4 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ |