diff --git a/webrtc/common_types.h b/webrtc/common_types.h index 6892a83f0..193e2818c 100644 --- a/webrtc/common_types.h +++ b/webrtc/common_types.h @@ -587,10 +587,24 @@ struct VideoCodecVP8 { } }; +// H264 specific. +struct VideoCodecH264 +{ + VideoCodecProfile profile; + bool frameDroppingOn; + int keyFrameInterval; + // These are NULL/0 if not externally negotiated. + const uint8_t* spsData; + size_t spsLen; + const uint8_t* ppsData; + size_t ppsLen; +}; + // Video codec types enum VideoCodecType { kVideoCodecVP8, + kVideoCodecH264, kVideoCodecI420, kVideoCodecRED, kVideoCodecULPFEC, @@ -601,6 +615,7 @@ enum VideoCodecType union VideoCodecUnion { VideoCodecVP8 VP8; + VideoCodecH264 H264; }; diff --git a/webrtc/engine_configurations.h b/webrtc/engine_configurations.h index be858b8e5..e9f23097f 100644 --- a/webrtc/engine_configurations.h +++ b/webrtc/engine_configurations.h @@ -51,6 +51,7 @@ #define VIDEOCODEC_I420 #define VIDEOCODEC_VP8 +#define VIDEOCODEC_H264 // ============================================================================ // VoiceEngine diff --git a/webrtc/modules/interface/module_common_types.h b/webrtc/modules/interface/module_common_types.h index 2c9470710..e37313c9d 100644 --- a/webrtc/modules/interface/module_common_types.h +++ b/webrtc/modules/interface/module_common_types.h @@ -75,14 +75,22 @@ struct RTPVideoHeaderVP8 { bool beginningOfPartition; // True if this packet is the first // in a VP8 partition. Otherwise false }; + +struct RTPVideoHeaderH264 { + uint8_t nalu_header; + bool single_nalu; +}; + union RTPVideoTypeHeader { RTPVideoHeaderVP8 VP8; + RTPVideoHeaderH264 H264; }; enum RtpVideoCodecTypes { kRtpVideoNone, kRtpVideoGeneric, - kRtpVideoVp8 + kRtpVideoVp8, + kRtpVideoH264 }; struct RTPVideoHeader { uint16_t width; // size diff --git a/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc b/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc index db2e4cd31..26db8f329 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc @@ -434,6 +434,8 @@ class RTPPayloadVideoStrategy : public RTPPayloadStrategy { RtpVideoCodecTypes videoType = kRtpVideoGeneric; if (ModuleRTPUtility::StringCompare(payloadName, "VP8", 3)) { videoType = kRtpVideoVp8; + } else if (ModuleRTPUtility::StringCompare(payloadName, "H264", 4)) { + videoType = kRtpVideoH264; } else if (ModuleRTPUtility::StringCompare(payloadName, "I420", 4)) { videoType = kRtpVideoGeneric; } else if (ModuleRTPUtility::StringCompare(payloadName, "ULPFEC", 6)) { diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc b/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc index 5bb519f62..261599163 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc @@ -113,6 +113,8 @@ int32_t RTPReceiverVideo::ParseVideoCodecSpecific( return ReceiveGenericCodec(rtp_header, payload_data, payload_data_length); case kRtpVideoVp8: return ReceiveVp8Codec(rtp_header, payload_data, payload_data_length); + case kRtpVideoH264: + assert(false); // Not yet supported. case kRtpVideoNone: break; } diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc index 5d8ae1665..e4138ff55 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc @@ -90,6 +90,8 @@ int32_t RTPSenderVideo::RegisterVideoPayload( RtpVideoCodecTypes videoType = kRtpVideoGeneric; if (ModuleRTPUtility::StringCompare(payloadName, "VP8",3)) { videoType = kRtpVideoVp8; + } else if (ModuleRTPUtility::StringCompare(payloadName, "H264", 4)) { + videoType = kRtpVideoH264; } else if (ModuleRTPUtility::StringCompare(payloadName, "I420", 4)) { videoType = kRtpVideoGeneric; } else { diff --git a/webrtc/modules/video_coding/main/interface/video_coding_defines.h b/webrtc/modules/video_coding/main/interface/video_coding_defines.h index fab91afd3..c5f93cb17 100644 --- a/webrtc/modules/video_coding/main/interface/video_coding_defines.h +++ b/webrtc/modules/video_coding/main/interface/video_coding_defines.h @@ -40,6 +40,7 @@ namespace webrtc { #define VCM_ULPFEC_PAYLOAD_TYPE 97 #define VCM_VP8_PAYLOAD_TYPE 100 #define VCM_I420_PAYLOAD_TYPE 124 +#define VCM_H264_PAYLOAD_TYPE 127 enum VCMVideoProtection { kProtectionNack, // Both send-side and receive-side diff --git a/webrtc/modules/video_coding/main/source/codec_database.cc b/webrtc/modules/video_coding/main/source/codec_database.cc index e7a9d91b1..7e26bea4e 100644 --- a/webrtc/modules/video_coding/main/source/codec_database.cc +++ b/webrtc/modules/video_coding/main/source/codec_database.cc @@ -102,6 +102,30 @@ bool VCMCodecDataBase::Codec(int list_id, return true; } #endif +#ifdef VIDEOCODEC_H264 + case VCM_H264_IDX: { + strncpy(settings->plName, "H264", 5); + settings->codecType = kVideoCodecH264; + // 96 to 127 dynamic payload types for video codecs. + settings->plType = VCM_H264_PAYLOAD_TYPE; + settings->startBitrate = 100; + settings->minBitrate = VCM_MIN_BITRATE; + settings->maxBitrate = 0; + settings->maxFramerate = VCM_DEFAULT_FRAME_RATE; + settings->width = VCM_DEFAULT_CODEC_WIDTH; + settings->height = VCM_DEFAULT_CODEC_HEIGHT; + settings->numberOfSimulcastStreams = 0; + settings->qpMax = 56; + settings->codecSpecific.H264.profile = kProfileBase; + settings->codecSpecific.H264.frameDroppingOn = true; + settings->codecSpecific.H264.keyFrameInterval = 3000; + settings->codecSpecific.H264.spsData = NULL; + settings->codecSpecific.H264.spsLen = 0; + settings->codecSpecific.H264.ppsData = NULL; + settings->codecSpecific.H264.ppsLen = 0; + return true; + } +#endif #ifdef VIDEOCODEC_I420 case VCM_I420_IDX: { strncpy(settings->plName, "I420", 5); @@ -316,8 +340,7 @@ bool VCMCodecDataBase::RequiresEncoderReset(const VideoCodec& new_send_codec) { case kVideoCodecVP8: if (memcmp(&new_send_codec.codecSpecific.VP8, &send_codec_.codecSpecific.VP8, - sizeof(new_send_codec.codecSpecific.VP8)) != - 0) { + sizeof(new_send_codec.codecSpecific.VP8)) != 0) { return true; } break; @@ -327,6 +350,12 @@ bool VCMCodecDataBase::RequiresEncoderReset(const VideoCodec& new_send_codec) { case kVideoCodecI420: case kVideoCodecRED: case kVideoCodecULPFEC: + case kVideoCodecH264: + if (memcmp(&new_send_codec.codecSpecific.H264, + &send_codec_.codecSpecific.H264, + sizeof(new_send_codec.codecSpecific.H264)) != 0) { + return true; + } break; // Unknown codec type, reset just to be sure. case kVideoCodecUnknown: @@ -619,6 +648,7 @@ VCMGenericDecoder* VCMCodecDataBase::CreateDecoder(VideoCodecType type) const { return new VCMGenericDecoder(*(new I420Decoder)); #endif default: + LOG(LS_WARNING) << "No internal decoder of this type exists."; return NULL; } } diff --git a/webrtc/modules/video_coding/main/source/internal_defines.h b/webrtc/modules/video_coding/main/source/internal_defines.h index efc6d8dd1..1128312be 100644 --- a/webrtc/modules/video_coding/main/source/internal_defines.h +++ b/webrtc/modules/video_coding/main/source/internal_defines.h @@ -39,10 +39,15 @@ inline uint32_t MaskWord64ToUWord32(int64_t w64) #else #define VCM_VP8_IDX VCM_NO_CODEC_IDX #endif -#ifdef VIDEOCODEC_I420 - #define VCM_I420_IDX VCM_VP8_IDX + 1 +#ifdef VIDEOCODEC_H264 + #define VCM_H264_IDX VCM_VP8_IDX + 1 #else - #define VCM_I420_IDX VCM_VP8_IDX + #define VCM_H264_IDX VCM_VP8_IDX +#endif +#ifdef VIDEOCODEC_I420 + #define VCM_I420_IDX VCM_H264_IDX + 1 +#else + #define VCM_I420_IDX VCM_H264_IDX #endif #define VCM_NUM_VIDEO_CODECS_AVAILABLE VCM_I420_IDX + 1 diff --git a/webrtc/test/encoder_settings.cc b/webrtc/test/encoder_settings.cc index 5193be65f..9842d1ed1 100644 --- a/webrtc/test/encoder_settings.cc +++ b/webrtc/test/encoder_settings.cc @@ -59,9 +59,13 @@ VideoCodec CreateDecoderVideoCodec( codec.plType = encoder_settings.payload_type; strcpy(codec.plName, encoder_settings.payload_name.c_str()); - codec.codecType = - (encoder_settings.payload_name == "VP8" ? kVideoCodecVP8 - : kVideoCodecGeneric); + if (encoder_settings.payload_name == "VP8") { + codec.codecType = kVideoCodecVP8; + } else if (encoder_settings.payload_name == "H264") { + codec.codecType = kVideoCodecH264; + } else { + codec.codecType = kVideoCodecGeneric; + } if (codec.codecType == kVideoCodecVP8) { codec.codecSpecific.VP8.resilience = kResilientStream; @@ -73,6 +77,12 @@ VideoCodec CreateDecoderVideoCodec( codec.codecSpecific.VP8.keyFrameInterval = 3000; } + if (codec.codecType == kVideoCodecH264) { + codec.codecSpecific.H264.profile = kProfileBase; + codec.codecSpecific.H264.frameDroppingOn = true; + codec.codecSpecific.H264.keyFrameInterval = 3000; + } + codec.width = 320; codec.height = 180; codec.startBitrate = codec.minBitrate = codec.maxBitrate = 300; diff --git a/webrtc/video/loopback.cc b/webrtc/video/loopback.cc index ea65ebb42..276f1d45c 100644 --- a/webrtc/video/loopback.cc +++ b/webrtc/video/loopback.cc @@ -48,6 +48,9 @@ size_t StartBitrate() { return static_cast(FLAGS_start_bitrate); } DEFINE_int32(max_bitrate, 800, "Maximum video bitrate."); size_t MaxBitrate() { return static_cast(FLAGS_max_bitrate); } + +DEFINE_string(codec, "VP8", "Video codec to use."); +std::string Codec() { return static_cast(FLAGS_codec); } } // namespace flags static const uint32_t kSendSsrc = 0x654321; @@ -72,10 +75,16 @@ void Loopback() { send_config.rtp.ssrcs.push_back(kSendSsrc); send_config.local_renderer = local_preview.get(); - - scoped_ptr encoder(VP8Encoder::Create()); + scoped_ptr encoder; + if (flags::Codec() == "VP8") { + encoder.reset(VP8Encoder::Create()); + } else { + // Codec not supported. + assert(false && "Codec not supported!"); + return; + } send_config.encoder_settings.encoder = encoder.get(); - send_config.encoder_settings.payload_name = "VP8"; + send_config.encoder_settings.payload_name = flags::Codec(); send_config.encoder_settings.payload_type = 124; std::vector video_streams = test::CreateVideoStreams(1); VideoStream* stream = &video_streams[0]; diff --git a/webrtc/video_engine/test/auto_test/source/vie_autotest.cc b/webrtc/video_engine/test/auto_test/source/vie_autotest.cc index 188567cb1..fb1a46f2b 100644 --- a/webrtc/video_engine/test/auto_test/source/vie_autotest.cc +++ b/webrtc/video_engine/test/auto_test/source/vie_autotest.cc @@ -101,6 +101,9 @@ void ViEAutoTest::PrintVideoCodec(const webrtc::VideoCodec videoCodec) case webrtc::kVideoCodecI420: ViETest::Log("\tcodecType: I420"); break; + case webrtc::kVideoCodecH264: + ViETest::Log("\tcodecType: H264"); + break; case webrtc::kVideoCodecRED: ViETest::Log("\tcodecType: RED"); break; diff --git a/webrtc/video_engine/vie_codec_impl.cc b/webrtc/video_engine/vie_codec_impl.cc index 3ba56de54..050958e22 100644 --- a/webrtc/video_engine/vie_codec_impl.cc +++ b/webrtc/video_engine/vie_codec_impl.cc @@ -69,6 +69,18 @@ static void LogCodec(const VideoCodec& codec) { << ", qp max " << codec.simulcastStream[idx].qpMax; } + } else if (codec.codecType == kVideoCodecH264) { + LOG(LS_INFO) << "H264 specific settings"; + LOG(LS_INFO) << "profile: " + << codec.codecSpecific.H264.profile + << ", framedropping: " + << codec.codecSpecific.H264.frameDroppingOn + << ", keyFrameInterval: " + << codec.codecSpecific.H264.keyFrameInterval + << ", spslen: " + << codec.codecSpecific.H264.spsLen + << ", ppslen: " + << codec.codecSpecific.H264.ppsLen; } } @@ -629,7 +641,9 @@ bool ViECodecImpl::CodecValid(const VideoCodec& video_codec) { } else if ((video_codec.codecType == kVideoCodecVP8 && strncmp(video_codec.plName, "VP8", 4) == 0) || (video_codec.codecType == kVideoCodecI420 && - strncmp(video_codec.plName, "I420", 4) == 0)) { + strncmp(video_codec.plName, "I420", 4) == 0) || + (video_codec.codecType == kVideoCodecH264 && + strncmp(video_codec.plName, "H264", 4) == 0)) { // OK. } else if (video_codec.codecType != kVideoCodecGeneric) { LOG(LS_ERROR) << "Codec type and name mismatch.";