summaryrefslogtreecommitdiffstats
path: root/tinyDAV/src/video/tdav_converter_video.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'tinyDAV/src/video/tdav_converter_video.cxx')
-rwxr-xr-xtinyDAV/src/video/tdav_converter_video.cxx1321
1 files changed, 660 insertions, 661 deletions
diff --git a/tinyDAV/src/video/tdav_converter_video.cxx b/tinyDAV/src/video/tdav_converter_video.cxx
index 2195d79..cc60b95 100755
--- a/tinyDAV/src/video/tdav_converter_video.cxx
+++ b/tinyDAV/src/video/tdav_converter_video.cxx
@@ -36,32 +36,31 @@
using namespace libyuv;
-typedef struct tdav_converter_video_libyuv_s
-{
- TMEDIA_DECLARE_CONVERTER_VIDEO;
-
- enum FourCC srcFormat;
- enum FourCC dstFormat;
-
- tsk_bool_t toI420;
- tsk_bool_t fromI420;
-
- struct{
- uint8* ptr;
- int size;
- }chroma;
- struct{
- uint8* ptr;
- int size;
- }rotate;
- struct{
- uint8* ptr;
- int size;
- }scale;
- struct{
- uint8* ptr;
- int size;
- }mirror;
+typedef struct tdav_converter_video_libyuv_s {
+ TMEDIA_DECLARE_CONVERTER_VIDEO;
+
+ enum FourCC srcFormat;
+ enum FourCC dstFormat;
+
+ tsk_bool_t toI420;
+ tsk_bool_t fromI420;
+
+ struct {
+ uint8* ptr;
+ int size;
+ } chroma;
+ struct {
+ uint8* ptr;
+ int size;
+ } rotate;
+ struct {
+ uint8* ptr;
+ int size;
+ } scale;
+ struct {
+ uint8* ptr;
+ int size;
+ } mirror;
}
tdav_converter_video_libyuv_t;
@@ -70,89 +69,88 @@ tdav_converter_video_libyuv_t;
static inline tsk_bool_t _tdav_converter_video_libyuv_is_chroma_varsize(tmedia_chroma_t chroma)
{
- return chroma == tmedia_chroma_mjpeg;
+ return chroma == tmedia_chroma_mjpeg;
}
static inline tsk_size_t _tdav_converter_video_libyuv_get_size(tmedia_chroma_t chroma, tsk_size_t w, tsk_size_t h)
{
- switch (chroma){
- case tmedia_chroma_rgb24:
- case tmedia_chroma_bgr24:
- return (w * h * 3);
- case tmedia_chroma_rgb565le:
- return ((w * h) << 1);
- case tmedia_chroma_rgb32:
- return ((w * h) << 2);
- case tmedia_chroma_nv21:
- return ((w * h * 3) >> 1);
- case tmedia_chroma_nv12:
- return ((w * h * 3) >> 1);
- case tmedia_chroma_yuv422p:
- return ((w * h) << 1);
- case tmedia_chroma_uyvy422:
- case tmedia_chroma_yuyv422:
- return ((w * h) << 1);
- case tmedia_chroma_yuv420p:
- return ((w * h * 3) >> 1);
- case tmedia_chroma_mjpeg:
- return 0;
- default:
- TSK_DEBUG_ERROR("Invalid chroma %d", (int)chroma);
- return 0;
- }
+ switch (chroma) {
+ case tmedia_chroma_rgb24:
+ case tmedia_chroma_bgr24:
+ return (w * h * 3);
+ case tmedia_chroma_rgb565le:
+ return ((w * h) << 1);
+ case tmedia_chroma_rgb32:
+ return ((w * h) << 2);
+ case tmedia_chroma_nv21:
+ return ((w * h * 3) >> 1);
+ case tmedia_chroma_nv12:
+ return ((w * h * 3) >> 1);
+ case tmedia_chroma_yuv422p:
+ return ((w * h) << 1);
+ case tmedia_chroma_uyvy422:
+ case tmedia_chroma_yuyv422:
+ return ((w * h) << 1);
+ case tmedia_chroma_yuv420p:
+ return ((w * h * 3) >> 1);
+ case tmedia_chroma_mjpeg:
+ return 0;
+ default:
+ TSK_DEBUG_ERROR("Invalid chroma %d", (int)chroma);
+ return 0;
+ }
}
static inline enum FourCC _tdav_converter_video_libyuv_get_pixfmt(tmedia_chroma_t chroma)
{
- switch (chroma){
- case tmedia_chroma_rgb24:
- case tmedia_chroma_bgr24:
- return FOURCC_24BG;
- case tmedia_chroma_rgb565le:
- return FOURCC_RGBP;
- case tmedia_chroma_rgb32:
- return FOURCC_ARGB;
- case tmedia_chroma_nv21:
- return FOURCC_NV21;
- case tmedia_chroma_nv12:
- return FOURCC_NV12;
- case tmedia_chroma_yuv422p:
- return FOURCC_I422;
- case tmedia_chroma_uyvy422:
- return FOURCC_UYVY;
- case tmedia_chroma_yuyv422:
- return FOURCC_YUY2;
- case tmedia_chroma_yuv420p:
- return FOURCC_I420;
- case tmedia_chroma_mjpeg:
- return FOURCC_MJPG;
- default:
- TSK_DEBUG_ERROR("Invalid chroma %d", (int)chroma);
- return FOURCC_ANY;
- }
+ switch (chroma) {
+ case tmedia_chroma_rgb24:
+ case tmedia_chroma_bgr24:
+ return FOURCC_24BG;
+ case tmedia_chroma_rgb565le:
+ return FOURCC_RGBP;
+ case tmedia_chroma_rgb32:
+ return FOURCC_ARGB;
+ case tmedia_chroma_nv21:
+ return FOURCC_NV21;
+ case tmedia_chroma_nv12:
+ return FOURCC_NV12;
+ case tmedia_chroma_yuv422p:
+ return FOURCC_I422;
+ case tmedia_chroma_uyvy422:
+ return FOURCC_UYVY;
+ case tmedia_chroma_yuyv422:
+ return FOURCC_YUY2;
+ case tmedia_chroma_yuv420p:
+ return FOURCC_I420;
+ case tmedia_chroma_mjpeg:
+ return FOURCC_MJPG;
+ default:
+ TSK_DEBUG_ERROR("Invalid chroma %d", (int)chroma);
+ return FOURCC_ANY;
+ }
}
static int tdav_converter_video_libyuv_init(tmedia_converter_video_t* self, tsk_size_t srcWidth, tsk_size_t srcHeight, tmedia_chroma_t srcChroma, tsk_size_t dstWidth, tsk_size_t dstHeight, tmedia_chroma_t dstChroma)
{
- TSK_DEBUG_INFO("Initializing new LibYUV Video Converter src=(%dx%d@%d) dst=(%dx%d@%d)", (int)srcWidth, (int)srcHeight, (int)srcChroma, (int)dstWidth, (int)dstHeight, (int)dstChroma);
-
- if ((TDAV_CONVERTER_VIDEO_LIBYUV(self)->srcFormat = _tdav_converter_video_libyuv_get_pixfmt(srcChroma)) == FOURCC_ANY){
- TSK_DEBUG_ERROR("Invalid source chroma");
- return -2;
- }
- if ((TDAV_CONVERTER_VIDEO_LIBYUV(self)->dstFormat = _tdav_converter_video_libyuv_get_pixfmt(dstChroma)) == FOURCC_ANY){
- TSK_DEBUG_ERROR("Invalid destination chroma");
- return -3;
- }
-
- TDAV_CONVERTER_VIDEO_LIBYUV(self)->toI420 = (TDAV_CONVERTER_VIDEO_LIBYUV(self)->dstFormat == FOURCC_I420);
- TDAV_CONVERTER_VIDEO_LIBYUV(self)->fromI420 = (TDAV_CONVERTER_VIDEO_LIBYUV(self)->srcFormat == FOURCC_I420);
- if (!TDAV_CONVERTER_VIDEO_LIBYUV(self)->toI420 && !TDAV_CONVERTER_VIDEO_LIBYUV(self)->fromI420)
- {
- TSK_DEBUG_ERROR("LIBYUV only support from/to I420");
- return -1;
- }
- return 0;
+ TSK_DEBUG_INFO("Initializing new LibYUV Video Converter src=(%dx%d@%d) dst=(%dx%d@%d)", (int)srcWidth, (int)srcHeight, (int)srcChroma, (int)dstWidth, (int)dstHeight, (int)dstChroma);
+
+ if ((TDAV_CONVERTER_VIDEO_LIBYUV(self)->srcFormat = _tdav_converter_video_libyuv_get_pixfmt(srcChroma)) == FOURCC_ANY) {
+ TSK_DEBUG_ERROR("Invalid source chroma");
+ return -2;
+ }
+ if ((TDAV_CONVERTER_VIDEO_LIBYUV(self)->dstFormat = _tdav_converter_video_libyuv_get_pixfmt(dstChroma)) == FOURCC_ANY) {
+ TSK_DEBUG_ERROR("Invalid destination chroma");
+ return -3;
+ }
+
+ TDAV_CONVERTER_VIDEO_LIBYUV(self)->toI420 = (TDAV_CONVERTER_VIDEO_LIBYUV(self)->dstFormat == FOURCC_I420);
+ TDAV_CONVERTER_VIDEO_LIBYUV(self)->fromI420 = (TDAV_CONVERTER_VIDEO_LIBYUV(self)->srcFormat == FOURCC_I420);
+ if (!TDAV_CONVERTER_VIDEO_LIBYUV(self)->toI420 && !TDAV_CONVERTER_VIDEO_LIBYUV(self)->fromI420) {
+ TSK_DEBUG_ERROR("LIBYUV only support from/to I420");
+ return -1;
+ }
+ return 0;
}
static tsk_size_t tdav_converter_video_libyuv_process(tmedia_converter_video_t* _self, const void* buffer, tsk_size_t buffer_size, void** output, tsk_size_t* output_max_size)
@@ -166,335 +164,339 @@ static tsk_size_t tdav_converter_video_libyuv_process(tmedia_converter_video_t*
} \
(curr_size) = (new_size); \
}
- static const int crop_x = 0;
- static const int crop_y = 0;
-
- int ret;
- tdav_converter_video_libyuv_t* self = TDAV_CONVERTER_VIDEO_LIBYUV(_self);
- tsk_bool_t scale = ((_self->dstWidth != _self->srcWidth) || (_self->dstHeight != _self->srcHeight));
- int s, ls, src_y_stride, src_u_stride, src_v_stride, dst_y_stride, dst_u_stride, dst_v_stride;
- int src_w, src_h, dst_w, dst_h;
- uint8 *dst_y, *dst_u, *dst_v, *src_y, *src_u, *src_v;
-
- RotationMode rotation = kRotate0;
-
- switch (_self->rotation){
- case 90: rotation = kRotate90; break;
- case 180: rotation = kRotate180; break;
- case 270: rotation = kRotate270; break;
- }
- //rotation = kRotate0;
-
- // not square and rotaion=270/90 -> requires scaling unless disabled
- if ((rotation == kRotate90 || rotation == kRotate270) && _self->scale_rotated_frames){
- scale |= (_self->dstWidth != _self->dstHeight) && (rotation == kRotate90 || rotation == kRotate270);
- }
-
- src_w = (int)_self->srcWidth, src_h = (int)_self->srcHeight;
-
- if (self->toI420) {
- tsk_size_t x_in_size;
- // check input size
- x_in_size = _tdav_converter_video_libyuv_is_chroma_varsize(_self->srcChroma) ? buffer_size : _tdav_converter_video_libyuv_get_size(_self->srcChroma, src_w, src_h);
- if (x_in_size > buffer_size) { // Ignore any extra data. For example, "CVPixelBufferGetDataSize()" will return size padded with 8 extra bytes for RGB32.
- TSK_DEBUG_ERROR("Invalid input size: %u>%u", (unsigned)x_in_size, (unsigned)buffer_size);
- return 0;
- }
-
- dst_w = src_w, dst_h = src_h; // because no scaling when converting to I420
- ls = src_w * src_h;
- s = ((ls * 3) >> 1);
- if (scale || rotation != kRotate0){
- RESIZE_BUFFER(self->chroma.ptr, self->chroma.size, s);
- dst_y = self->chroma.ptr;
- }
- else{
- RESIZE_BUFFER((*output), (*output_max_size), s);
- dst_y = (uint8*)*output;
- }
- dst_u = (dst_y + ls);
- dst_v = dst_u + (ls >> 2);
- src_y_stride = dst_y_stride = src_w;
- src_u_stride = src_v_stride = dst_u_stride = dst_v_stride = ((dst_y_stride + 1) >> 1);
-
- // convert to I420 without scaling or rotation
- ret = ConvertToI420(
- (const uint8*)buffer, (int)x_in_size,
- dst_y, dst_y_stride,
- dst_u, dst_u_stride,
- dst_v, dst_v_stride,
- crop_x, crop_y,
- (int)_self->srcWidth, (int)(_self->flip ? (_self->srcHeight * -1) : _self->srcHeight), // vertical flip
- (int)_self->srcWidth, (int)_self->srcHeight,
- kRotate0,
- (uint32)self->srcFormat);
- // mirror: horizontal flip (front camera video)
- if (_self->mirror) {
- RESIZE_BUFFER(self->mirror.ptr, self->mirror.size, s);
- ret = I420Mirror(
- dst_y, dst_y_stride,
- dst_u, dst_u_stride,
- dst_v, dst_v_stride,
- self->mirror.ptr, dst_y_stride,
- (self->mirror.ptr + ls), dst_u_stride,
- (self->mirror.ptr + ls + (ls >> 2)), dst_v_stride,
- (int)_self->srcWidth, (int)_self->srcHeight);
- memcpy(dst_y, self->mirror.ptr, s);
- }
-
- if (ret){
- TSK_DEBUG_ERROR("ConvertToI420 failed with error code = %d, in_size:%u", ret, x_in_size);
- return 0;
- }
-
- // rotate
- if (rotation != kRotate0){
- dst_w = (int)((rotation == kRotate90 || rotation == kRotate270) ? _self->srcHeight : _self->srcWidth);
- dst_h = (int)((rotation == kRotate90 || rotation == kRotate270) ? _self->srcWidth : _self->srcHeight);
-
- src_y = dst_y, src_u = dst_u, src_v = dst_v;
- src_y_stride = src_y_stride, src_u_stride = src_u_stride, src_v_stride = src_v_stride;
- dst_y_stride = dst_w;
- dst_u_stride = dst_v_stride = ((dst_y_stride + 1) >> 1);
-
- if (scale){
- RESIZE_BUFFER(self->rotate.ptr, self->rotate.size, s);
- dst_y = self->rotate.ptr;
- }
- else{// last step
- RESIZE_BUFFER((*output), (*output_max_size), s);
- dst_y = (uint8*)*output;
- }
-
- dst_u = (dst_y + ls);
- dst_v = dst_u + (ls >> 2);
- ret = I420Rotate(
- src_y, src_y_stride,
- src_u, src_u_stride,
- src_v, src_v_stride,
- dst_y, dst_y_stride,
- dst_u, dst_u_stride,
- dst_v, dst_v_stride,
- (int)_self->srcWidth, (int)_self->srcHeight, rotation);
- if (ret){
- TSK_DEBUG_ERROR("I420Rotate failed with error code = %d", ret);
- return 0;
- }
-
- // scale to fit ratio, pad, crop then copy
- if ((rotation == kRotate90 || rotation == kRotate270) && _self->scale_rotated_frames){
- int iwidth = (int)_self->srcHeight;
- int iheight = (int)_self->srcWidth;
-
- src_y = dst_y, src_u = dst_u, src_v = dst_v;
- src_w = dst_w, src_h = dst_h;
- src_y_stride = dst_y_stride, src_u_stride = dst_u_stride, src_v_stride = dst_v_stride;
-
- if (_self->dstWidth != _self->dstHeight) {
- if (iwidth * _self->srcHeight > iheight * _self->srcWidth) {
- iwidth = (int)((iheight * _self->srcWidth / _self->srcHeight) & ~1);
- int iwidth_offset = (int)((_self->srcHeight - iwidth) >> 1);
- src_y += iwidth_offset;
- src_u += iwidth_offset >> 1;
- src_v += iwidth_offset >> 1;
- }
- else if (iwidth * _self->srcHeight < iheight * _self->srcWidth) {
- iheight = (int)(iwidth * _self->srcHeight / _self->srcWidth);
- int iheight_offset = (int)((_self->srcWidth - iheight) >> 2);
- iheight_offset <<= 1;
- src_y += iheight_offset * src_y_stride;
- src_u += (iheight_offset >> 1) * src_u_stride;
- src_v += (iheight_offset >> 1) * src_v_stride;
- }
-
- src_w = iwidth, src_h = iheight;
- src_y_stride = src_w;
- src_u_stride = src_v_stride = ((src_y_stride + 1) >> 1);
-
- dst_w = (int)_self->dstWidth;
- dst_h = (int)_self->dstHeight;
- ls = dst_w * dst_h;
- s = ((ls * 3) >> 1);
- RESIZE_BUFFER((*output), (*output_max_size), s);
- dst_y_stride = dst_w;
- dst_u_stride = dst_v_stride = ((dst_y_stride + 1) >> 1);
- uint8* dst_y = (uint8*)*output;
- uint8* dst_u = (dst_y + ls);
- uint8* dst_v = dst_u + (ls >> 2);
-
- ret = I420Scale(
- src_y, src_y_stride,
- src_u, src_u_stride,
- src_v, src_v_stride,
- src_w, src_h,
- dst_y, dst_y_stride,
- dst_u, dst_u_stride,
- dst_v, dst_v_stride,
- dst_w, dst_h,
- kFilterBox);
- if (ret){
- TSK_DEBUG_ERROR("I420Scale failed with error code = %d", ret);
- return 0;
- }
- return s;
- }
- }
- }
-
- // scale
- if (scale){
- src_w = dst_w, src_h = dst_h;
- dst_w = (int)(((rotation == kRotate90 || rotation == kRotate270) && !_self->scale_rotated_frames) ? _self->dstHeight : _self->dstWidth);
- dst_h = (int)(((rotation == kRotate90 || rotation == kRotate270) && !_self->scale_rotated_frames) ? _self->dstWidth : _self->dstHeight);
- src_y = dst_y, src_u = dst_u, src_v = dst_v;
- src_y_stride = dst_y_stride, src_u_stride = dst_u_stride, src_v_stride = dst_v_stride;
- dst_y_stride = dst_w;
- dst_u_stride = dst_v_stride = ((dst_y_stride + 1) >> 1);
-
- ls = dst_w * dst_h;
- s = ((ls * 3) >> 1);
- RESIZE_BUFFER((*output), (*output_max_size), s);
- dst_y = (uint8*)*output;
- dst_u = (dst_y + ls);
- dst_v = dst_u + (ls >> 2);
-
- ret = I420Scale(
- src_y, src_y_stride,
- src_u, src_u_stride,
- src_v, src_v_stride,
- src_w, src_h,
- dst_y, dst_y_stride,
- dst_u, dst_u_stride,
- dst_v, dst_v_stride,
- dst_w, dst_h,
- kFilterNone);
- if (ret){
- TSK_DEBUG_ERROR("I420Scale failed with error code = %d", ret);
- return 0;
- }
- }
-
- return ((dst_w * dst_h * 3) >> 1);
- }
- else if (self->fromI420){
- static const int dst_sample_stride = 0;
-
- dst_w = (int)_self->dstWidth, dst_h = (int)_self->dstHeight;
- src_y = (uint8*)buffer;
- src_u = (src_y + (src_w * src_h));
- src_v = (src_u + ((src_w * src_h) >> 2));
- src_y_stride = src_w;
- src_u_stride = src_v_stride = ((src_y_stride + 1) >> 1);
-
- // mirror: horizontal flip (front camera video)
- if ((_self->mirror)) {
- ls = src_w * src_h;
- s = ((ls * 3) >> 1);
- if (s < (int)buffer_size) { // security check
- RESIZE_BUFFER(self->mirror.ptr, self->mirror.size, s);
- ret = I420Mirror(
- src_y, src_y_stride,
- src_u, src_u_stride,
- src_v, src_v_stride,
- self->mirror.ptr, src_y_stride,
- (self->mirror.ptr + ls), src_u_stride,
- (self->mirror.ptr + ls + (ls >> 2)), src_v_stride,
- src_w, src_h);
- memcpy(src_y, self->mirror.ptr, s);
- }
- }
-
- if (scale){
- ls = dst_w * dst_h;
- s = ((ls * 3) >> 1);
-
- RESIZE_BUFFER(self->scale.ptr, self->scale.size, s);
- dst_y = self->scale.ptr;
- dst_u = (dst_y + (dst_w * dst_h));
- dst_v = (dst_u + ((dst_w * dst_h) >> 2));
- dst_y_stride = dst_w;
- dst_u_stride = dst_v_stride = ((dst_y_stride + 1) >> 1);
-
- ret = I420Scale(
- src_y, src_y_stride,
- src_u, src_u_stride,
- src_v, src_v_stride,
- src_w, src_h,
- dst_y, dst_y_stride,
- dst_u, dst_u_stride,
- dst_v, dst_v_stride,
- dst_w, dst_h,
- kFilterNone);
-
- if (ret){
- TSK_DEBUG_ERROR("I420Scale failed with error code = %d", ret);
- return 0;
- }
-
- src_y = dst_y;
- src_u = (dst_y + ls);
- src_v = (dst_u + (ls >> 2));
- src_y_stride = dst_y_stride;
- src_u_stride = src_v_stride = ((src_y_stride + 1) >> 1);
- }
-
- s = (int)_tdav_converter_video_libyuv_get_size(_self->dstChroma, _self->srcWidth, _self->srcHeight);
- RESIZE_BUFFER((*output), (*output_max_size), s);
-
- ret = ConvertFromI420(
- src_y, src_y_stride,
- src_u, src_u_stride,
- src_v, src_v_stride,
- (uint8*)*output, dst_sample_stride,
- (int)_self->dstWidth, (_self->flip ? ((int)_self->dstHeight * -1) : (int)_self->dstHeight), // vertical flip
- (uint32)self->dstFormat);
- if (ret){
- TSK_DEBUG_ERROR("ConvertFromI420 failed with error code = %d", ret);
- return 0;
- }
-
- return s;
- }
-
- // Must be from/to I420
- TSK_DEBUG_ERROR("Not expected code called");
- return 0;
+ static const int crop_x = 0;
+ static const int crop_y = 0;
+
+ int ret;
+ tdav_converter_video_libyuv_t* self = TDAV_CONVERTER_VIDEO_LIBYUV(_self);
+ tsk_bool_t scale = ((_self->dstWidth != _self->srcWidth) || (_self->dstHeight != _self->srcHeight));
+ int s, ls, src_y_stride, src_u_stride, src_v_stride, dst_y_stride, dst_u_stride, dst_v_stride;
+ int src_w, src_h, dst_w, dst_h;
+ uint8 *dst_y, *dst_u, *dst_v, *src_y, *src_u, *src_v;
+
+ RotationMode rotation = kRotate0;
+
+ switch (_self->rotation) {
+ case 90:
+ rotation = kRotate90;
+ break;
+ case 180:
+ rotation = kRotate180;
+ break;
+ case 270:
+ rotation = kRotate270;
+ break;
+ }
+ //rotation = kRotate0;
+
+ // not square and rotaion=270/90 -> requires scaling unless disabled
+ if ((rotation == kRotate90 || rotation == kRotate270) && _self->scale_rotated_frames) {
+ scale |= (_self->dstWidth != _self->dstHeight) && (rotation == kRotate90 || rotation == kRotate270);
+ }
+
+ src_w = (int)_self->srcWidth, src_h = (int)_self->srcHeight;
+
+ if (self->toI420) {
+ tsk_size_t x_in_size;
+ // check input size
+ x_in_size = _tdav_converter_video_libyuv_is_chroma_varsize(_self->srcChroma) ? buffer_size : _tdav_converter_video_libyuv_get_size(_self->srcChroma, src_w, src_h);
+ if (x_in_size > buffer_size) { // Ignore any extra data. For example, "CVPixelBufferGetDataSize()" will return size padded with 8 extra bytes for RGB32.
+ TSK_DEBUG_ERROR("Invalid input size: %u>%u", (unsigned)x_in_size, (unsigned)buffer_size);
+ return 0;
+ }
+
+ dst_w = src_w, dst_h = src_h; // because no scaling when converting to I420
+ ls = src_w * src_h;
+ s = ((ls * 3) >> 1);
+ if (scale || rotation != kRotate0) {
+ RESIZE_BUFFER(self->chroma.ptr, self->chroma.size, s);
+ dst_y = self->chroma.ptr;
+ }
+ else {
+ RESIZE_BUFFER((*output), (*output_max_size), s);
+ dst_y = (uint8*)*output;
+ }
+ dst_u = (dst_y + ls);
+ dst_v = dst_u + (ls >> 2);
+ src_y_stride = dst_y_stride = src_w;
+ src_u_stride = src_v_stride = dst_u_stride = dst_v_stride = ((dst_y_stride + 1) >> 1);
+
+ // convert to I420 without scaling or rotation
+ ret = ConvertToI420(
+ (const uint8*)buffer, (int)x_in_size,
+ dst_y, dst_y_stride,
+ dst_u, dst_u_stride,
+ dst_v, dst_v_stride,
+ crop_x, crop_y,
+ (int)_self->srcWidth, (int)(_self->flip ? (_self->srcHeight * -1) : _self->srcHeight), // vertical flip
+ (int)_self->srcWidth, (int)_self->srcHeight,
+ kRotate0,
+ (uint32)self->srcFormat);
+ // mirror: horizontal flip (front camera video)
+ if (_self->mirror) {
+ RESIZE_BUFFER(self->mirror.ptr, self->mirror.size, s);
+ ret = I420Mirror(
+ dst_y, dst_y_stride,
+ dst_u, dst_u_stride,
+ dst_v, dst_v_stride,
+ self->mirror.ptr, dst_y_stride,
+ (self->mirror.ptr + ls), dst_u_stride,
+ (self->mirror.ptr + ls + (ls >> 2)), dst_v_stride,
+ (int)_self->srcWidth, (int)_self->srcHeight);
+ memcpy(dst_y, self->mirror.ptr, s);
+ }
+
+ if (ret) {
+ TSK_DEBUG_ERROR("ConvertToI420 failed with error code = %d, in_size:%u", ret, x_in_size);
+ return 0;
+ }
+
+ // rotate
+ if (rotation != kRotate0) {
+ dst_w = (int)((rotation == kRotate90 || rotation == kRotate270) ? _self->srcHeight : _self->srcWidth);
+ dst_h = (int)((rotation == kRotate90 || rotation == kRotate270) ? _self->srcWidth : _self->srcHeight);
+
+ src_y = dst_y, src_u = dst_u, src_v = dst_v;
+ src_y_stride = src_y_stride, src_u_stride = src_u_stride, src_v_stride = src_v_stride;
+ dst_y_stride = dst_w;
+ dst_u_stride = dst_v_stride = ((dst_y_stride + 1) >> 1);
+
+ if (scale) {
+ RESIZE_BUFFER(self->rotate.ptr, self->rotate.size, s);
+ dst_y = self->rotate.ptr;
+ }
+ else { // last step
+ RESIZE_BUFFER((*output), (*output_max_size), s);
+ dst_y = (uint8*)*output;
+ }
+
+ dst_u = (dst_y + ls);
+ dst_v = dst_u + (ls >> 2);
+ ret = I420Rotate(
+ src_y, src_y_stride,
+ src_u, src_u_stride,
+ src_v, src_v_stride,
+ dst_y, dst_y_stride,
+ dst_u, dst_u_stride,
+ dst_v, dst_v_stride,
+ (int)_self->srcWidth, (int)_self->srcHeight, rotation);
+ if (ret) {
+ TSK_DEBUG_ERROR("I420Rotate failed with error code = %d", ret);
+ return 0;
+ }
+
+ // scale to fit ratio, pad, crop then copy
+ if ((rotation == kRotate90 || rotation == kRotate270) && _self->scale_rotated_frames) {
+ int iwidth = (int)_self->srcHeight;
+ int iheight = (int)_self->srcWidth;
+
+ src_y = dst_y, src_u = dst_u, src_v = dst_v;
+ src_w = dst_w, src_h = dst_h;
+ src_y_stride = dst_y_stride, src_u_stride = dst_u_stride, src_v_stride = dst_v_stride;
+
+ if (_self->dstWidth != _self->dstHeight) {
+ if (iwidth * _self->srcHeight > iheight * _self->srcWidth) {
+ iwidth = (int)((iheight * _self->srcWidth / _self->srcHeight) & ~1);
+ int iwidth_offset = (int)((_self->srcHeight - iwidth) >> 1);
+ src_y += iwidth_offset;
+ src_u += iwidth_offset >> 1;
+ src_v += iwidth_offset >> 1;
+ }
+ else if (iwidth * _self->srcHeight < iheight * _self->srcWidth) {
+ iheight = (int)(iwidth * _self->srcHeight / _self->srcWidth);
+ int iheight_offset = (int)((_self->srcWidth - iheight) >> 2);
+ iheight_offset <<= 1;
+ src_y += iheight_offset * src_y_stride;
+ src_u += (iheight_offset >> 1) * src_u_stride;
+ src_v += (iheight_offset >> 1) * src_v_stride;
+ }
+
+ src_w = iwidth, src_h = iheight;
+ src_y_stride = src_w;
+ src_u_stride = src_v_stride = ((src_y_stride + 1) >> 1);
+
+ dst_w = (int)_self->dstWidth;
+ dst_h = (int)_self->dstHeight;
+ ls = dst_w * dst_h;
+ s = ((ls * 3) >> 1);
+ RESIZE_BUFFER((*output), (*output_max_size), s);
+ dst_y_stride = dst_w;
+ dst_u_stride = dst_v_stride = ((dst_y_stride + 1) >> 1);
+ uint8* dst_y = (uint8*)*output;
+ uint8* dst_u = (dst_y + ls);
+ uint8* dst_v = dst_u + (ls >> 2);
+
+ ret = I420Scale(
+ src_y, src_y_stride,
+ src_u, src_u_stride,
+ src_v, src_v_stride,
+ src_w, src_h,
+ dst_y, dst_y_stride,
+ dst_u, dst_u_stride,
+ dst_v, dst_v_stride,
+ dst_w, dst_h,
+ kFilterBox);
+ if (ret) {
+ TSK_DEBUG_ERROR("I420Scale failed with error code = %d", ret);
+ return 0;
+ }
+ return s;
+ }
+ }
+ }
+
+ // scale
+ if (scale) {
+ src_w = dst_w, src_h = dst_h;
+ dst_w = (int)(((rotation == kRotate90 || rotation == kRotate270) && !_self->scale_rotated_frames) ? _self->dstHeight : _self->dstWidth);
+ dst_h = (int)(((rotation == kRotate90 || rotation == kRotate270) && !_self->scale_rotated_frames) ? _self->dstWidth : _self->dstHeight);
+ src_y = dst_y, src_u = dst_u, src_v = dst_v;
+ src_y_stride = dst_y_stride, src_u_stride = dst_u_stride, src_v_stride = dst_v_stride;
+ dst_y_stride = dst_w;
+ dst_u_stride = dst_v_stride = ((dst_y_stride + 1) >> 1);
+
+ ls = dst_w * dst_h;
+ s = ((ls * 3) >> 1);
+ RESIZE_BUFFER((*output), (*output_max_size), s);
+ dst_y = (uint8*)*output;
+ dst_u = (dst_y + ls);
+ dst_v = dst_u + (ls >> 2);
+
+ ret = I420Scale(
+ src_y, src_y_stride,
+ src_u, src_u_stride,
+ src_v, src_v_stride,
+ src_w, src_h,
+ dst_y, dst_y_stride,
+ dst_u, dst_u_stride,
+ dst_v, dst_v_stride,
+ dst_w, dst_h,
+ kFilterNone);
+ if (ret) {
+ TSK_DEBUG_ERROR("I420Scale failed with error code = %d", ret);
+ return 0;
+ }
+ }
+
+ return ((dst_w * dst_h * 3) >> 1);
+ }
+ else if (self->fromI420) {
+ static const int dst_sample_stride = 0;
+
+ dst_w = (int)_self->dstWidth, dst_h = (int)_self->dstHeight;
+ src_y = (uint8*)buffer;
+ src_u = (src_y + (src_w * src_h));
+ src_v = (src_u + ((src_w * src_h) >> 2));
+ src_y_stride = src_w;
+ src_u_stride = src_v_stride = ((src_y_stride + 1) >> 1);
+
+ // mirror: horizontal flip (front camera video)
+ if ((_self->mirror)) {
+ ls = src_w * src_h;
+ s = ((ls * 3) >> 1);
+ if (s < (int)buffer_size) { // security check
+ RESIZE_BUFFER(self->mirror.ptr, self->mirror.size, s);
+ ret = I420Mirror(
+ src_y, src_y_stride,
+ src_u, src_u_stride,
+ src_v, src_v_stride,
+ self->mirror.ptr, src_y_stride,
+ (self->mirror.ptr + ls), src_u_stride,
+ (self->mirror.ptr + ls + (ls >> 2)), src_v_stride,
+ src_w, src_h);
+ memcpy(src_y, self->mirror.ptr, s);
+ }
+ }
+
+ if (scale) {
+ ls = dst_w * dst_h;
+ s = ((ls * 3) >> 1);
+
+ RESIZE_BUFFER(self->scale.ptr, self->scale.size, s);
+ dst_y = self->scale.ptr;
+ dst_u = (dst_y + (dst_w * dst_h));
+ dst_v = (dst_u + ((dst_w * dst_h) >> 2));
+ dst_y_stride = dst_w;
+ dst_u_stride = dst_v_stride = ((dst_y_stride + 1) >> 1);
+
+ ret = I420Scale(
+ src_y, src_y_stride,
+ src_u, src_u_stride,
+ src_v, src_v_stride,
+ src_w, src_h,
+ dst_y, dst_y_stride,
+ dst_u, dst_u_stride,
+ dst_v, dst_v_stride,
+ dst_w, dst_h,
+ kFilterNone);
+
+ if (ret) {
+ TSK_DEBUG_ERROR("I420Scale failed with error code = %d", ret);
+ return 0;
+ }
+
+ src_y = dst_y;
+ src_u = (dst_y + ls);
+ src_v = (dst_u + (ls >> 2));
+ src_y_stride = dst_y_stride;
+ src_u_stride = src_v_stride = ((src_y_stride + 1) >> 1);
+ }
+
+ s = (int)_tdav_converter_video_libyuv_get_size(_self->dstChroma, _self->srcWidth, _self->srcHeight);
+ RESIZE_BUFFER((*output), (*output_max_size), s);
+
+ ret = ConvertFromI420(
+ src_y, src_y_stride,
+ src_u, src_u_stride,
+ src_v, src_v_stride,
+ (uint8*)*output, dst_sample_stride,
+ (int)_self->dstWidth, (_self->flip ? ((int)_self->dstHeight * -1) : (int)_self->dstHeight), // vertical flip
+ (uint32)self->dstFormat);
+ if (ret) {
+ TSK_DEBUG_ERROR("ConvertFromI420 failed with error code = %d", ret);
+ return 0;
+ }
+
+ return s;
+ }
+
+ // Must be from/to I420
+ TSK_DEBUG_ERROR("Not expected code called");
+ return 0;
}
static tsk_object_t* tdav_converter_video_libyuv_ctor(tsk_object_t * self, va_list * app)
{
- tdav_converter_video_libyuv_t *converter = (tdav_converter_video_libyuv_t *)self;
- if (converter){
+ tdav_converter_video_libyuv_t *converter = (tdav_converter_video_libyuv_t *)self;
+ if (converter) {
- }
- return self;
+ }
+ return self;
}
static tsk_object_t* tdav_converter_video_libyuv_dtor(tsk_object_t * self)
{
- tdav_converter_video_libyuv_t *converter = (tdav_converter_video_libyuv_t *)self;
- if (converter){
- TSK_FREE(converter->chroma.ptr);
- TSK_FREE(converter->rotate.ptr);
- TSK_FREE(converter->scale.ptr);
- TSK_FREE(converter->mirror.ptr);
- }
-
- return self;
+ tdav_converter_video_libyuv_t *converter = (tdav_converter_video_libyuv_t *)self;
+ if (converter) {
+ TSK_FREE(converter->chroma.ptr);
+ TSK_FREE(converter->rotate.ptr);
+ TSK_FREE(converter->scale.ptr);
+ TSK_FREE(converter->mirror.ptr);
+ }
+
+ return self;
}
-static const tsk_object_def_t tdav_converter_video_libyuv_def_s =
-{
- sizeof(tdav_converter_video_libyuv_t),
- tdav_converter_video_libyuv_ctor,
- tdav_converter_video_libyuv_dtor,
- tsk_null,
+static const tsk_object_def_t tdav_converter_video_libyuv_def_s = {
+ sizeof(tdav_converter_video_libyuv_t),
+ tdav_converter_video_libyuv_ctor,
+ tdav_converter_video_libyuv_dtor,
+ tsk_null,
};
const tsk_object_def_t *tdav_converter_video_libyuv_def_t = &tdav_converter_video_libyuv_def_s;
-static const tmedia_converter_video_plugin_def_t tdav_converter_video_libyuv_plugin_def_s =
-{
- &tdav_converter_video_libyuv_def_s,
+static const tmedia_converter_video_plugin_def_t tdav_converter_video_libyuv_plugin_def_s = {
+ &tdav_converter_video_libyuv_def_s,
- tdav_converter_video_libyuv_init,
- tdav_converter_video_libyuv_process
+ tdav_converter_video_libyuv_init,
+ tdav_converter_video_libyuv_process
};
const tmedia_converter_video_plugin_def_t *tdav_converter_video_libyuv_plugin_def_t = &tdav_converter_video_libyuv_plugin_def_s;
@@ -516,24 +518,23 @@ extern "C" {
}
#endif
-typedef struct tdav_converter_video_ffmpeg_s
-{
- TMEDIA_DECLARE_CONVERTER_VIDEO;
+typedef struct tdav_converter_video_ffmpeg_s {
+ TMEDIA_DECLARE_CONVERTER_VIDEO;
- struct SwsContext *context;
+ struct SwsContext *context;
- enum PixelFormat srcFormat;
- enum PixelFormat dstFormat;
+ enum PixelFormat srcFormat;
+ enum PixelFormat dstFormat;
- AVFrame* srcFrame;
- AVFrame* dstFrame;
+ AVFrame* srcFrame;
+ AVFrame* dstFrame;
- struct {
- struct SwsContext *context;
- AVFrame* frame;
- uint8_t* buffer;
- tsk_size_t buffer_size;
- } rot;
+ struct {
+ struct SwsContext *context;
+ AVFrame* frame;
+ uint8_t* buffer;
+ tsk_size_t buffer_size;
+ } rot;
}
tdav_converter_video_ffmpeg_t;
@@ -563,207 +564,207 @@ tdav_converter_video_ffmpeg_t;
static inline enum PixelFormat _tdav_converter_video_ffmpeg_get_pixfmt(tmedia_chroma_t chroma)
{
- switch(chroma){
- case tmedia_chroma_rgb24:
- return PIX_FMT_RGB24;
- case tmedia_chroma_bgr24:
- return PIX_FMT_BGR24;
- case tmedia_chroma_rgb32:
- return PIX_FMT_RGB32;
- case tmedia_chroma_rgb565le:
- return PIX_FMT_RGB565LE;
- case tmedia_chroma_rgb565be:
- return PIX_FMT_RGB565BE;
- case tmedia_chroma_nv21:
- return PIX_FMT_NV21;
- case tmedia_chroma_nv12:
- return PIX_FMT_NV12;
- case tmedia_chroma_yuv422p:
- return PIX_FMT_YUV422P;
- case tmedia_chroma_uyvy422:
- return PIX_FMT_UYVY422;
- case tmedia_chroma_yuyv422:
- return PIX_FMT_YUYV422;
- case tmedia_chroma_yuv420p:
- return PIX_FMT_YUV420P;
- default:
- TSK_DEBUG_ERROR("Invalid chroma %d", (int)chroma);
- return PIX_FMT_NONE;
- }
+ switch(chroma) {
+ case tmedia_chroma_rgb24:
+ return PIX_FMT_RGB24;
+ case tmedia_chroma_bgr24:
+ return PIX_FMT_BGR24;
+ case tmedia_chroma_rgb32:
+ return PIX_FMT_RGB32;
+ case tmedia_chroma_rgb565le:
+ return PIX_FMT_RGB565LE;
+ case tmedia_chroma_rgb565be:
+ return PIX_FMT_RGB565BE;
+ case tmedia_chroma_nv21:
+ return PIX_FMT_NV21;
+ case tmedia_chroma_nv12:
+ return PIX_FMT_NV12;
+ case tmedia_chroma_yuv422p:
+ return PIX_FMT_YUV422P;
+ case tmedia_chroma_uyvy422:
+ return PIX_FMT_UYVY422;
+ case tmedia_chroma_yuyv422:
+ return PIX_FMT_YUYV422;
+ case tmedia_chroma_yuv420p:
+ return PIX_FMT_YUV420P;
+ default:
+ TSK_DEBUG_ERROR("Invalid chroma %d", (int)chroma);
+ return PIX_FMT_NONE;
+ }
}
static int tdav_converter_video_ffmpeg_init(tmedia_converter_video_t* self, tsk_size_t srcWidth, tsk_size_t srcHeight, tmedia_chroma_t srcChroma, tsk_size_t dstWidth, tsk_size_t dstHeight, tmedia_chroma_t dstChroma)
{
- TSK_DEBUG_INFO("Initializing new FFmpeg Video Converter src=(%dx%d@%d) dst=(%dx%d@%d)", srcWidth, srcHeight, srcChroma, dstWidth, dstHeight, dstChroma);
-
- if((TDAV_CONVERTER_VIDEO_FFMPEG(self)->srcFormat = _tdav_converter_video_ffmpeg_get_pixfmt(srcChroma)) == PIX_FMT_NONE){
- TSK_DEBUG_ERROR("Invalid source chroma");
- return -2;
- }
- if((TDAV_CONVERTER_VIDEO_FFMPEG(self)->dstFormat = _tdav_converter_video_ffmpeg_get_pixfmt(dstChroma)) == PIX_FMT_NONE){
- TSK_DEBUG_ERROR("Invalid destination chroma");
- return -3;
- }
-
- return 0;
+ TSK_DEBUG_INFO("Initializing new FFmpeg Video Converter src=(%dx%d@%d) dst=(%dx%d@%d)", srcWidth, srcHeight, srcChroma, dstWidth, dstHeight, dstChroma);
+
+ if((TDAV_CONVERTER_VIDEO_FFMPEG(self)->srcFormat = _tdav_converter_video_ffmpeg_get_pixfmt(srcChroma)) == PIX_FMT_NONE) {
+ TSK_DEBUG_ERROR("Invalid source chroma");
+ return -2;
+ }
+ if((TDAV_CONVERTER_VIDEO_FFMPEG(self)->dstFormat = _tdav_converter_video_ffmpeg_get_pixfmt(dstChroma)) == PIX_FMT_NONE) {
+ TSK_DEBUG_ERROR("Invalid destination chroma");
+ return -3;
+ }
+
+ return 0;
}
static tsk_size_t tdav_converter_video_ffmpeg_process(tmedia_converter_video_t* _self, const void* buffer, tsk_size_t buffer_size, void** output, tsk_size_t* output_max_size)
{
- int ret, size;
- tsk_bool_t _rotate = tsk_false;
- tdav_converter_video_ffmpeg_t* self = TDAV_CONVERTER_VIDEO_FFMPEG(_self);
-
- if (!self || !buffer || !output){
- TSK_DEBUG_ERROR("Invalid parameter");
- return 0;
- }
-
- /* Pictures */
- if (!self->srcFrame){
- if (!(self->srcFrame = avcodec_alloc_frame())){
- TSK_DEBUG_ERROR("Failed to create picture");
- return 0;
- }
- }
- if (!self->dstFrame){
- if (!(self->dstFrame = avcodec_alloc_frame())){
- TSK_DEBUG_ERROR("Failed to create picture");
- return 0;
- }
- }
-
- size = avpicture_get_size(self->dstFormat, (int)_self->dstWidth, (int)_self->dstHeight);
- if ((int)*output_max_size < size){
- if (!(*output = tsk_realloc(*output, (size + FF_INPUT_BUFFER_PADDING_SIZE)))){
- *output_max_size = 0;
- TSK_DEBUG_ERROR("Failed to allocate buffer");
- return 0;
- }
- *output_max_size = size;
- }
-
- /* Wrap the source buffer */
- ret = avpicture_fill((AVPicture *)self->srcFrame, (uint8_t*)buffer, self->srcFormat, (int)_self->srcWidth, (int)_self->srcHeight);
- /* Wrap the destination buffer */
- ret = avpicture_fill((AVPicture *)self->dstFrame, (uint8_t*)*output, self->dstFormat, (int)_self->dstWidth, (int)_self->dstHeight);
-
- /* === performs conversion === */
- /* Context */
- if (!self->context) {
- self->context = sws_getContext(
- (int)_self->srcWidth, (int)_self->srcHeight, self->srcFormat,
- (int)_self->dstWidth, (int)_self->dstHeight, self->dstFormat,
- SWS_FAST_BILINEAR, NULL, NULL, NULL);
-
- if (!self->context) {
- TSK_DEBUG_ERROR("Failed to create context");
- return 0;
- }
- }
-
- /*FIXME: For now only 90\B0 rotation is supported this is why we always use libyuv on mobile devices */
- _rotate = (PIX_FMT_YUV420P == self->dstFormat) && _self->rotation == 90;
-
- // if no rotation then, flip while scaling othersize do it after rotation
- if (!_rotate && _self->flip) {
- _tdav_converter_video_ffmpeg_flip(self->dstFrame, _self->dstHeight);
- }
-
- // chroma conversion and scaling
- ret = sws_scale(self->context, (const uint8_t* const*)self->srcFrame->data, self->srcFrame->linesize, 0, (int)_self->srcHeight,
- self->dstFrame->data, self->dstFrame->linesize);
- if (ret < 0){
- TSK_FREE(*output);
- return 0;
- }
-
- // Rotation
- if (_rotate){
- // because we rotated 90 width = original height, height = original width
- int w = (int)_self->dstHeight;
- int h = (int)_self->dstWidth;
-
- // allocation rotation frame if not already done
- if (!(self->rot.frame) && !(self->rot.frame = avcodec_alloc_frame())){
- TSK_DEBUG_ERROR("failed to allocate rotation frame");
- TSK_FREE(*output);
- return(0);
- }
-
- // allocate rotation temporary buffer
- size = avpicture_get_size(self->dstFormat, w, h);
- if (self->rot.buffer_size != size){
- if (!(self->rot.buffer = (uint8_t *)av_realloc(self->rot.buffer, size))){
- TSK_DEBUG_ERROR("failed to allocate new buffer for the frame");
- self->rot.buffer_size = 0;
- return(0);
- }
- self->rot.buffer_size = size;
- }
-
- //wrap
- avpicture_fill((AVPicture *)self->rot.frame, self->rot.buffer, self->dstFormat, w, h);
- // rotate
- _tdav_converter_video_ffmpeg_rotate90(_self->dstWidth, _self->dstHeight, self->dstFrame->data[0], self->rot.frame->data[0]);
- _tdav_converter_video_ffmpeg_rotate90((_self->dstWidth >> 1), (_self->dstHeight >> 1), self->dstFrame->data[1], self->rot.frame->data[1]);
- _tdav_converter_video_ffmpeg_rotate90((_self->dstWidth >> 1), (_self->dstHeight >> 1), self->dstFrame->data[2], self->rot.frame->data[2]);
- // flip
- if (_self->flip){
- _tdav_converter_video_ffmpeg_flip(self->rot.frame, h);
- }
-
- {
- static const int y_shift = 1;
- static const int x_shift = 1;
- int r_size, r_w, r_h, left_band, top_band;
- int pad = ((int)_self->dstWidth - w) > ((int)_self->dstHeight - h) ? ((int)_self->dstWidth - w) : ((int)_self->dstHeight - h);
- if (pad < 0){
- pad = 0;
- }
- r_size;
- r_w = w + pad;
- r_h = h + pad;
- left_band = (int)((r_w - _self->dstWidth) / 2);
- top_band = (int)((r_h - _self->dstHeight) / 3);
-
- if (!self->rot.context){
- if (!(self->rot.context = sws_getContext(w, h, self->dstFormat, r_w, r_h, self->dstFormat, SWS_FAST_BILINEAR, NULL, NULL, NULL))){
- TSK_DEBUG_ERROR("Failed to create context");
- TSK_FREE(*output);
- return 0;
- }
- }
-
- r_size = avpicture_get_size(self->dstFormat, r_w, r_h);
- if ((int)*output_max_size < r_size){
- if (!(*output = tsk_realloc(*output, (r_size + FF_INPUT_BUFFER_PADDING_SIZE)))){
- *output_max_size = 0;
- TSK_DEBUG_ERROR("Failed to allocate buffer");
- return 0;
- }
- *output_max_size = r_size;
- }
-
- // re-wrap
- avpicture_fill((AVPicture *)self->dstFrame, (uint8_t*)*output, self->dstFormat, r_w, r_h);
-
- // pad
- sws_scale(self->rot.context, (const uint8_t* const*)self->rot.frame->data, self->rot.frame->linesize,
- 0, h, self->dstFrame->data, self->dstFrame->linesize);
-
- // crop
- self->dstFrame->data[0] = self->dstFrame->data[0] + (top_band * self->dstFrame->linesize[0]) + left_band;
- self->dstFrame->data[1] = self->dstFrame->data[1] + ((top_band >> y_shift) * self->dstFrame->linesize[1]) + (left_band >> x_shift);
- self->dstFrame->data[2] = self->dstFrame->data[2] + ((top_band >> y_shift) * self->dstFrame->linesize[2]) + (left_band >> x_shift);
-
- avpicture_layout((const AVPicture*)self->dstFrame, self->dstFormat, (int)_self->dstWidth, (int)_self->dstHeight, (unsigned char *)*output, (int)*output_max_size);
- }
-
- }//end of rotation
-
- return size;
+ int ret, size;
+ tsk_bool_t _rotate = tsk_false;
+ tdav_converter_video_ffmpeg_t* self = TDAV_CONVERTER_VIDEO_FFMPEG(_self);
+
+ if (!self || !buffer || !output) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return 0;
+ }
+
+ /* Pictures */
+ if (!self->srcFrame) {
+ if (!(self->srcFrame = avcodec_alloc_frame())) {
+ TSK_DEBUG_ERROR("Failed to create picture");
+ return 0;
+ }
+ }
+ if (!self->dstFrame) {
+ if (!(self->dstFrame = avcodec_alloc_frame())) {
+ TSK_DEBUG_ERROR("Failed to create picture");
+ return 0;
+ }
+ }
+
+ size = avpicture_get_size(self->dstFormat, (int)_self->dstWidth, (int)_self->dstHeight);
+ if ((int)*output_max_size < size) {
+ if (!(*output = tsk_realloc(*output, (size + FF_INPUT_BUFFER_PADDING_SIZE)))) {
+ *output_max_size = 0;
+ TSK_DEBUG_ERROR("Failed to allocate buffer");
+ return 0;
+ }
+ *output_max_size = size;
+ }
+
+ /* Wrap the source buffer */
+ ret = avpicture_fill((AVPicture *)self->srcFrame, (uint8_t*)buffer, self->srcFormat, (int)_self->srcWidth, (int)_self->srcHeight);
+ /* Wrap the destination buffer */
+ ret = avpicture_fill((AVPicture *)self->dstFrame, (uint8_t*)*output, self->dstFormat, (int)_self->dstWidth, (int)_self->dstHeight);
+
+ /* === performs conversion === */
+ /* Context */
+ if (!self->context) {
+ self->context = sws_getContext(
+ (int)_self->srcWidth, (int)_self->srcHeight, self->srcFormat,
+ (int)_self->dstWidth, (int)_self->dstHeight, self->dstFormat,
+ SWS_FAST_BILINEAR, NULL, NULL, NULL);
+
+ if (!self->context) {
+ TSK_DEBUG_ERROR("Failed to create context");
+ return 0;
+ }
+ }
+
+ /*FIXME: For now only 90\B0 rotation is supported this is why we always use libyuv on mobile devices */
+ _rotate = (PIX_FMT_YUV420P == self->dstFormat) && _self->rotation == 90;
+
+ // if no rotation then, flip while scaling othersize do it after rotation
+ if (!_rotate && _self->flip) {
+ _tdav_converter_video_ffmpeg_flip(self->dstFrame, _self->dstHeight);
+ }
+
+ // chroma conversion and scaling
+ ret = sws_scale(self->context, (const uint8_t* const*)self->srcFrame->data, self->srcFrame->linesize, 0, (int)_self->srcHeight,
+ self->dstFrame->data, self->dstFrame->linesize);
+ if (ret < 0) {
+ TSK_FREE(*output);
+ return 0;
+ }
+
+ // Rotation
+ if (_rotate) {
+ // because we rotated 90 width = original height, height = original width
+ int w = (int)_self->dstHeight;
+ int h = (int)_self->dstWidth;
+
+ // allocation rotation frame if not already done
+ if (!(self->rot.frame) && !(self->rot.frame = avcodec_alloc_frame())) {
+ TSK_DEBUG_ERROR("failed to allocate rotation frame");
+ TSK_FREE(*output);
+ return(0);
+ }
+
+ // allocate rotation temporary buffer
+ size = avpicture_get_size(self->dstFormat, w, h);
+ if (self->rot.buffer_size != size) {
+ if (!(self->rot.buffer = (uint8_t *)av_realloc(self->rot.buffer, size))) {
+ TSK_DEBUG_ERROR("failed to allocate new buffer for the frame");
+ self->rot.buffer_size = 0;
+ return(0);
+ }
+ self->rot.buffer_size = size;
+ }
+
+ //wrap
+ avpicture_fill((AVPicture *)self->rot.frame, self->rot.buffer, self->dstFormat, w, h);
+ // rotate
+ _tdav_converter_video_ffmpeg_rotate90(_self->dstWidth, _self->dstHeight, self->dstFrame->data[0], self->rot.frame->data[0]);
+ _tdav_converter_video_ffmpeg_rotate90((_self->dstWidth >> 1), (_self->dstHeight >> 1), self->dstFrame->data[1], self->rot.frame->data[1]);
+ _tdav_converter_video_ffmpeg_rotate90((_self->dstWidth >> 1), (_self->dstHeight >> 1), self->dstFrame->data[2], self->rot.frame->data[2]);
+ // flip
+ if (_self->flip) {
+ _tdav_converter_video_ffmpeg_flip(self->rot.frame, h);
+ }
+
+ {
+ static const int y_shift = 1;
+ static const int x_shift = 1;
+ int r_size, r_w, r_h, left_band, top_band;
+ int pad = ((int)_self->dstWidth - w) > ((int)_self->dstHeight - h) ? ((int)_self->dstWidth - w) : ((int)_self->dstHeight - h);
+ if (pad < 0) {
+ pad = 0;
+ }
+ r_size;
+ r_w = w + pad;
+ r_h = h + pad;
+ left_band = (int)((r_w - _self->dstWidth) / 2);
+ top_band = (int)((r_h - _self->dstHeight) / 3);
+
+ if (!self->rot.context) {
+ if (!(self->rot.context = sws_getContext(w, h, self->dstFormat, r_w, r_h, self->dstFormat, SWS_FAST_BILINEAR, NULL, NULL, NULL))) {
+ TSK_DEBUG_ERROR("Failed to create context");
+ TSK_FREE(*output);
+ return 0;
+ }
+ }
+
+ r_size = avpicture_get_size(self->dstFormat, r_w, r_h);
+ if ((int)*output_max_size < r_size) {
+ if (!(*output = tsk_realloc(*output, (r_size + FF_INPUT_BUFFER_PADDING_SIZE)))) {
+ *output_max_size = 0;
+ TSK_DEBUG_ERROR("Failed to allocate buffer");
+ return 0;
+ }
+ *output_max_size = r_size;
+ }
+
+ // re-wrap
+ avpicture_fill((AVPicture *)self->dstFrame, (uint8_t*)*output, self->dstFormat, r_w, r_h);
+
+ // pad
+ sws_scale(self->rot.context, (const uint8_t* const*)self->rot.frame->data, self->rot.frame->linesize,
+ 0, h, self->dstFrame->data, self->dstFrame->linesize);
+
+ // crop
+ self->dstFrame->data[0] = self->dstFrame->data[0] + (top_band * self->dstFrame->linesize[0]) + left_band;
+ self->dstFrame->data[1] = self->dstFrame->data[1] + ((top_band >> y_shift) * self->dstFrame->linesize[1]) + (left_band >> x_shift);
+ self->dstFrame->data[2] = self->dstFrame->data[2] + ((top_band >> y_shift) * self->dstFrame->linesize[2]) + (left_band >> x_shift);
+
+ avpicture_layout((const AVPicture*)self->dstFrame, self->dstFormat, (int)_self->dstWidth, (int)_self->dstHeight, (unsigned char *)*output, (int)*output_max_size);
+ }
+
+ }//end of rotation
+
+ return size;
}
@@ -773,58 +774,56 @@ static tsk_size_t tdav_converter_video_ffmpeg_process(tmedia_converter_video_t*
//
static tsk_object_t* tdav_converter_video_ffmpeg_ctor(tsk_object_t * self, va_list * app)
{
- tdav_converter_video_ffmpeg_t *converter = (tdav_converter_video_ffmpeg_t *)self;
- if(converter){
+ tdav_converter_video_ffmpeg_t *converter = (tdav_converter_video_ffmpeg_t *)self;
+ if(converter) {
- }
- return self;
+ }
+ return self;
}
static tsk_object_t* tdav_converter_video_ffmpeg_dtor(tsk_object_t * self)
-{
- tdav_converter_video_ffmpeg_t *converter = (tdav_converter_video_ffmpeg_t *)self;
- if(converter){
- if(converter->context){
- sws_freeContext(converter->context);
- }
- if(converter->srcFrame){
- av_free(converter->srcFrame);
- }
- if(converter->dstFrame){
- av_free(converter->dstFrame);
- }
-
- // Rotation
- if(converter->rot.context){
- sws_freeContext(converter->rot.context);
- }
- if(converter->rot.frame){
- av_free(converter->rot.frame);
- }
- if(converter->rot.buffer){
- av_free(converter->rot.buffer);
- }
- }
-
- return self;
+{
+ tdav_converter_video_ffmpeg_t *converter = (tdav_converter_video_ffmpeg_t *)self;
+ if(converter) {
+ if(converter->context) {
+ sws_freeContext(converter->context);
+ }
+ if(converter->srcFrame) {
+ av_free(converter->srcFrame);
+ }
+ if(converter->dstFrame) {
+ av_free(converter->dstFrame);
+ }
+
+ // Rotation
+ if(converter->rot.context) {
+ sws_freeContext(converter->rot.context);
+ }
+ if(converter->rot.frame) {
+ av_free(converter->rot.frame);
+ }
+ if(converter->rot.buffer) {
+ av_free(converter->rot.buffer);
+ }
+ }
+
+ return self;
}
-static const tsk_object_def_t tdav_converter_video_ffmpeg_def_s =
-{
- sizeof(tdav_converter_video_ffmpeg_t),
- tdav_converter_video_ffmpeg_ctor,
- tdav_converter_video_ffmpeg_dtor,
- tsk_null,
+static const tsk_object_def_t tdav_converter_video_ffmpeg_def_s = {
+ sizeof(tdav_converter_video_ffmpeg_t),
+ tdav_converter_video_ffmpeg_ctor,
+ tdav_converter_video_ffmpeg_dtor,
+ tsk_null,
};
const tsk_object_def_t *tdav_converter_video_ffmpeg_def_t = &tdav_converter_video_ffmpeg_def_s;
/* plugin definition*/
-static const tmedia_converter_video_plugin_def_t tdav_converter_video_ffmpeg_plugin_def_s =
-{
- &tdav_converter_video_ffmpeg_def_s,
+static const tmedia_converter_video_plugin_def_t tdav_converter_video_ffmpeg_plugin_def_s = {
+ &tdav_converter_video_ffmpeg_def_s,
- tdav_converter_video_ffmpeg_init,
- tdav_converter_video_ffmpeg_process
+ tdav_converter_video_ffmpeg_init,
+ tdav_converter_video_ffmpeg_process
};
const tmedia_converter_video_plugin_def_t *tdav_converter_video_ffmpeg_plugin_def_t = &tdav_converter_video_ffmpeg_plugin_def_s;
OpenPOWER on IntegriCloud