| /* |
| * 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. |
| */ |
| |
| #ifndef MODULE_COMMON_TYPES_H |
| #define MODULE_COMMON_TYPES_H |
| |
| #include <cstring> // memcpy |
| #include <assert.h> |
| |
| #include "typedefs.h" |
| #include "common_types.h" |
| |
| #ifdef _WIN32 |
| #pragma warning(disable:4351) // remove warning "new behavior: elements of array |
| // 'array' will be default initialized" |
| #endif |
| |
| namespace webrtc |
| { |
| struct RTPHeader |
| { |
| bool markerBit; |
| WebRtc_UWord8 payloadType; |
| WebRtc_UWord16 sequenceNumber; |
| WebRtc_UWord32 timestamp; |
| WebRtc_UWord32 ssrc; |
| WebRtc_UWord8 numCSRCs; |
| WebRtc_UWord32 arrOfCSRCs[kRtpCsrcSize]; |
| WebRtc_UWord8 paddingLength; |
| WebRtc_UWord16 headerLength; |
| }; |
| |
| struct RTPHeaderExtension |
| { |
| WebRtc_Word32 transmissionTimeOffset; |
| }; |
| |
| struct RTPAudioHeader |
| { |
| WebRtc_UWord8 numEnergy; // number of valid entries in arrOfEnergy |
| WebRtc_UWord8 arrOfEnergy[kRtpCsrcSize]; // one energy byte (0-9) per channel |
| bool isCNG; // is this CNG |
| WebRtc_UWord8 channel; // number of channels 2 = stereo |
| }; |
| |
| enum {kNoPictureId = -1}; |
| enum {kNoTl0PicIdx = -1}; |
| enum {kNoTemporalIdx = -1}; |
| enum {kNoKeyIdx = -1}; |
| enum {kNoSimulcastIdx = 0}; |
| |
| struct RTPVideoHeaderVP8 |
| { |
| void InitRTPVideoHeaderVP8() |
| { |
| nonReference = false; |
| pictureId = kNoPictureId; |
| tl0PicIdx = kNoTl0PicIdx; |
| temporalIdx = kNoTemporalIdx; |
| layerSync = false; |
| keyIdx = kNoKeyIdx; |
| partitionId = 0; |
| beginningOfPartition = false; |
| frameWidth = 0; |
| frameHeight = 0; |
| } |
| |
| bool nonReference; // Frame is discardable. |
| WebRtc_Word16 pictureId; // Picture ID index, 15 bits; |
| // kNoPictureId if PictureID does not exist. |
| WebRtc_Word16 tl0PicIdx; // TL0PIC_IDX, 8 bits; |
| // kNoTl0PicIdx means no value provided. |
| WebRtc_Word8 temporalIdx; // Temporal layer index, or kNoTemporalIdx. |
| bool layerSync; // This frame is a layer sync frame. |
| // Disabled if temporalIdx == kNoTemporalIdx. |
| int keyIdx; // 5 bits; kNoKeyIdx means not used. |
| int partitionId; // VP8 partition ID |
| bool beginningOfPartition; // True if this packet is the first |
| // in a VP8 partition. Otherwise false |
| int frameWidth; // Exists for key frames. |
| int frameHeight; // Exists for key frames. |
| }; |
| union RTPVideoTypeHeader |
| { |
| RTPVideoHeaderVP8 VP8; |
| }; |
| |
| enum RTPVideoCodecTypes |
| { |
| kRTPVideoGeneric = 0, |
| kRTPVideoVP8 = 8, |
| kRTPVideoNoVideo = 10, |
| kRTPVideoFEC = 11, |
| kRTPVideoI420 = 12 |
| }; |
| struct RTPVideoHeader |
| { |
| WebRtc_UWord16 width; // size |
| WebRtc_UWord16 height; |
| |
| bool isFirstPacket; // first packet in frame |
| WebRtc_UWord8 simulcastIdx; // Index if the simulcast encoder creating |
| // this frame, 0 if not using simulcast. |
| RTPVideoCodecTypes codec; |
| RTPVideoTypeHeader codecHeader; |
| }; |
| union RTPTypeHeader |
| { |
| RTPAudioHeader Audio; |
| RTPVideoHeader Video; |
| }; |
| |
| struct WebRtcRTPHeader |
| { |
| RTPHeader header; |
| FrameType frameType; |
| RTPTypeHeader type; |
| RTPHeaderExtension extension; |
| }; |
| |
| class RTPFragmentationHeader |
| { |
| public: |
| RTPFragmentationHeader() : |
| fragmentationVectorSize(0), |
| fragmentationOffset(NULL), |
| fragmentationLength(NULL), |
| fragmentationTimeDiff(NULL), |
| fragmentationPlType(NULL) |
| {}; |
| |
| ~RTPFragmentationHeader() |
| { |
| delete [] fragmentationOffset; |
| delete [] fragmentationLength; |
| delete [] fragmentationTimeDiff; |
| delete [] fragmentationPlType; |
| } |
| |
| RTPFragmentationHeader& operator=(const RTPFragmentationHeader& header) |
| { |
| if(this == &header) |
| { |
| return *this; |
| } |
| |
| if(header.fragmentationVectorSize != fragmentationVectorSize) |
| { |
| // new size of vectors |
| |
| // delete old |
| delete [] fragmentationOffset; |
| fragmentationOffset = NULL; |
| delete [] fragmentationLength; |
| fragmentationLength = NULL; |
| delete [] fragmentationTimeDiff; |
| fragmentationTimeDiff = NULL; |
| delete [] fragmentationPlType; |
| fragmentationPlType = NULL; |
| |
| if(header.fragmentationVectorSize > 0) |
| { |
| // allocate new |
| if(header.fragmentationOffset) |
| { |
| fragmentationOffset = new WebRtc_UWord32[header.fragmentationVectorSize]; |
| } |
| if(header.fragmentationLength) |
| { |
| fragmentationLength = new WebRtc_UWord32[header.fragmentationVectorSize]; |
| } |
| if(header.fragmentationTimeDiff) |
| { |
| fragmentationTimeDiff = new WebRtc_UWord16[header.fragmentationVectorSize]; |
| } |
| if(header.fragmentationPlType) |
| { |
| fragmentationPlType = new WebRtc_UWord8[header.fragmentationVectorSize]; |
| } |
| } |
| // set new size |
| fragmentationVectorSize = header.fragmentationVectorSize; |
| } |
| |
| if(header.fragmentationVectorSize > 0) |
| { |
| // copy values |
| if(header.fragmentationOffset) |
| { |
| memcpy(fragmentationOffset, header.fragmentationOffset, |
| header.fragmentationVectorSize * sizeof(WebRtc_UWord32)); |
| } |
| if(header.fragmentationLength) |
| { |
| memcpy(fragmentationLength, header.fragmentationLength, |
| header.fragmentationVectorSize * sizeof(WebRtc_UWord32)); |
| } |
| if(header.fragmentationTimeDiff) |
| { |
| memcpy(fragmentationTimeDiff, header.fragmentationTimeDiff, |
| header.fragmentationVectorSize * sizeof(WebRtc_UWord16)); |
| } |
| if(header.fragmentationPlType) |
| { |
| memcpy(fragmentationPlType, header.fragmentationPlType, |
| header.fragmentationVectorSize * sizeof(WebRtc_UWord8)); |
| } |
| } |
| return *this; |
| } |
| void VerifyAndAllocateFragmentationHeader( const WebRtc_UWord16 size) |
| { |
| if( fragmentationVectorSize < size) |
| { |
| WebRtc_UWord16 oldVectorSize = fragmentationVectorSize; |
| { |
| // offset |
| WebRtc_UWord32* oldOffsets = fragmentationOffset; |
| fragmentationOffset = new WebRtc_UWord32[size]; |
| memset(fragmentationOffset+oldVectorSize, 0, |
| sizeof(WebRtc_UWord32)*(size-oldVectorSize)); |
| // copy old values |
| memcpy(fragmentationOffset,oldOffsets, sizeof(WebRtc_UWord32) * oldVectorSize); |
| delete[] oldOffsets; |
| } |
| // length |
| { |
| WebRtc_UWord32* oldLengths = fragmentationLength; |
| fragmentationLength = new WebRtc_UWord32[size]; |
| memset(fragmentationLength+oldVectorSize, 0, |
| sizeof(WebRtc_UWord32) * (size- oldVectorSize)); |
| memcpy(fragmentationLength, oldLengths, |
| sizeof(WebRtc_UWord32) * oldVectorSize); |
| delete[] oldLengths; |
| } |
| // time diff |
| { |
| WebRtc_UWord16* oldTimeDiffs = fragmentationTimeDiff; |
| fragmentationTimeDiff = new WebRtc_UWord16[size]; |
| memset(fragmentationTimeDiff+oldVectorSize, 0, |
| sizeof(WebRtc_UWord16) * (size- oldVectorSize)); |
| memcpy(fragmentationTimeDiff, oldTimeDiffs, |
| sizeof(WebRtc_UWord16) * oldVectorSize); |
| delete[] oldTimeDiffs; |
| } |
| // payload type |
| { |
| WebRtc_UWord8* oldTimePlTypes = fragmentationPlType; |
| fragmentationPlType = new WebRtc_UWord8[size]; |
| memset(fragmentationPlType+oldVectorSize, 0, |
| sizeof(WebRtc_UWord8) * (size- oldVectorSize)); |
| memcpy(fragmentationPlType, oldTimePlTypes, |
| sizeof(WebRtc_UWord8) * oldVectorSize); |
| delete[] oldTimePlTypes; |
| } |
| fragmentationVectorSize = size; |
| } |
| } |
| |
| WebRtc_UWord16 fragmentationVectorSize; // Number of fragmentations |
| WebRtc_UWord32* fragmentationOffset; // Offset of pointer to data for each fragm. |
| WebRtc_UWord32* fragmentationLength; // Data size for each fragmentation |
| WebRtc_UWord16* fragmentationTimeDiff; // Timestamp difference relative "now" for |
| // each fragmentation |
| WebRtc_UWord8* fragmentationPlType; // Payload type of each fragmentation |
| }; |
| |
| struct RTCPVoIPMetric |
| { |
| // RFC 3611 4.7 |
| WebRtc_UWord8 lossRate; |
| WebRtc_UWord8 discardRate; |
| WebRtc_UWord8 burstDensity; |
| WebRtc_UWord8 gapDensity; |
| WebRtc_UWord16 burstDuration; |
| WebRtc_UWord16 gapDuration; |
| WebRtc_UWord16 roundTripDelay; |
| WebRtc_UWord16 endSystemDelay; |
| WebRtc_UWord8 signalLevel; |
| WebRtc_UWord8 noiseLevel; |
| WebRtc_UWord8 RERL; |
| WebRtc_UWord8 Gmin; |
| WebRtc_UWord8 Rfactor; |
| WebRtc_UWord8 extRfactor; |
| WebRtc_UWord8 MOSLQ; |
| WebRtc_UWord8 MOSCQ; |
| WebRtc_UWord8 RXconfig; |
| WebRtc_UWord16 JBnominal; |
| WebRtc_UWord16 JBmax; |
| WebRtc_UWord16 JBabsMax; |
| }; |
| |
| // Types for the FEC packet masks. The type |kFecMaskRandom| is based on a |
| // random loss model. The type |kFecMaskBursty| is based on a bursty/consecutive |
| // loss model. The packet masks are defined in |
| // modules/rtp_rtcp/fec_private_tables_random(bursty).h |
| enum FecMaskType { |
| kFecMaskRandom, |
| kFecMaskBursty, |
| }; |
| |
| // Struct containing forward error correction settings. |
| struct FecProtectionParams { |
| int fec_rate; |
| bool use_uep_protection; |
| int max_fec_frames; |
| FecMaskType fec_mask_type; |
| }; |
| |
| // class describing a complete, or parts of an encoded frame. |
| class EncodedVideoData |
| { |
| public: |
| EncodedVideoData() : |
| payloadType(0), |
| timeStamp(0), |
| renderTimeMs(0), |
| encodedWidth(0), |
| encodedHeight(0), |
| completeFrame(false), |
| missingFrame(false), |
| payloadData(NULL), |
| payloadSize(0), |
| bufferSize(0), |
| fragmentationHeader(), |
| frameType(kVideoFrameDelta), |
| codec(kVideoCodecUnknown) |
| {}; |
| |
| EncodedVideoData(const EncodedVideoData& data) |
| { |
| payloadType = data.payloadType; |
| timeStamp = data.timeStamp; |
| renderTimeMs = data.renderTimeMs; |
| encodedWidth = data.encodedWidth; |
| encodedHeight = data.encodedHeight; |
| completeFrame = data.completeFrame; |
| missingFrame = data.missingFrame; |
| payloadSize = data.payloadSize; |
| fragmentationHeader = data.fragmentationHeader; |
| frameType = data.frameType; |
| codec = data.codec; |
| if (data.payloadSize > 0) |
| { |
| payloadData = new WebRtc_UWord8[data.payloadSize]; |
| memcpy(payloadData, data.payloadData, data.payloadSize); |
| } |
| else |
| { |
| payloadData = NULL; |
| } |
| } |
| |
| |
| ~EncodedVideoData() |
| { |
| delete [] payloadData; |
| }; |
| |
| EncodedVideoData& operator=(const EncodedVideoData& data) |
| { |
| if (this == &data) |
| { |
| return *this; |
| } |
| payloadType = data.payloadType; |
| timeStamp = data.timeStamp; |
| renderTimeMs = data.renderTimeMs; |
| encodedWidth = data.encodedWidth; |
| encodedHeight = data.encodedHeight; |
| completeFrame = data.completeFrame; |
| missingFrame = data.missingFrame; |
| payloadSize = data.payloadSize; |
| fragmentationHeader = data.fragmentationHeader; |
| frameType = data.frameType; |
| codec = data.codec; |
| if (data.payloadSize > 0) |
| { |
| delete [] payloadData; |
| payloadData = new WebRtc_UWord8[data.payloadSize]; |
| memcpy(payloadData, data.payloadData, data.payloadSize); |
| bufferSize = data.payloadSize; |
| } |
| return *this; |
| }; |
| void VerifyAndAllocate( const WebRtc_UWord32 size) |
| { |
| if (bufferSize < size) |
| { |
| WebRtc_UWord8* oldPayload = payloadData; |
| payloadData = new WebRtc_UWord8[size]; |
| memcpy(payloadData, oldPayload, sizeof(WebRtc_UWord8) * payloadSize); |
| |
| bufferSize = size; |
| delete[] oldPayload; |
| } |
| } |
| |
| WebRtc_UWord8 payloadType; |
| WebRtc_UWord32 timeStamp; |
| WebRtc_Word64 renderTimeMs; |
| WebRtc_UWord32 encodedWidth; |
| WebRtc_UWord32 encodedHeight; |
| bool completeFrame; |
| bool missingFrame; |
| WebRtc_UWord8* payloadData; |
| WebRtc_UWord32 payloadSize; |
| WebRtc_UWord32 bufferSize; |
| RTPFragmentationHeader fragmentationHeader; |
| FrameType frameType; |
| VideoCodecType codec; |
| }; |
| |
| struct VideoContentMetrics { |
| VideoContentMetrics() |
| : motion_magnitude(0.0f), |
| spatial_pred_err(0.0f), |
| spatial_pred_err_h(0.0f), |
| spatial_pred_err_v(0.0f) { |
| } |
| |
| void Reset() { |
| motion_magnitude = 0.0f; |
| spatial_pred_err = 0.0f; |
| spatial_pred_err_h = 0.0f; |
| spatial_pred_err_v = 0.0f; |
| } |
| float motion_magnitude; |
| float spatial_pred_err; |
| float spatial_pred_err_h; |
| float spatial_pred_err_v; |
| }; |
| |
| /************************************************* |
| * |
| * VideoFrame class |
| * |
| * The VideoFrame class allows storing and |
| * handling of video frames. |
| * |
| * |
| *************************************************/ |
| class VideoFrame |
| { |
| public: |
| VideoFrame(); |
| ~VideoFrame(); |
| /** |
| * Verifies that current allocated buffer size is larger than or equal to the input size. |
| * If the current buffer size is smaller, a new allocation is made and the old buffer data |
| * is copied to the new buffer. |
| * Buffer size is updated to minimumSize. |
| */ |
| WebRtc_Word32 VerifyAndAllocate(const WebRtc_UWord32 minimumSize); |
| /** |
| * Update length of data buffer in frame. Function verifies that new length is less or |
| * equal to allocated size. |
| */ |
| WebRtc_Word32 SetLength(const WebRtc_UWord32 newLength); |
| /* |
| * Swap buffer and size data |
| */ |
| WebRtc_Word32 Swap(WebRtc_UWord8*& newMemory, |
| WebRtc_UWord32& newLength, |
| WebRtc_UWord32& newSize); |
| /* |
| * Swap buffer and size data |
| */ |
| WebRtc_Word32 SwapFrame(VideoFrame& videoFrame); |
| /** |
| * Copy buffer: If newLength is bigger than allocated size, a new buffer of size length |
| * is allocated. |
| */ |
| WebRtc_Word32 CopyFrame(const VideoFrame& videoFrame); |
| /** |
| * Copy buffer: If newLength is bigger than allocated size, a new buffer of size length |
| * is allocated. |
| */ |
| WebRtc_Word32 CopyFrame(WebRtc_UWord32 length, const WebRtc_UWord8* sourceBuffer); |
| /** |
| * Delete VideoFrame and resets members to zero |
| */ |
| void Free(); |
| /** |
| * Set frame timestamp (90kHz) |
| */ |
| void SetTimeStamp(const WebRtc_UWord32 timeStamp) {_timeStamp = timeStamp;} |
| /** |
| * Get pointer to frame buffer |
| */ |
| WebRtc_UWord8* Buffer() const {return _buffer;} |
| |
| WebRtc_UWord8*& Buffer() {return _buffer;} |
| |
| /** |
| * Get allocated buffer size |
| */ |
| WebRtc_UWord32 Size() const {return _bufferSize;} |
| /** |
| * Get frame length |
| */ |
| WebRtc_UWord32 Length() const {return _bufferLength;} |
| /** |
| * Get frame timestamp (90kHz) |
| */ |
| WebRtc_UWord32 TimeStamp() const {return _timeStamp;} |
| /** |
| * Get frame width |
| */ |
| WebRtc_UWord32 Width() const {return _width;} |
| /** |
| * Get frame height |
| */ |
| WebRtc_UWord32 Height() const {return _height;} |
| /** |
| * Set frame width |
| */ |
| void SetWidth(const WebRtc_UWord32 width) {_width = width;} |
| /** |
| * Set frame height |
| */ |
| void SetHeight(const WebRtc_UWord32 height) {_height = height;} |
| /** |
| * Set render time in miliseconds |
| */ |
| void SetRenderTime(const WebRtc_Word64 renderTimeMs) {_renderTimeMs = renderTimeMs;} |
| /** |
| * Get render time in miliseconds |
| */ |
| WebRtc_Word64 RenderTimeMs() const {return _renderTimeMs;} |
| |
| private: |
| void Set(WebRtc_UWord8* buffer, |
| WebRtc_UWord32 size, |
| WebRtc_UWord32 length, |
| WebRtc_UWord32 timeStamp); |
| |
| WebRtc_UWord8* _buffer; // Pointer to frame buffer |
| WebRtc_UWord32 _bufferSize; // Allocated buffer size |
| WebRtc_UWord32 _bufferLength; // Length (in bytes) of buffer |
| WebRtc_UWord32 _timeStamp; // Timestamp of frame (90kHz) |
| WebRtc_UWord32 _width; |
| WebRtc_UWord32 _height; |
| WebRtc_Word64 _renderTimeMs; |
| }; // end of VideoFrame class declaration |
| |
| // inline implementation of VideoFrame class: |
| inline |
| VideoFrame::VideoFrame(): |
| _buffer(0), |
| _bufferSize(0), |
| _bufferLength(0), |
| _timeStamp(0), |
| _width(0), |
| _height(0), |
| _renderTimeMs(0) |
| { |
| // |
| } |
| inline |
| VideoFrame::~VideoFrame() |
| { |
| if(_buffer) |
| { |
| delete [] _buffer; |
| _buffer = NULL; |
| } |
| } |
| |
| |
| inline |
| WebRtc_Word32 |
| VideoFrame::VerifyAndAllocate(const WebRtc_UWord32 minimumSize) |
| { |
| if (minimumSize < 1) |
| { |
| return -1; |
| } |
| if(minimumSize > _bufferSize) |
| { |
| // create buffer of sufficient size |
| WebRtc_UWord8* newBufferBuffer = new WebRtc_UWord8[minimumSize]; |
| if(_buffer) |
| { |
| // copy old data |
| memcpy(newBufferBuffer, _buffer, _bufferSize); |
| delete [] _buffer; |
| } |
| else |
| { |
| memset(newBufferBuffer, 0, minimumSize * sizeof(WebRtc_UWord8)); |
| } |
| _buffer = newBufferBuffer; |
| _bufferSize = minimumSize; |
| } |
| return 0; |
| } |
| |
| inline |
| WebRtc_Word32 |
| VideoFrame::SetLength(const WebRtc_UWord32 newLength) |
| { |
| if (newLength >_bufferSize ) |
| { // can't accomodate new value |
| return -1; |
| } |
| _bufferLength = newLength; |
| return 0; |
| } |
| |
| inline |
| WebRtc_Word32 |
| VideoFrame::SwapFrame(VideoFrame& videoFrame) |
| { |
| WebRtc_UWord32 tmpTimeStamp = _timeStamp; |
| WebRtc_UWord32 tmpWidth = _width; |
| WebRtc_UWord32 tmpHeight = _height; |
| WebRtc_Word64 tmpRenderTime = _renderTimeMs; |
| |
| _timeStamp = videoFrame._timeStamp; |
| _width = videoFrame._width; |
| _height = videoFrame._height; |
| _renderTimeMs = videoFrame._renderTimeMs; |
| |
| videoFrame._timeStamp = tmpTimeStamp; |
| videoFrame._width = tmpWidth; |
| videoFrame._height = tmpHeight; |
| videoFrame._renderTimeMs = tmpRenderTime; |
| |
| return Swap(videoFrame._buffer, videoFrame._bufferLength, videoFrame._bufferSize); |
| } |
| |
| inline |
| WebRtc_Word32 |
| VideoFrame::Swap(WebRtc_UWord8*& newMemory, WebRtc_UWord32& newLength, WebRtc_UWord32& newSize) |
| { |
| WebRtc_UWord8* tmpBuffer = _buffer; |
| WebRtc_UWord32 tmpLength = _bufferLength; |
| WebRtc_UWord32 tmpSize = _bufferSize; |
| _buffer = newMemory; |
| _bufferLength = newLength; |
| _bufferSize = newSize; |
| newMemory = tmpBuffer; |
| newLength = tmpLength; |
| newSize = tmpSize; |
| return 0; |
| } |
| |
| inline |
| WebRtc_Word32 |
| VideoFrame::CopyFrame(WebRtc_UWord32 length, const WebRtc_UWord8* sourceBuffer) |
| { |
| if (length > _bufferSize) |
| { |
| WebRtc_Word32 ret = VerifyAndAllocate(length); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| } |
| memcpy(_buffer, sourceBuffer, length); |
| _bufferLength = length; |
| return 0; |
| } |
| |
| inline |
| WebRtc_Word32 |
| VideoFrame::CopyFrame(const VideoFrame& videoFrame) |
| { |
| if(CopyFrame(videoFrame.Length(), videoFrame.Buffer()) != 0) |
| { |
| return -1; |
| } |
| _timeStamp = videoFrame._timeStamp; |
| _width = videoFrame._width; |
| _height = videoFrame._height; |
| _renderTimeMs = videoFrame._renderTimeMs; |
| return 0; |
| } |
| |
| inline |
| void |
| VideoFrame::Free() |
| { |
| _timeStamp = 0; |
| _bufferLength = 0; |
| _bufferSize = 0; |
| _height = 0; |
| _width = 0; |
| _renderTimeMs = 0; |
| |
| if(_buffer) |
| { |
| delete [] _buffer; |
| _buffer = NULL; |
| } |
| } |
| |
| |
| /* This class holds up to 60 ms of super-wideband (32 kHz) stereo audio. It |
| * allows for adding and subtracting frames while keeping track of the resulting |
| * states. |
| * |
| * Notes |
| * - The total number of samples in |data_| is |
| * samples_per_channel_ * num_channels_ |
| * |
| * - Stereo data is interleaved starting with the left channel. |
| * |
| * - The +operator assume that you would never add exactly opposite frames when |
| * deciding the resulting state. To do this use the -operator. |
| */ |
| class AudioFrame |
| { |
| public: |
| enum { kMaxDataSizeSamples = 3840 }; // stereo, 32 kHz, 60ms (2*32*60) |
| |
| enum VADActivity |
| { |
| kVadActive = 0, |
| kVadPassive = 1, |
| kVadUnknown = 2 |
| }; |
| enum SpeechType |
| { |
| kNormalSpeech = 0, |
| kPLC = 1, |
| kCNG = 2, |
| kPLCCNG = 3, |
| kUndefined = 4 |
| }; |
| |
| AudioFrame(); |
| virtual ~AudioFrame(); |
| |
| int UpdateFrame( |
| int id, |
| uint32_t timestamp, |
| const int16_t* data, |
| int samples_per_channel, |
| int sample_rate_hz, |
| SpeechType speech_type, |
| VADActivity vad_activity, |
| int num_channels = 1, |
| uint32_t energy = -1); |
| |
| AudioFrame& Append(const AudioFrame& rhs); |
| |
| void Mute(); |
| |
| AudioFrame& operator=(const AudioFrame& rhs); |
| AudioFrame& operator>>=(const int rhs); |
| AudioFrame& operator+=(const AudioFrame& rhs); |
| AudioFrame& operator-=(const AudioFrame& rhs); |
| |
| int id_; |
| uint32_t timestamp_; |
| int16_t data_[kMaxDataSizeSamples]; |
| int samples_per_channel_; |
| int sample_rate_hz_; |
| int num_channels_; |
| SpeechType speech_type_; |
| VADActivity vad_activity_; |
| uint32_t energy_; |
| }; |
| |
| inline |
| AudioFrame::AudioFrame() |
| : |
| id_(-1), |
| timestamp_(0), |
| data_(), |
| samples_per_channel_(0), |
| sample_rate_hz_(0), |
| num_channels_(1), |
| speech_type_(kUndefined), |
| vad_activity_(kVadUnknown), |
| energy_(0xffffffff) |
| { |
| } |
| |
| inline |
| AudioFrame::~AudioFrame() |
| { |
| } |
| |
| inline |
| int |
| AudioFrame::UpdateFrame( |
| int id, |
| uint32_t timestamp, |
| const int16_t* data, |
| int samples_per_channel, |
| int sample_rate_hz, |
| SpeechType speech_type, |
| VADActivity vad_activity, |
| int num_channels, |
| uint32_t energy) |
| { |
| id_ = id; |
| timestamp_ = timestamp; |
| sample_rate_hz_ = sample_rate_hz; |
| speech_type_ = speech_type; |
| vad_activity_ = vad_activity; |
| num_channels_ = num_channels; |
| energy_ = energy; |
| |
| if((samples_per_channel > kMaxDataSizeSamples) || |
| (num_channels > 2) || (num_channels < 1)) |
| { |
| samples_per_channel_ = 0; |
| return -1; |
| } |
| samples_per_channel_ = samples_per_channel; |
| if(data != NULL) |
| { |
| memcpy(data_, data, sizeof(int16_t) * |
| samples_per_channel * num_channels_); |
| } |
| else |
| { |
| memset(data_,0,sizeof(int16_t) * |
| samples_per_channel * num_channels_); |
| } |
| return 0; |
| } |
| |
| inline |
| void |
| AudioFrame::Mute() |
| { |
| memset(data_, 0, samples_per_channel_ * num_channels_ * sizeof(int16_t)); |
| } |
| |
| inline |
| AudioFrame& |
| AudioFrame::operator=(const AudioFrame& rhs) |
| { |
| // Sanity Check |
| if((rhs.samples_per_channel_ > kMaxDataSizeSamples) || |
| (rhs.num_channels_ > 2) || |
| (rhs.num_channels_ < 1)) |
| { |
| return *this; |
| } |
| if(this == &rhs) |
| { |
| return *this; |
| } |
| id_ = rhs.id_; |
| timestamp_ = rhs.timestamp_; |
| sample_rate_hz_ = rhs.sample_rate_hz_; |
| speech_type_ = rhs.speech_type_; |
| vad_activity_ = rhs.vad_activity_; |
| num_channels_ = rhs.num_channels_; |
| energy_ = rhs.energy_; |
| |
| samples_per_channel_ = rhs.samples_per_channel_; |
| memcpy(data_, rhs.data_, |
| sizeof(int16_t) * rhs.samples_per_channel_ * num_channels_); |
| |
| return *this; |
| } |
| |
| inline |
| AudioFrame& |
| AudioFrame::operator>>=(const int rhs) |
| { |
| assert((num_channels_ > 0) && (num_channels_ < 3)); |
| if((num_channels_ > 2) || |
| (num_channels_ < 1)) |
| { |
| return *this; |
| } |
| for(int i = 0; i < samples_per_channel_ * num_channels_; i++) |
| { |
| data_[i] = static_cast<int16_t>(data_[i] >> rhs); |
| } |
| return *this; |
| } |
| |
| inline |
| AudioFrame& |
| AudioFrame::Append(const AudioFrame& rhs) |
| { |
| // Sanity check |
| assert((num_channels_ > 0) && (num_channels_ < 3)); |
| if((num_channels_ > 2) || |
| (num_channels_ < 1)) |
| { |
| return *this; |
| } |
| if(num_channels_ != rhs.num_channels_) |
| { |
| return *this; |
| } |
| if((vad_activity_ == kVadActive) || |
| rhs.vad_activity_ == kVadActive) |
| { |
| vad_activity_ = kVadActive; |
| } |
| else if((vad_activity_ == kVadUnknown) || |
| rhs.vad_activity_ == kVadUnknown) |
| { |
| vad_activity_ = kVadUnknown; |
| } |
| if(speech_type_ != rhs.speech_type_) |
| { |
| speech_type_ = kUndefined; |
| } |
| |
| int offset = samples_per_channel_ * num_channels_; |
| for(int i = 0; |
| i < rhs.samples_per_channel_ * rhs.num_channels_; |
| i++) |
| { |
| data_[offset+i] = rhs.data_[i]; |
| } |
| samples_per_channel_ += rhs.samples_per_channel_; |
| return *this; |
| } |
| |
| // merge vectors |
| inline |
| AudioFrame& |
| AudioFrame::operator+=(const AudioFrame& rhs) |
| { |
| // Sanity check |
| assert((num_channels_ > 0) && (num_channels_ < 3)); |
| if((num_channels_ > 2) || |
| (num_channels_ < 1)) |
| { |
| return *this; |
| } |
| if(num_channels_ != rhs.num_channels_) |
| { |
| return *this; |
| } |
| bool noPrevData = false; |
| if(samples_per_channel_ != rhs.samples_per_channel_) |
| { |
| if(samples_per_channel_ == 0) |
| { |
| // special case we have no data to start with |
| samples_per_channel_ = rhs.samples_per_channel_; |
| noPrevData = true; |
| } else |
| { |
| return *this; |
| } |
| } |
| |
| if((vad_activity_ == kVadActive) || |
| rhs.vad_activity_ == kVadActive) |
| { |
| vad_activity_ = kVadActive; |
| } |
| else if((vad_activity_ == kVadUnknown) || |
| rhs.vad_activity_ == kVadUnknown) |
| { |
| vad_activity_ = kVadUnknown; |
| } |
| |
| if(speech_type_ != rhs.speech_type_) |
| { |
| speech_type_ = kUndefined; |
| } |
| |
| if(noPrevData) |
| { |
| memcpy(data_, rhs.data_, |
| sizeof(int16_t) * rhs.samples_per_channel_ * num_channels_); |
| } else |
| { |
| // IMPROVEMENT this can be done very fast in assembly |
| for(int i = 0; i < samples_per_channel_ * num_channels_; i++) |
| { |
| int32_t wrapGuard = static_cast<int32_t>(data_[i]) + |
| static_cast<int32_t>(rhs.data_[i]); |
| if(wrapGuard < -32768) |
| { |
| data_[i] = -32768; |
| }else if(wrapGuard > 32767) |
| { |
| data_[i] = 32767; |
| }else |
| { |
| data_[i] = (int16_t)wrapGuard; |
| } |
| } |
| } |
| energy_ = 0xffffffff; |
| return *this; |
| } |
| |
| inline |
| AudioFrame& |
| AudioFrame::operator-=(const AudioFrame& rhs) |
| { |
| // Sanity check |
| assert((num_channels_ > 0) && (num_channels_ < 3)); |
| if((num_channels_ > 2)|| |
| (num_channels_ < 1)) |
| { |
| return *this; |
| } |
| if((samples_per_channel_ != rhs.samples_per_channel_) || |
| (num_channels_ != rhs.num_channels_)) |
| { |
| return *this; |
| } |
| if((vad_activity_ != kVadPassive) || |
| rhs.vad_activity_ != kVadPassive) |
| { |
| vad_activity_ = kVadUnknown; |
| } |
| speech_type_ = kUndefined; |
| |
| for(int i = 0; i < samples_per_channel_ * num_channels_; i++) |
| { |
| int32_t wrapGuard = static_cast<int32_t>(data_[i]) - |
| static_cast<int32_t>(rhs.data_[i]); |
| if(wrapGuard < -32768) |
| { |
| data_[i] = -32768; |
| } |
| else if(wrapGuard > 32767) |
| { |
| data_[i] = 32767; |
| } |
| else |
| { |
| data_[i] = (int16_t)wrapGuard; |
| } |
| } |
| energy_ = 0xffffffff; |
| return *this; |
| } |
| |
| } // namespace webrtc |
| |
| #endif // MODULE_COMMON_TYPES_H |