diff --git a/src/modules/video_coding/codecs/vp8/Android.mk b/src/modules/video_coding/codecs/vp8/Android.mk index eb6c1af88..7db37ec76 100644 --- a/src/modules/video_coding/codecs/vp8/Android.mk +++ b/src/modules/video_coding/codecs/vp8/Android.mk @@ -18,7 +18,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_CPP_EXTENSION := .cc LOCAL_SRC_FILES := \ reference_picture_selection.cc \ - vp8.cc + vp8_impl.cc # Flags passed to both C and C++ files. LOCAL_CFLAGS := \ diff --git a/src/modules/video_coding/codecs/vp8/include/vp8.h b/src/modules/video_coding/codecs/vp8/include/vp8.h index e6416f504..d1f7b7698 100644 --- a/src/modules/video_coding/codecs/vp8/include/vp8.h +++ b/src/modules/video_coding/codecs/vp8/include/vp8.h @@ -7,142 +7,21 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. * - * WEBRTC VP8 wrapper interface + * WEBRTC VP8 wrapper interface */ -#ifndef WEBRTC_MODULES_VIDEO_CODING_CODECS_VP8_H_ -#define WEBRTC_MODULES_VIDEO_CODING_CODECS_VP8_H_ +#ifndef WEBRTC_MODULES_VIDEO_CODING_CODECS_VP8_INCLUDE_VP8_H_ +#define WEBRTC_MODULES_VIDEO_CODING_CODECS_VP8_INCLUDE_VP8_H_ -#include "video_codec_interface.h" +#include "modules/video_coding/codecs/interface/video_codec_interface.h" -// VPX forward declaration -typedef struct vpx_codec_ctx vpx_codec_ctx_t; -typedef struct vpx_codec_ctx vpx_dec_ctx_t; -typedef struct vpx_codec_enc_cfg vpx_codec_enc_cfg_t; -typedef struct vpx_image vpx_image_t; -typedef struct vpx_ref_frame vpx_ref_frame_t; -struct vpx_codec_cx_pkt; - -namespace webrtc -{ -class TemporalLayers; -class ReferencePictureSelection; +namespace webrtc { class VP8Encoder : public VideoEncoder { public: static VP8Encoder* Create(); - virtual ~VP8Encoder(); - - // Free encoder memory. - // - // Return value : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise. - virtual int Release(); - - // Initialize the encoder with the information from the codecSettings - // - // Input: - // - codec_settings : Codec settings - // - number_of_cores : Number of cores available for the encoder - // - max_payload_size : The maximum size each payload is allowed - // to have. Usually MTU - overhead. - // - // Return value : Set bit rate if OK - // <0 - Errors: - // WEBRTC_VIDEO_CODEC_ERR_PARAMETER - // WEBRTC_VIDEO_CODEC_ERR_SIZE - // WEBRTC_VIDEO_CODEC_LEVEL_EXCEEDED - // WEBRTC_VIDEO_CODEC_MEMORY - // WEBRTC_VIDEO_CODEC_ERROR - virtual int InitEncode(const VideoCodec* codec_settings, - int number_of_cores, - uint32_t max_payload_size); - - // Encode an I420 image (as a part of a video stream). The encoded image - // will be returned to the user through the encode complete callback. - // - // Input: - // - input_image : Image to be encoded - // - frame_types : Frame type to be generated by the encoder. - // - // Return value : WEBRTC_VIDEO_CODEC_OK if OK - // <0 - Errors: - // WEBRTC_VIDEO_CODEC_ERR_PARAMETER - // WEBRTC_VIDEO_CODEC_MEMORY - // WEBRTC_VIDEO_CODEC_ERROR - // WEBRTC_VIDEO_CODEC_TIMEOUT - - virtual int Encode(const VideoFrame& input_image, - const CodecSpecificInfo* codec_specific_info, - const VideoFrameType frame_type); - - // Register an encode complete callback object. - // - // Input: - // - callback : Callback object which handles encoded images. - // - // Return value : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise. - virtual int RegisterEncodeCompleteCallback(EncodedImageCallback* callback); - - // Inform the encoder of the new packet loss rate and the round-trip time of - // the network. - // - // - packet_loss : Fraction lost - // (loss rate in percent = 100 * packetLoss / 255) - // - rtt : Round-trip time in milliseconds - // Return value : WEBRTC_VIDEO_CODEC_OK if OK - // <0 - Errors: WEBRTC_VIDEO_CODEC_ERROR - // - virtual int SetChannelParameters(uint32_t packet_loss, int rtt); - - // Inform the encoder about the new target bit rate. - // - // - new_bitrate_kbit : New target bit rate - // - frame_rate : The target frame rate - // - // Return value : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise. - virtual int SetRates(uint32_t new_bitrate_kbit, uint32_t frame_rate); - - private: - VP8Encoder(); - - // Call encoder initialize function and set control settings. - int InitAndSetControlSettings(const VideoCodec* inst); - - // Update frame size for codec. - int UpdateCodecFrameSize(WebRtc_UWord32 input_image_width, - WebRtc_UWord32 input_image_height); - - void PopulateCodecSpecific(CodecSpecificInfo* codec_specific, - const vpx_codec_cx_pkt& pkt); - - int GetEncodedFrame(const VideoFrame& input_image); - - int GetEncodedPartitions(const VideoFrame& input_image); - - // Determine maximum target for Intra frames - // - // Input: - // - optimal_buffer_size : Optimal buffer size - // Return Value : Max target size for Intra frames represented as - // percentage of the per frame bandwidth - uint32_t MaxIntraTarget(uint32_t optimal_buffer_size); - - EncodedImage encoded_image_; - EncodedImageCallback* encoded_complete_callback_; - VideoCodec codec_; - bool inited_; - int64_t timestamp_; - uint16_t picture_id_; - bool feedback_mode_; - int cpu_speed_; - uint32_t rc_max_intra_target_; - int token_partitions_; - ReferencePictureSelection* rps_; - TemporalLayers* temporal_layers_; - vpx_codec_ctx_t* encoder_; - vpx_codec_enc_cfg_t* config_; - vpx_image_t* raw_; + virtual ~VP8Encoder() {}; }; // end of VP8Encoder class @@ -150,91 +29,8 @@ class VP8Decoder : public VideoDecoder { public: static VP8Decoder* Create(); - virtual ~VP8Decoder(); - - // Initialize the decoder. - // - // Return value : WEBRTC_VIDEO_CODEC_OK. - // <0 - Errors: - // WEBRTC_VIDEO_CODEC_ERROR - virtual int InitDecode(const VideoCodec* inst, int number_of_cores); - - // Decode encoded image (as a part of a video stream). The decoded image - // will be returned to the user through the decode complete callback. - // - // Input: - // - input_image : Encoded image to be decoded - // - missing_frames : True if one or more frames have been lost - // since the previous decode call. - // - fragmentation : Specifies the start and length of each VP8 - // partition. - // - codec_specific_info : pointer to specific codec data - // - render_time_ms : Render time in Ms - // - // Return value : WEBRTC_VIDEO_CODEC_OK if OK - // <0 - Errors: - // WEBRTC_VIDEO_CODEC_ERROR - // WEBRTC_VIDEO_CODEC_ERR_PARAMETER - virtual int Decode(const EncodedImage& input_image, - bool missing_frames, - const RTPFragmentationHeader* fragmentation, - const CodecSpecificInfo* codec_specific_info, - int64_t /*render_time_ms*/); - - // Register a decode complete callback object. - // - // Input: - // - callback : Callback object which handles decoded images. - // - // Return value : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise. - virtual int RegisterDecodeCompleteCallback(DecodedImageCallback* callback); - - // Free decoder memory. - // - // Return value : WEBRTC_VIDEO_CODEC_OK if OK - // <0 - Errors: - // WEBRTC_VIDEO_CODEC_ERROR - virtual int Release(); - - // Reset decoder state and prepare for a new call. - // - // Return value : WEBRTC_VIDEO_CODEC_OK. - // <0 - Errors: - // WEBRTC_VIDEO_CODEC_UNINITIALIZED - // WEBRTC_VIDEO_CODEC_ERROR - virtual int Reset(); - - // Create a copy of the codec and its internal state. - // - // Return value : A copy of the instance if OK, NULL otherwise. - virtual VideoDecoder* Copy(); - - private: - VP8Decoder(); - - // Copy reference image from this _decoder to the _decoder in copyTo. Set - // which frame type to copy in _refFrame->frame_type before the call to - // this function. - int CopyReference(VP8Decoder* copy); - - int DecodePartitions(const EncodedImage& input_image, - const RTPFragmentationHeader* fragmentation); - - int ReturnFrame(const vpx_image_t* img, uint32_t timeStamp); - - VideoFrame decoded_image_; - DecodedImageCallback* decode_complete_callback_; - bool inited_; - bool feedback_mode_; - vpx_dec_ctx_t* decoder_; - VideoCodec codec_; - EncodedImage last_keyframe_; - int image_format_; - vpx_ref_frame_t* ref_frame_; - int propagation_cnt_; - bool latest_keyframe_complete_; - bool mfqe_enabled_; + virtual ~VP8Decoder() {}; }; // end of VP8Decoder class } // namespace webrtc -#endif // WEBRTC_MODULES_VIDEO_CODING_CODECS_VP8_H_ +#endif // WEBRTC_MODULES_VIDEO_CODING_CODECS_VP8_INCLUDE_VP8_H_ diff --git a/src/modules/video_coding/codecs/vp8/temporal_layers.cc b/src/modules/video_coding/codecs/vp8/temporal_layers.cc index 63874e031..fb6accfae 100644 --- a/src/modules/video_coding/codecs/vp8/temporal_layers.cc +++ b/src/modules/video_coding/codecs/vp8/temporal_layers.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. +/* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source @@ -27,7 +27,8 @@ TemporalLayers::TemporalLayers(int numberOfTemporalLayers) temporal_ids_length_(0), temporal_pattern_length_(0), tl0_pic_idx_(rand()), - pattern_idx_(255) { + pattern_idx_(255), + timestamp_(0) { assert(kMaxTemporalStreams >= numberOfTemporalLayers); memset(temporal_ids_, 0, sizeof(temporal_ids_)); memset(temporal_pattern_, 0, sizeof(temporal_pattern_)); @@ -214,7 +215,8 @@ int TemporalLayers::EncodeFlags() { } void TemporalLayers::PopulateCodecSpecific(bool key_frame, - CodecSpecificInfoVP8 *vp8_info) { + CodecSpecificInfoVP8 *vp8_info, + uint32_t timestamp) { assert(number_of_temporal_layers_ > 1); assert(0 < temporal_ids_length_); @@ -237,10 +239,11 @@ void TemporalLayers::PopulateCodecSpecific(bool key_frame, } else { vp8_info->layerSync = false; } - - if (vp8_info->temporalIdx == 0) { + if (vp8_info->temporalIdx == 0 && timestamp != timestamp_) { + timestamp_ = timestamp; tl0_pic_idx_++; } vp8_info->tl0PicIdx = tl0_pic_idx_; } } // namespace webrtc + diff --git a/src/modules/video_coding/codecs/vp8/temporal_layers.h b/src/modules/video_coding/codecs/vp8/temporal_layers.h index 6f738b51b..fd061911e 100644 --- a/src/modules/video_coding/codecs/vp8/temporal_layers.h +++ b/src/modules/video_coding/codecs/vp8/temporal_layers.h @@ -31,7 +31,8 @@ class TemporalLayers { bool ConfigureBitrates(int bitrate_kbit, vpx_codec_enc_cfg_t* cfg); - void PopulateCodecSpecific(bool key_frame, CodecSpecificInfoVP8 *vp8_info); + void PopulateCodecSpecific(bool key_frame, CodecSpecificInfoVP8 *vp8_info, + uint32_t timestamp); private: enum TemporalReferences { @@ -73,6 +74,7 @@ class TemporalLayers { TemporalReferences temporal_pattern_[kMaxTemporalPattern]; uint8_t tl0_pic_idx_; uint8_t pattern_idx_; + uint32_t timestamp_; }; } // namespace webrtc #endif // WEBRTC_MODULES_VIDEO_CODING_CODECS_VP8_TEMPORAL_LAYERS_H_ diff --git a/src/modules/video_coding/codecs/vp8/temporal_layers_unittest.cc b/src/modules/video_coding/codecs/vp8/temporal_layers_unittest.cc index 2572fcd59..4003d242a 100644 --- a/src/modules/video_coding/codecs/vp8/temporal_layers_unittest.cc +++ b/src/modules/video_coding/codecs/vp8/temporal_layers_unittest.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source @@ -94,10 +94,9 @@ TEST(TemporalLayersTest, 2Layers) { for (int i = 0; i < 16; ++i) { EXPECT_EQ(expected_flags[i], tl.EncodeFlags()); - tl.PopulateCodecSpecific(false, &vp8_info); + tl.PopulateCodecSpecific(false, &vp8_info, 0); EXPECT_EQ(expected_temporal_idx[i], vp8_info.temporalIdx); - bool expected_sync = expected_layer_sync[i]; - EXPECT_EQ(expected_sync, vp8_info.layerSync); + EXPECT_EQ(expected_layer_sync[i], vp8_info.layerSync); } } @@ -133,10 +132,9 @@ TEST(TemporalLayersTest, 3Layers) { for (int i = 0; i < 16; ++i) { EXPECT_EQ(expected_flags[i], tl.EncodeFlags()); - tl.PopulateCodecSpecific(false, &vp8_info); + tl.PopulateCodecSpecific(false, &vp8_info, 0); EXPECT_EQ(expected_temporal_idx[i], vp8_info.temporalIdx); - bool expected_sync = expected_layer_sync[i]; - EXPECT_EQ(expected_sync, vp8_info.layerSync); + EXPECT_EQ(expected_layer_sync[i], vp8_info.layerSync); } } @@ -172,10 +170,9 @@ TEST(TemporalLayersTest, 4Layers) { for (int i = 0; i < 16; ++i) { EXPECT_EQ(expected_flags[i], tl.EncodeFlags()); - tl.PopulateCodecSpecific(false, &vp8_info); + tl.PopulateCodecSpecific(false, &vp8_info, 0); EXPECT_EQ(expected_temporal_idx[i], vp8_info.temporalIdx); - bool expected_sync = expected_layer_sync[i]; - EXPECT_EQ(expected_sync, vp8_info.layerSync); + EXPECT_EQ(expected_layer_sync[i], vp8_info.layerSync); } } @@ -203,15 +200,14 @@ TEST(TemporalLayersTest, KeyFrame) { for (int i = 0; i < 7; ++i) { EXPECT_EQ(expected_flags[i], tl.EncodeFlags()); - tl.PopulateCodecSpecific(true, &vp8_info); + tl.PopulateCodecSpecific(true, &vp8_info, 0); EXPECT_EQ(expected_temporal_idx[i], vp8_info.temporalIdx); - bool expected_sync = expected_layer_sync[i]; - EXPECT_EQ(expected_sync, vp8_info.layerSync); + EXPECT_EQ(expected_layer_sync[i], vp8_info.layerSync); } EXPECT_EQ(expected_flags[7], tl.EncodeFlags()); - tl.PopulateCodecSpecific(false, &vp8_info); + tl.PopulateCodecSpecific(false, &vp8_info, 0); EXPECT_EQ(expected_temporal_idx[7], vp8_info.temporalIdx); - bool expected_sync = expected_layer_sync[7]; - EXPECT_EQ(expected_sync, vp8_info.layerSync); + EXPECT_EQ(expected_layer_sync[7], vp8_info.layerSync); } } // namespace webrtc + diff --git a/src/modules/video_coding/codecs/vp8/vp8.gyp b/src/modules/video_coding/codecs/vp8/vp8.gyp index dbb1457db..c828d6ad1 100644 --- a/src/modules/video_coding/codecs/vp8/vp8.gyp +++ b/src/modules/video_coding/codecs/vp8/vp8.gyp @@ -60,7 +60,7 @@ 'reference_picture_selection.cc', 'include/vp8.h', 'include/vp8_common_types.h', - 'vp8.cc', + 'vp8_impl.cc', ], }, ], # targets diff --git a/src/modules/video_coding/codecs/vp8/vp8.cc b/src/modules/video_coding/codecs/vp8/vp8_impl.cc similarity index 88% rename from src/modules/video_coding/codecs/vp8/vp8.cc rename to src/modules/video_coding/codecs/vp8/vp8_impl.cc index 2016559b2..4f08f4658 100644 --- a/src/modules/video_coding/codecs/vp8/vp8.cc +++ b/src/modules/video_coding/codecs/vp8/vp8_impl.cc @@ -10,39 +10,40 @@ * This file contains the WEBRTC VP8 wrapper implementation * */ -#include "vp8.h" + +#include "modules/video_coding/codecs/vp8/vp8_impl.h" #include #include #include -#include "common_video/libyuv/include/webrtc_libyuv.h" -#include "module_common_types.h" -#include "reference_picture_selection.h" -#include "temporal_layers.h" -#include "tick_util.h" #include "vpx/vpx_encoder.h" #include "vpx/vpx_decoder.h" #include "vpx/vp8cx.h" #include "vpx/vp8dx.h" +#include "common_video/libyuv/include/webrtc_libyuv.h" +#include "module_common_types.h" +#include "modules/video_coding/codecs/vp8/reference_picture_selection.h" +#include "modules/video_coding/codecs/vp8/temporal_layers.h" +#include "system_wrappers/interface/tick_util.h" + enum { kVp8ErrorPropagationTh = 30 }; -namespace webrtc -{ +namespace webrtc { VP8Encoder* VP8Encoder::Create() { - return new VP8Encoder(); + return new VP8EncoderImpl(); } -VP8Encoder::VP8Encoder() +VP8EncoderImpl::VP8EncoderImpl() : encoded_image_(), encoded_complete_callback_(NULL), inited_(false), timestamp_(0), picture_id_(0), feedback_mode_(false), - cpu_speed_(-6), // default value + cpu_speed_(-6), // default value rc_max_intra_target_(0), token_partitions_(VP8_ONE_TOKENPARTITION), rps_(new ReferencePictureSelection), @@ -57,12 +58,12 @@ VP8Encoder::VP8Encoder() srand(seed); } -VP8Encoder::~VP8Encoder() { +VP8EncoderImpl::~VP8EncoderImpl() { Release(); delete rps_; } -int VP8Encoder::Release() { +int VP8EncoderImpl::Release() { if (encoded_image_._buffer != NULL) { delete [] encoded_image_._buffer; encoded_image_._buffer = NULL; @@ -92,7 +93,8 @@ int VP8Encoder::Release() { return WEBRTC_VIDEO_CODEC_OK; } -int VP8Encoder::SetRates(uint32_t new_bitrate_kbit, uint32_t new_framerate) { +int VP8EncoderImpl::SetRates(uint32_t new_bitrate_kbit, + uint32_t new_framerate) { if (!inited_) { return WEBRTC_VIDEO_CODEC_UNINITIALIZED; } @@ -106,7 +108,7 @@ int VP8Encoder::SetRates(uint32_t new_bitrate_kbit, uint32_t new_framerate) { if (codec_.maxBitrate > 0 && new_bitrate_kbit > codec_.maxBitrate) { new_bitrate_kbit = codec_.maxBitrate; } - config_->rc_target_bitrate = new_bitrate_kbit; // in kbit/s + config_->rc_target_bitrate = new_bitrate_kbit; // in kbit/s #if WEBRTC_LIBVPX_VERSION >= 971 if (temporal_layers_) { @@ -122,9 +124,9 @@ int VP8Encoder::SetRates(uint32_t new_bitrate_kbit, uint32_t new_framerate) { return WEBRTC_VIDEO_CODEC_OK; } -int VP8Encoder::InitEncode(const VideoCodec* inst, - int number_of_cores, - uint32_t /*max_payload_size*/) { +int VP8EncoderImpl::InitEncode(const VideoCodec* inst, + int number_of_cores, + uint32_t /*max_payload_size*/) { if (inst == NULL) { return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; } @@ -222,7 +224,7 @@ int VP8Encoder::InitEncode(const VideoCodec* inst, return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; // Not supported #endif } - config_->g_lag_in_frames = 0; // 0- no frame lagging + config_->g_lag_in_frames = 0; // 0- no frame lagging // Determining number of threads based on the image size if (codec_.width * codec_.height > 704 * 576 && number_of_cores > 1) { @@ -280,7 +282,7 @@ int VP8Encoder::InitEncode(const VideoCodec* inst, return InitAndSetControlSettings(inst); } -int VP8Encoder::InitAndSetControlSettings(const VideoCodec* inst) { +int VP8EncoderImpl::InitAndSetControlSettings(const VideoCodec* inst) { vpx_codec_flags_t flags = 0; // TODO(holmer): We should make a smarter decision on the number of // partitions. Eight is probably not the optimal number for low resolution @@ -306,7 +308,7 @@ int VP8Encoder::InitAndSetControlSettings(const VideoCodec* inst) { return WEBRTC_VIDEO_CODEC_OK; } -uint32_t VP8Encoder::MaxIntraTarget(uint32_t optimalBuffersize) { +uint32_t VP8EncoderImpl::MaxIntraTarget(uint32_t optimalBuffersize) { // Set max to the optimal buffer level (normalized by target BR), // and scaled by a scalePar. // Max target size = scalePar * optimalBufferSize * targetBR[Kbps]. @@ -322,9 +324,9 @@ uint32_t VP8Encoder::MaxIntraTarget(uint32_t optimalBuffersize) { return (targetPct < minIntraTh) ? minIntraTh: targetPct; } -int VP8Encoder::Encode(const VideoFrame& input_image, - const CodecSpecificInfo* codec_specific_info, - const VideoFrameType frame_type) { +int VP8EncoderImpl::Encode(const VideoFrame& input_image, + const CodecSpecificInfo* codec_specific_info, + const VideoFrameType frame_type) { if (!inited_) { return WEBRTC_VIDEO_CODEC_UNINITIALIZED; } @@ -398,8 +400,8 @@ int VP8Encoder::Encode(const VideoFrame& input_image, #endif } -int VP8Encoder::UpdateCodecFrameSize(WebRtc_UWord32 input_image_width, - WebRtc_UWord32 input_image_height) { +int VP8EncoderImpl::UpdateCodecFrameSize(WebRtc_UWord32 input_image_width, + WebRtc_UWord32 input_image_height) { codec_.width = input_image_width; codec_.height = input_image_height; @@ -422,8 +424,9 @@ int VP8Encoder::UpdateCodecFrameSize(WebRtc_UWord32 input_image_width, return WEBRTC_VIDEO_CODEC_OK; } -void VP8Encoder::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, - const vpx_codec_cx_pkt& pkt) { +void VP8EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, + const vpx_codec_cx_pkt& pkt, + uint32_t timestamp) { assert(codec_specific != NULL); codec_specific->codecType = kVideoCodecVP8; CodecSpecificInfoVP8 *vp8Info = &(codec_specific->codecSpecific.VP8); @@ -434,7 +437,8 @@ void VP8Encoder::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, #if WEBRTC_LIBVPX_VERSION >= 971 if (temporal_layers_) { temporal_layers_->PopulateCodecSpecific( - (pkt.data.frame.flags & VPX_FRAME_IS_KEY) ? true : false, vp8Info); + (pkt.data.frame.flags & VPX_FRAME_IS_KEY) ? true : false, vp8Info, + timestamp); } else { #endif vp8Info->temporalIdx = kNoTemporalIdx; @@ -446,7 +450,7 @@ void VP8Encoder::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, picture_id_ = (picture_id_ + 1) & 0x7FFF; // prepare next } -int VP8Encoder::GetEncodedFrame(const VideoFrame& input_image) { +int VP8EncoderImpl::GetEncodedFrame(const VideoFrame& input_image) { vpx_codec_iter_t iter = NULL; encoded_image_._frameType = kDeltaFrame; const vpx_codec_cx_pkt_t *pkt= vpx_codec_get_cx_data(encoder_, &iter); @@ -459,7 +463,7 @@ int VP8Encoder::GetEncodedFrame(const VideoFrame& input_image) { } } else if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { CodecSpecificInfo codecSpecific; - PopulateCodecSpecific(&codecSpecific, *pkt); + PopulateCodecSpecific(&codecSpecific, *pkt, input_image.TimeStamp()); assert(pkt->data.frame.sz <= encoded_image_._size); memcpy(encoded_image_._buffer, pkt->data.frame.buf, pkt->data.frame.sz); @@ -489,14 +493,14 @@ int VP8Encoder::GetEncodedFrame(const VideoFrame& input_image) { uint32_t tmpSize = (firstByte[2] << 16) | (firstByte[1] << 8) | firstByte[0]; fragInfo.fragmentationLength[0] = (tmpSize >> 5) & 0x7FFFF; - fragInfo.fragmentationPlType[0] = 0; // not known here + fragInfo.fragmentationPlType[0] = 0; // not known here fragInfo.fragmentationTimeDiff[0] = 0; // Second partition fragInfo.fragmentationOffset[1] = fragInfo.fragmentationLength[0]; fragInfo.fragmentationLength[1] = encoded_image_._length - fragInfo.fragmentationLength[0]; - fragInfo.fragmentationPlType[1] = 0; // not known here + fragInfo.fragmentationPlType[1] = 0; // not known here fragInfo.fragmentationTimeDiff[1] = 0; encoded_complete_callback_->Encoded(encoded_image_, &codecSpecific, @@ -508,7 +512,7 @@ int VP8Encoder::GetEncodedFrame(const VideoFrame& input_image) { } #if WEBRTC_LIBVPX_VERSION >= 971 -int VP8Encoder::GetEncodedPartitions(const VideoFrame& input_image) { +int VP8EncoderImpl::GetEncodedPartitions(const VideoFrame& input_image) { vpx_codec_iter_t iter = NULL; int part_idx = 0; encoded_image_._length = 0; @@ -519,7 +523,7 @@ int VP8Encoder::GetEncodedPartitions(const VideoFrame& input_image) { const vpx_codec_cx_pkt_t *pkt = NULL; while ((pkt = vpx_codec_get_cx_data(encoder_, &iter)) != NULL) { - switch(pkt->kind) { + switch (pkt->kind) { case VPX_CODEC_CX_FRAME_PKT: { memcpy(&encoded_image_._buffer[encoded_image_._length], pkt->data.frame.buf, @@ -544,7 +548,7 @@ int VP8Encoder::GetEncodedPartitions(const VideoFrame& input_image) { encoded_image_._frameType = kKeyFrame; rps_->EncodedKeyFrame(picture_id_); } - PopulateCodecSpecific(&codec_specific, *pkt); + PopulateCodecSpecific(&codec_specific, *pkt, input_image.TimeStamp()); break; } } @@ -560,22 +564,22 @@ int VP8Encoder::GetEncodedPartitions(const VideoFrame& input_image) { } #endif -int VP8Encoder::SetChannelParameters(uint32_t /*packet_loss*/, int rtt) { +int VP8EncoderImpl::SetChannelParameters(uint32_t /*packet_loss*/, int rtt) { rps_->SetRtt(rtt); return WEBRTC_VIDEO_CODEC_OK; } -int VP8Encoder::RegisterEncodeCompleteCallback( +int VP8EncoderImpl::RegisterEncodeCompleteCallback( EncodedImageCallback* callback) { encoded_complete_callback_ = callback; return WEBRTC_VIDEO_CODEC_OK; } VP8Decoder* VP8Decoder::Create() { - return new VP8Decoder(); + return new VP8DecoderImpl(); } -VP8Decoder::VP8Decoder() +VP8DecoderImpl::VP8DecoderImpl() : decode_complete_callback_(NULL), inited_(false), feedback_mode_(false), @@ -589,12 +593,12 @@ VP8Decoder::VP8Decoder() memset(&codec_, 0, sizeof(codec_)); } -VP8Decoder::~VP8Decoder() { - inited_ = true; // in order to do the actual release +VP8DecoderImpl::~VP8DecoderImpl() { + inited_ = true; // in order to do the actual release Release(); } -int VP8Decoder::Reset() { +int VP8DecoderImpl::Reset() { if (!inited_) { return WEBRTC_VIDEO_CODEC_UNINITIALIZED; } @@ -605,12 +609,12 @@ int VP8Decoder::Reset() { return WEBRTC_VIDEO_CODEC_OK; } -int VP8Decoder::InitDecode(const VideoCodec* inst, int number_of_cores) { +int VP8DecoderImpl::InitDecode(const VideoCodec* inst, int number_of_cores) { if (inst == NULL) { return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; } int ret_val = Release(); - if (ret_val < 0 ) { + if (ret_val < 0) { return ret_val; } if (decoder_ == NULL) { @@ -622,7 +626,7 @@ int VP8Decoder::InitDecode(const VideoCodec* inst, int number_of_cores) { vpx_codec_dec_cfg_t cfg; // Setting number of threads to a constant value (1) cfg.threads = 1; - cfg.h = cfg.w = 0; // set after decode + cfg.h = cfg.w = 0; // set after decode vpx_codec_flags_t flags = 0; #if (WEBRTC_LIBVPX_VERSION >= 971) && !defined(WEBRTC_ANDROID) @@ -656,11 +660,11 @@ int VP8Decoder::InitDecode(const VideoCodec* inst, int number_of_cores) { return WEBRTC_VIDEO_CODEC_OK; } -int VP8Decoder::Decode(const EncodedImage& input_image, - bool missing_frames, - const RTPFragmentationHeader* fragmentation, - const CodecSpecificInfo* codec_specific_info, - int64_t /*render_time_ms*/) { +int VP8DecoderImpl::Decode(const EncodedImage& input_image, + bool missing_frames, + const RTPFragmentationHeader* fragmentation, + const CodecSpecificInfo* codec_specific_info, + int64_t /*render_time_ms*/) { if (!inited_) { return WEBRTC_VIDEO_CODEC_UNINITIALIZED; } @@ -737,7 +741,7 @@ int VP8Decoder::Decode(const EncodedImage& input_image, #else uint8_t* buffer = input_image._buffer; if (input_image._length == 0) { - buffer = NULL; // Triggers full frame concealment. + buffer = NULL; // Triggers full frame concealment. } if (vpx_codec_decode(decoder_, buffer, @@ -760,11 +764,11 @@ int VP8Decoder::Decode(const EncodedImage& input_image, last_keyframe_._size = 0; } - uint8_t* temp_buffer = last_keyframe_._buffer; // Save buffer ptr. - uint32_t temp_size = last_keyframe_._size; // Save size. - last_keyframe_ = input_image; // Shallow copy. - last_keyframe_._buffer = temp_buffer; // Restore buffer ptr. - last_keyframe_._size = temp_size; // Restore buffer size. + uint8_t* temp_buffer = last_keyframe_._buffer; // Save buffer ptr. + uint32_t temp_size = last_keyframe_._size; // Save size. + last_keyframe_ = input_image; // Shallow copy. + last_keyframe_._buffer = temp_buffer; // Restore buffer ptr. + last_keyframe_._size = temp_size; // Restore buffer size. if (!last_keyframe_._buffer) { // Allocate memory. last_keyframe_._size = bytes_to_copy; @@ -835,7 +839,7 @@ int VP8Decoder::Decode(const EncodedImage& input_image, return WEBRTC_VIDEO_CODEC_OK; } -int VP8Decoder::DecodePartitions( +int VP8DecoderImpl::DecodePartitions( const EncodedImage& input_image, const RTPFragmentationHeader* fragmentation) { for (int i = 0; i < fragmentation->fragmentationVectorSize; ++i) { @@ -858,7 +862,7 @@ int VP8Decoder::DecodePartitions( return WEBRTC_VIDEO_CODEC_OK; } -int VP8Decoder::ReturnFrame(const vpx_image_t* img, uint32_t timestamp) { +int VP8DecoderImpl::ReturnFrame(const vpx_image_t* img, uint32_t timestamp) { if (img == NULL) { // Decoder OK and NULL image => No show frame return WEBRTC_VIDEO_CODEC_NO_OUTPUT; @@ -875,7 +879,7 @@ int VP8Decoder::ReturnFrame(const vpx_image_t* img, uint32_t timestamp) { unsigned int width = (plane ? (img->d_w + 1) >> 1 : img->d_w); unsigned int height = (plane ? (img->d_h + 1) >> 1 : img->d_h); buf = img->planes[plane]; - for(y = 0; y < height; y++) { + for (y = 0; y < height; y++) { memcpy(&buffer[pos], buf, width); pos += width; buf += img->stride[plane]; @@ -896,20 +900,20 @@ int VP8Decoder::ReturnFrame(const vpx_image_t* img, uint32_t timestamp) { return WEBRTC_VIDEO_CODEC_OK; } -int VP8Decoder::RegisterDecodeCompleteCallback( +int VP8DecoderImpl::RegisterDecodeCompleteCallback( DecodedImageCallback* callback) { decode_complete_callback_ = callback; return WEBRTC_VIDEO_CODEC_OK; } -int VP8Decoder::Release() { +int VP8DecoderImpl::Release() { decoded_image_.Free(); if (last_keyframe_._buffer != NULL) { delete [] last_keyframe_._buffer; last_keyframe_._buffer = NULL; } if (decoder_ != NULL) { - if(vpx_codec_destroy(decoder_)) { + if (vpx_codec_destroy(decoder_)) { return WEBRTC_VIDEO_CODEC_MEMORY; } delete decoder_; @@ -924,7 +928,7 @@ int VP8Decoder::Release() { return WEBRTC_VIDEO_CODEC_OK; } -VideoDecoder* VP8Decoder::Copy() { +VideoDecoder* VP8DecoderImpl::Copy() { // Sanity checks. if (!inited_) { // Not initialized. @@ -940,7 +944,7 @@ VideoDecoder* VP8Decoder::Copy() { return NULL; } // Create a new VideoDecoder object - VP8Decoder *copy = new VP8Decoder; + VP8DecoderImpl *copy = new VP8DecoderImpl; // Initialize the new decoder if (copy->InitDecode(&codec_, 1) != WEBRTC_VIDEO_CODEC_OK) { @@ -997,7 +1001,7 @@ VideoDecoder* VP8Decoder::Copy() { // Copy all member variables (that are not set in initialization). copy->feedback_mode_ = feedback_mode_; copy->image_format_ = image_format_; - copy->last_keyframe_ = last_keyframe_; // Shallow copy. + copy->last_keyframe_ = last_keyframe_; // Shallow copy. // Allocate memory. (Discard copied _buffer pointer.) copy->last_keyframe_._buffer = new uint8_t[last_keyframe_._size]; memcpy(copy->last_keyframe_._buffer, last_keyframe_._buffer, @@ -1006,18 +1010,18 @@ VideoDecoder* VP8Decoder::Copy() { return static_cast(copy); } -int VP8Decoder::CopyReference(VP8Decoder* copyTo) { +int VP8DecoderImpl::CopyReference(VP8Decoder* copyTo) { // The type of frame to copy should be set in ref_frame_->frame_type // before the call to this function. if (vpx_codec_control(decoder_, VP8_COPY_REFERENCE, ref_frame_) != VPX_CODEC_OK) { return -1; } - if (vpx_codec_control(copyTo->decoder_, VP8_SET_REFERENCE, ref_frame_) - != VPX_CODEC_OK) { + if (vpx_codec_control(static_cast(copyTo)->decoder_, + VP8_SET_REFERENCE, ref_frame_) != VPX_CODEC_OK) { return -1; } return 0; } -} // namespace webrtc +} // namespace webrtc diff --git a/src/modules/video_coding/codecs/vp8/vp8_impl.h b/src/modules/video_coding/codecs/vp8/vp8_impl.h new file mode 100644 index 000000000..82c85eac8 --- /dev/null +++ b/src/modules/video_coding/codecs/vp8/vp8_impl.h @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + * + * WEBRTC VP8 wrapper interface + */ + +#ifndef WEBRTC_MODULES_VIDEO_CODING_CODECS_VP8_IMPL_H_ +#define WEBRTC_MODULES_VIDEO_CODING_CODECS_VP8_IMPL_H_ + +#include "modules/video_coding/codecs/vp8/include/vp8.h" + +// VPX forward declaration +typedef struct vpx_codec_ctx vpx_codec_ctx_t; +typedef struct vpx_codec_ctx vpx_dec_ctx_t; +typedef struct vpx_codec_enc_cfg vpx_codec_enc_cfg_t; +typedef struct vpx_image vpx_image_t; +typedef struct vpx_ref_frame vpx_ref_frame_t; +struct vpx_codec_cx_pkt; + +namespace webrtc { + +class TemporalLayers; +class ReferencePictureSelection; + +class VP8EncoderImpl : public VP8Encoder { + public: + VP8EncoderImpl(); + + virtual ~VP8EncoderImpl(); + + // Free encoder memory. + // + // Return value : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise. + virtual int Release(); + + // Initialize the encoder with the information from the codecSettings + // + // Input: + // - codec_settings : Codec settings + // - number_of_cores : Number of cores available for the encoder + // - max_payload_size : The maximum size each payload is allowed + // to have. Usually MTU - overhead. + // + // Return value : Set bit rate if OK + // <0 - Errors: + // WEBRTC_VIDEO_CODEC_ERR_PARAMETER + // WEBRTC_VIDEO_CODEC_ERR_SIZE + // WEBRTC_VIDEO_CODEC_LEVEL_EXCEEDED + // WEBRTC_VIDEO_CODEC_MEMORY + // WEBRTC_VIDEO_CODEC_ERROR + virtual int InitEncode(const VideoCodec* codec_settings, + int number_of_cores, + uint32_t max_payload_size); + + // Encode an I420 image (as a part of a video stream). The encoded image + // will be returned to the user through the encode complete callback. + // + // Input: + // - input_image : Image to be encoded + // - frame_types : Frame type to be generated by the encoder. + // + // Return value : WEBRTC_VIDEO_CODEC_OK if OK + // <0 - Errors: + // WEBRTC_VIDEO_CODEC_ERR_PARAMETER + // WEBRTC_VIDEO_CODEC_MEMORY + // WEBRTC_VIDEO_CODEC_ERROR + // WEBRTC_VIDEO_CODEC_TIMEOUT + + virtual int Encode(const VideoFrame& input_image, + const CodecSpecificInfo* codec_specific_info, + const VideoFrameType frame_type); + + // Register an encode complete callback object. + // + // Input: + // - callback : Callback object which handles encoded images. + // + // Return value : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise. + virtual int RegisterEncodeCompleteCallback(EncodedImageCallback* callback); + + // Inform the encoder of the new packet loss rate and the round-trip time of + // the network. + // + // - packet_loss : Fraction lost + // (loss rate in percent = 100 * packetLoss / 255) + // - rtt : Round-trip time in milliseconds + // Return value : WEBRTC_VIDEO_CODEC_OK if OK + // <0 - Errors: WEBRTC_VIDEO_CODEC_ERROR + // + virtual int SetChannelParameters(uint32_t packet_loss, int rtt); + + // Inform the encoder about the new target bit rate. + // + // - new_bitrate_kbit : New target bit rate + // - frame_rate : The target frame rate + // + // Return value : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise. + virtual int SetRates(uint32_t new_bitrate_kbit, uint32_t frame_rate); + + private: + // Call encoder initialize function and set control settings. + int InitAndSetControlSettings(const VideoCodec* inst); + + // Update frame size for codec. + int UpdateCodecFrameSize(WebRtc_UWord32 input_image_width, + WebRtc_UWord32 input_image_height); + + void PopulateCodecSpecific(CodecSpecificInfo* codec_specific, + const vpx_codec_cx_pkt& pkt, + uint32_t timestamp); + + int GetEncodedFrame(const VideoFrame& input_image); + + int GetEncodedPartitions(const VideoFrame& input_image); + + // Determine maximum target for Intra frames + // + // Input: + // - optimal_buffer_size : Optimal buffer size + // Return Value : Max target size for Intra frames represented as + // percentage of the per frame bandwidth + uint32_t MaxIntraTarget(uint32_t optimal_buffer_size); + + EncodedImage encoded_image_; + EncodedImageCallback* encoded_complete_callback_; + VideoCodec codec_; + bool inited_; + int64_t timestamp_; + uint16_t picture_id_; + bool feedback_mode_; + int cpu_speed_; + uint32_t rc_max_intra_target_; + int token_partitions_; + ReferencePictureSelection* rps_; + TemporalLayers* temporal_layers_; + vpx_codec_ctx_t* encoder_; + vpx_codec_enc_cfg_t* config_; + vpx_image_t* raw_; +}; // end of VP8Encoder class + + +class VP8DecoderImpl : public VP8Decoder { + public: + VP8DecoderImpl(); + + virtual ~VP8DecoderImpl(); + + // Initialize the decoder. + // + // Return value : WEBRTC_VIDEO_CODEC_OK. + // <0 - Errors: + // WEBRTC_VIDEO_CODEC_ERROR + virtual int InitDecode(const VideoCodec* inst, int number_of_cores); + + // Decode encoded image (as a part of a video stream). The decoded image + // will be returned to the user through the decode complete callback. + // + // Input: + // - input_image : Encoded image to be decoded + // - missing_frames : True if one or more frames have been lost + // since the previous decode call. + // - fragmentation : Specifies the start and length of each VP8 + // partition. + // - codec_specific_info : pointer to specific codec data + // - render_time_ms : Render time in Ms + // + // Return value : WEBRTC_VIDEO_CODEC_OK if OK + // <0 - Errors: + // WEBRTC_VIDEO_CODEC_ERROR + // WEBRTC_VIDEO_CODEC_ERR_PARAMETER + virtual int Decode(const EncodedImage& input_image, + bool missing_frames, + const RTPFragmentationHeader* fragmentation, + const CodecSpecificInfo* codec_specific_info, + int64_t /*render_time_ms*/); + + // Register a decode complete callback object. + // + // Input: + // - callback : Callback object which handles decoded images. + // + // Return value : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise. + virtual int RegisterDecodeCompleteCallback(DecodedImageCallback* callback); + + // Free decoder memory. + // + // Return value : WEBRTC_VIDEO_CODEC_OK if OK + // <0 - Errors: + // WEBRTC_VIDEO_CODEC_ERROR + virtual int Release(); + + // Reset decoder state and prepare for a new call. + // + // Return value : WEBRTC_VIDEO_CODEC_OK. + // <0 - Errors: + // WEBRTC_VIDEO_CODEC_UNINITIALIZED + // WEBRTC_VIDEO_CODEC_ERROR + virtual int Reset(); + + // Create a copy of the codec and its internal state. + // + // Return value : A copy of the instance if OK, NULL otherwise. + virtual VideoDecoder* Copy(); + + private: + // Copy reference image from this _decoder to the _decoder in copyTo. Set + // which frame type to copy in _refFrame->frame_type before the call to + // this function. + int CopyReference(VP8Decoder* copy); + + int DecodePartitions(const EncodedImage& input_image, + const RTPFragmentationHeader* fragmentation); + + int ReturnFrame(const vpx_image_t* img, uint32_t timeStamp); + + VideoFrame decoded_image_; + DecodedImageCallback* decode_complete_callback_; + bool inited_; + bool feedback_mode_; + vpx_dec_ctx_t* decoder_; + VideoCodec codec_; + EncodedImage last_keyframe_; + int image_format_; + vpx_ref_frame_t* ref_frame_; + int propagation_cnt_; + bool latest_keyframe_complete_; + bool mfqe_enabled_; +}; // end of VP8Decoder class +} // namespace webrtc + +#endif // WEBRTC_MODULES_VIDEO_CODING_CODECS_VP8_IMPL_H_