Generic video-codec support.
Labels frames as key/delta, also marks the first RTP packet of a frame as such, to allow proper reconstruction even if packets are received out of order. BUG=1442 TBR=ajm@webrtc.org Review URL: https://webrtc-codereview.appspot.com/1207004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@3680 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@@ -8,17 +8,18 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_VIDEO_CODING_CODECS_I420_H_
|
||||
#define WEBRTC_MODULES_VIDEO_CODING_CODECS_I420_H_
|
||||
#ifndef WEBRTC_MODULES_VIDEO_CODING_CODECS_I420_MAIN_INTERFACE_I420_H_
|
||||
#define WEBRTC_MODULES_VIDEO_CODING_CODECS_I420_MAIN_INTERFACE_I420_H_
|
||||
|
||||
#include "video_codec_interface.h"
|
||||
#include "typedefs.h"
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class I420Encoder : public VideoEncoder {
|
||||
public:
|
||||
|
||||
public:
|
||||
I420Encoder();
|
||||
|
||||
virtual ~I420Encoder();
|
||||
@@ -64,25 +65,29 @@ public:
|
||||
// Return value : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise.
|
||||
virtual int Release();
|
||||
|
||||
virtual int SetRates(uint32_t /*newBitRate*/, uint32_t /*frameRate*/)
|
||||
{return WEBRTC_VIDEO_CODEC_OK;}
|
||||
virtual int SetRates(uint32_t /*newBitRate*/, uint32_t /*frameRate*/) {
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
virtual int SetChannelParameters(uint32_t /*packetLoss*/, int /*rtt*/)
|
||||
{return WEBRTC_VIDEO_CODEC_OK;}
|
||||
virtual int SetChannelParameters(uint32_t /*packetLoss*/, int /*rtt*/) {
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
virtual int CodecConfigParameters(uint8_t* /*buffer*/, int /*size*/)
|
||||
{return WEBRTC_VIDEO_CODEC_OK;}
|
||||
virtual int CodecConfigParameters(uint8_t* /*buffer*/, int /*size*/) {
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
static uint8_t* InsertHeader(uint8_t* buffer, uint16_t width,
|
||||
uint16_t height);
|
||||
|
||||
private:
|
||||
bool _inited;
|
||||
EncodedImage _encodedImage;
|
||||
EncodedImageCallback* _encodedCompleteCallback;
|
||||
|
||||
}; // end of WebRtcI420DEncoder class
|
||||
}; // class I420Encoder
|
||||
|
||||
class I420Decoder : public VideoDecoder {
|
||||
public:
|
||||
|
||||
public:
|
||||
I420Decoder();
|
||||
|
||||
virtual ~I420Decoder();
|
||||
@@ -95,8 +100,10 @@ public:
|
||||
virtual int InitDecode(const VideoCodec* codecSettings,
|
||||
int /*numberOfCores*/);
|
||||
|
||||
virtual int SetCodecConfigParameters(const uint8_t* /*buffer*/, int /*size*/)
|
||||
{return WEBRTC_VIDEO_CODEC_OK;};
|
||||
virtual int SetCodecConfigParameters(const uint8_t* /*buffer*/,
|
||||
int /*size*/) {
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
// Decode encoded image (as a part of a video stream). The decoded image
|
||||
// will be returned to the user through the decode complete callback.
|
||||
@@ -136,16 +143,17 @@ public:
|
||||
// <0 - Error
|
||||
virtual int Reset();
|
||||
|
||||
private:
|
||||
private:
|
||||
static const uint8_t* ExtractHeader(const uint8_t* buffer, uint16_t* width,
|
||||
uint16_t* height);
|
||||
|
||||
I420VideoFrame _decodedImage;
|
||||
int _width;
|
||||
int _height;
|
||||
bool _inited;
|
||||
DecodedImageCallback* _decodeCompleteCallback;
|
||||
}; // class I420Decoder
|
||||
|
||||
}; // End of WebRtcI420Decoder class.
|
||||
} // namespace webrtc
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_VIDEO_CODING_CODECS_I420_H_
|
||||
#endif // WEBRTC_MODULES_VIDEO_CODING_CODECS_I420_MAIN_INTERFACE_I420_H_
|
||||
|
||||
@@ -10,25 +10,20 @@
|
||||
|
||||
#include "modules/video_coding/codecs/i420/main/interface/i420.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <limits>
|
||||
|
||||
#include "common_video/libyuv/include/webrtc_libyuv.h"
|
||||
|
||||
namespace webrtc
|
||||
{
|
||||
namespace webrtc {
|
||||
|
||||
I420Encoder::I420Encoder():
|
||||
_inited(false),
|
||||
_encodedImage(),
|
||||
_encodedCompleteCallback(NULL)
|
||||
{}
|
||||
I420Encoder::I420Encoder() : _inited(false), _encodedImage(),
|
||||
_encodedCompleteCallback(NULL) {
|
||||
}
|
||||
|
||||
I420Encoder::~I420Encoder() {
|
||||
_inited = false;
|
||||
if (_encodedImage._buffer != NULL) {
|
||||
delete [] _encodedImage._buffer;
|
||||
_encodedImage._buffer = NULL;
|
||||
}
|
||||
delete [] _encodedImage._buffer;
|
||||
}
|
||||
|
||||
int I420Encoder::Release() {
|
||||
@@ -85,37 +80,53 @@ int I420Encoder::Encode(const I420VideoFrame& inputImage,
|
||||
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
|
||||
}
|
||||
|
||||
_encodedImage._frameType = kKeyFrame; // No coding.
|
||||
_encodedImage._frameType = kKeyFrame;
|
||||
_encodedImage._timeStamp = inputImage.timestamp();
|
||||
_encodedImage._encodedHeight = inputImage.height();
|
||||
_encodedImage._encodedWidth = inputImage.width();
|
||||
|
||||
int req_length = CalcBufferSize(kI420, inputImage.width(),
|
||||
inputImage.height());
|
||||
if (_encodedImage._size > static_cast<unsigned int>(req_length)) {
|
||||
// Allocating encoded memory.
|
||||
if (_encodedImage._buffer != NULL) {
|
||||
delete [] _encodedImage._buffer;
|
||||
_encodedImage._buffer = NULL;
|
||||
_encodedImage._size = 0;
|
||||
}
|
||||
uint8_t* newBuffer = new uint8_t[req_length];
|
||||
if (newBuffer == NULL) {
|
||||
return WEBRTC_VIDEO_CODEC_MEMORY;
|
||||
}
|
||||
_encodedImage._size = req_length;
|
||||
_encodedImage._buffer = newBuffer;
|
||||
int width = inputImage.width();
|
||||
if (width > std::numeric_limits<uint16_t>::max()) {
|
||||
return WEBRTC_VIDEO_CODEC_ERR_SIZE;
|
||||
}
|
||||
int height = inputImage.height();
|
||||
if (height > std::numeric_limits<uint16_t>::max()) {
|
||||
return WEBRTC_VIDEO_CODEC_ERR_SIZE;
|
||||
}
|
||||
|
||||
int ret_length = ExtractBuffer(inputImage, req_length, _encodedImage._buffer);
|
||||
const size_t kI420HeaderSize = 4;
|
||||
int req_length = CalcBufferSize(kI420, inputImage.width(),
|
||||
inputImage.height()) + kI420HeaderSize;
|
||||
if (_encodedImage._size > static_cast<unsigned int>(req_length)) {
|
||||
// Reallocate buffer.
|
||||
delete [] _encodedImage._buffer;
|
||||
|
||||
_encodedImage._buffer = new uint8_t[req_length];
|
||||
_encodedImage._size = req_length;
|
||||
}
|
||||
|
||||
uint8_t *buffer = _encodedImage._buffer;
|
||||
|
||||
buffer = InsertHeader(buffer, width, height);
|
||||
|
||||
int ret_length = ExtractBuffer(inputImage, req_length - kI420HeaderSize,
|
||||
buffer);
|
||||
if (ret_length < 0)
|
||||
return WEBRTC_VIDEO_CODEC_MEMORY;
|
||||
_encodedImage._length = ret_length;
|
||||
_encodedImage._length = ret_length + kI420HeaderSize;
|
||||
|
||||
_encodedCompleteCallback->Encoded(_encodedImage);
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
uint8_t* I420Encoder::InsertHeader(uint8_t *buffer, uint16_t width,
|
||||
uint16_t height) {
|
||||
*buffer++ = static_cast<uint8_t>(width >> 8);
|
||||
*buffer++ = static_cast<uint8_t>(width & 0xFF);
|
||||
*buffer++ = static_cast<uint8_t>(height >> 8);
|
||||
*buffer++ = static_cast<uint8_t>(height & 0xFF);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int
|
||||
I420Encoder::RegisterEncodeCompleteCallback(EncodedImageCallback* callback) {
|
||||
@@ -124,13 +135,9 @@ I420Encoder::RegisterEncodeCompleteCallback(EncodedImageCallback* callback) {
|
||||
}
|
||||
|
||||
|
||||
I420Decoder::I420Decoder():
|
||||
_decodedImage(),
|
||||
_width(0),
|
||||
_height(0),
|
||||
_inited(false),
|
||||
_decodeCompleteCallback(NULL)
|
||||
{}
|
||||
I420Decoder::I420Decoder() : _decodedImage(), _width(0), _height(0),
|
||||
_inited(false), _decodeCompleteCallback(NULL) {
|
||||
}
|
||||
|
||||
I420Decoder::~I420Decoder() {
|
||||
Release();
|
||||
@@ -156,12 +163,10 @@ I420Decoder::InitDecode(const VideoCodec* codecSettings,
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
int
|
||||
I420Decoder::Decode(const EncodedImage& inputImage,
|
||||
bool /*missingFrames*/,
|
||||
const RTPFragmentationHeader* /*fragmentation*/,
|
||||
const CodecSpecificInfo* /*codecSpecificInfo*/,
|
||||
int64_t /*renderTimeMs*/) {
|
||||
int I420Decoder::Decode(const EncodedImage& inputImage, bool /*missingFrames*/,
|
||||
const RTPFragmentationHeader* /*fragmentation*/,
|
||||
const CodecSpecificInfo* /*codecSpecificInfo*/,
|
||||
int64_t /*renderTimeMs*/) {
|
||||
if (inputImage._buffer == NULL) {
|
||||
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
|
||||
}
|
||||
@@ -175,8 +180,14 @@ I420Decoder::Decode(const EncodedImage& inputImage,
|
||||
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
|
||||
}
|
||||
if (!_inited) {
|
||||
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
|
||||
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
|
||||
}
|
||||
const uint8_t* buffer = inputImage._buffer;
|
||||
uint16_t width, height;
|
||||
|
||||
buffer = ExtractHeader(buffer, &width, &height);
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
// Verify that the available length is sufficient:
|
||||
int req_length = CalcBufferSize(kI420, _width, _height);
|
||||
@@ -187,9 +198,9 @@ I420Decoder::Decode(const EncodedImage& inputImage,
|
||||
int half_width = (_width + 1) / 2;
|
||||
_decodedImage.CreateEmptyFrame(_width, _height,
|
||||
_width, half_width, half_width);
|
||||
// Converting from buffer to plane representation.
|
||||
int ret = ConvertToI420(kI420, inputImage._buffer, 0, 0, _width, _height,
|
||||
0, kRotateNone, &_decodedImage);
|
||||
// Converting from buffer to plane representation.
|
||||
int ret = ConvertToI420(kI420, buffer, 0, 0, _width, _height, 0, kRotateNone,
|
||||
&_decodedImage);
|
||||
if (ret < 0) {
|
||||
return WEBRTC_VIDEO_CODEC_MEMORY;
|
||||
}
|
||||
@@ -199,16 +210,24 @@ I420Decoder::Decode(const EncodedImage& inputImage,
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
int
|
||||
I420Decoder::RegisterDecodeCompleteCallback(DecodedImageCallback* callback) {
|
||||
const uint8_t* I420Decoder::ExtractHeader(const uint8_t* buffer,
|
||||
uint16_t* width, uint16_t* height) {
|
||||
*width = static_cast<uint16_t>(*buffer++) << 8;
|
||||
*width |= *buffer++;
|
||||
*height = static_cast<uint16_t>(*buffer++) << 8;
|
||||
*height |= *buffer++;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int I420Decoder::RegisterDecodeCompleteCallback(
|
||||
DecodedImageCallback* callback) {
|
||||
_decodeCompleteCallback = callback;
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
int
|
||||
I420Decoder::Release() {
|
||||
int I420Decoder::Release() {
|
||||
_inited = false;
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
||||
Reference in New Issue
Block a user