video function improvements (neon scaling)

parent add023bd
......@@ -50,9 +50,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MS_VIDEO_SIZE_QQVGA_W 160
#define MS_VIDEO_SIZE_QQVGA_H 120
#define MS_VIDEO_SIZE_HQVGA_W 160
#define MS_VIDEO_SIZE_HQVGA_H 240
#define MS_VIDEO_SIZE_QVGA_W 320
#define MS_VIDEO_SIZE_QVGA_H 240
#define MS_VIDEO_SIZE_HVGA_W 320
#define MS_VIDEO_SIZE_HVGA_H 480
#define MS_VIDEO_SIZE_VGA_W 640
#define MS_VIDEO_SIZE_VGA_H 480
......@@ -223,6 +229,9 @@ MS2_PUBLIC void rotate_plane_neon_clockwise(int wDest, int hDest, int full_width
MS2_PUBLIC void rotate_plane_neon_anticlockwise(int wDest, int hDest, int full_width, uint8_t* src, uint8_t* dst);
MS2_PUBLIC void rotate_cbcr_to_cr_cb(int wDest, int hDest, int full_width, uint8_t* cbcr_src, uint8_t* cr_dst, uint8_t* cb_dst,bool_t clockWise);
MS2_PUBLIC void deinterlace_and_rotate_180_neon(uint8_t* ysrc, uint8_t* cbcrsrc, uint8_t* ydst, uint8_t* udst, uint8_t* vdst, int w, int h, int y_byte_per_row,int cbcr_byte_per_row);
void deinterlace_down_scale_and_rotate_180_neon(uint8_t* ysrc, uint8_t* cbcrsrc, uint8_t* ydst, uint8_t* udst, uint8_t* vdst, int w, int h, int y_byte_per_row,int cbcr_byte_per_row,bool_t down_scale);
void deinterlace_down_scale_neon(uint8_t* ysrc, uint8_t* cbcrsrc, uint8_t* ydst, uint8_t* u_dst, uint8_t* v_dst, int w, int h, int y_byte_per_row,int cbcr_byte_per_row,bool_t down_scale);
mblk_t *copy_ycbcrbiplanar_to_true_yuv_with_rotation_and_down_scale_by_2(uint8_t* y, uint8_t * cbcr, int rotation, int w, int h, int y_byte_per_row,int cbcr_byte_per_row, bool_t uFirstvSecond, bool_t down_scale);
#endif
static inline bool_t ms_video_size_greater_than(MSVideoSize vs1, MSVideoSize vs2){
......
......@@ -78,6 +78,7 @@ struct AndroidReaderContext {
MSVideoSize requestedSize, hwCapableSize;
ms_mutex_t mutex;
int rotation, rotationSavedDuringVSize;
int useDownscaling;
jobject androidCamera;
jobject previewWindow;
......@@ -135,25 +136,29 @@ static int video_capture_set_vsize(MSFilter *f, void* data){
// handle result :
// - 0 : width
// - 1 : height
jint res[2];
env->GetIntArrayRegion((jintArray)resArray, 0, 2, res);
ms_message("Camera selected resolution is: %dx%d (requested: %dx%d)\n", res[0], res[1], d->requestedSize.width, d->requestedSize.height);
// - 2 : useDownscaling
jint res[3];
env->GetIntArrayRegion((jintArray)resArray, 0, 3, res);
ms_message("Camera selected resolution is: %dx%d (requested: %dx%d) with downscaling?%d\n", res[0], res[1], d->requestedSize.width, d->requestedSize.height, res[2]);
d->hwCapableSize.width = res[0];
d->hwCapableSize.height = res[1];
d->useDownscaling = res[2];
int rqSize = d->requestedSize.width * d->requestedSize.height;
int hwSize = d->hwCapableSize.width * d->hwCapableSize.height;
double downscale = d->useDownscaling ? 0.5 : 1;
// if hw supplies a smaller resolution, modify requested size accordingly
if (hwSize < rqSize) {
if ((hwSize * downscale * downscale) < rqSize) {
ms_message("Camera cannot produce requested resolution %dx%d, will supply smaller one: %dx%d\n",
d->requestedSize.width, d->requestedSize.height, res[0], res[1]);
d->requestedSize = d->hwCapableSize;
} else if (hwSize > rqSize) {
d->requestedSize.width, d->requestedSize.height, (int) (res[0] * downscale), (int) (res[1]*downscale));
d->requestedSize.width = (int) (d->hwCapableSize.width * downscale);
d->requestedSize.height = (int) (d->hwCapableSize.height * downscale);
} else if ((hwSize * downscale * downscale) > rqSize) {
ms_message("Camera cannot produce requested resolution %dx%d, will capture a bigger one (%dx%d) and crop it to match encoder requested resolution\n",
d->requestedSize.width, d->requestedSize.height, res[0], res[1]);
d->requestedSize.width, d->requestedSize.height, (int)(res[0] * downscale), (int)(res[1] * downscale));
}
// is phone held |_ to cam orientation ?
if (d->rotation == UNDEFINED_ROTATION || compute_image_rotation_correction(d, d->rotation) % 180 != 0) {
if (d->rotation == UNDEFINED_ROTATION) {
......@@ -476,14 +481,15 @@ JNIEXPORT void JNICALL Java_org_linphone_mediastream_video_capture_AndroidVideoA
It only implies one thing: image needs to rotated by that amount to be correctly
displayed.
*/
mblk_t* yuv_block = copy_ycbcrbiplanar_to_true_yuv_with_rotation(y_src
mblk_t* yuv_block = copy_ycbcrbiplanar_to_true_yuv_with_rotation_and_down_scale_by_2(y_src
, cbcr_src
, image_rotation_correction
, d->requestedSize.width
, d->requestedSize.height
, d->hwCapableSize.width
, d->hwCapableSize.width,
false);
false,
d->useDownscaling);
if (yuv_block) {
if (d->frame)
freemsg(d->frame);
......
......@@ -395,10 +395,14 @@ static MSScalerContext *ff_create_swscale_context(int src_w, int src_h, MSPixFmt
int ff_flags=0;
MSFFScalerContext *ctx=ms_new(MSFFScalerContext,1);
ctx->src_h=src_h;
#if (TARGET_OS_IPHONE)
ff_flags|=SWS_FAST_BILINEAR;
#else
if (flags & MS_SCALER_METHOD_BILINEAR)
ff_flags|=SWS_BILINEAR;
else if (flags & MS_SCALER_METHOD_NEIGHBOUR)
ff_flags|=SWS_BILINEAR;
#endif
ctx->ctx=sws_getContext (src_w,src_h,ms_pix_fmt_to_ffmpeg (src_fmt),
dst_w,dst_h,ms_pix_fmt_to_ffmpeg (dst_fmt),ff_flags,NULL,NULL,NULL);
if (ctx->ctx==NULL){
......@@ -557,7 +561,6 @@ static void rotate_plane(int wDest, int hDest, int full_width, uint8_t* src, uin
int signed_dst_stride;
int incr;
int y,x;
......@@ -572,6 +575,7 @@ static void rotate_plane(int wDest, int hDest, int full_width, uint8_t* src, uin
incr = -1;
signed_dst_stride = -wDest;
}
int y,x;
for (y=0; y<hSrc; y++) {
uint8_t* dst2 = dst;
for (x=0; x<step*wSrc; x+=step) {
......@@ -593,22 +597,23 @@ static void rotate_plane(int wDest, int hDest, int full_width, uint8_t* src, uin
static int hasNeon = -1;
#elif defined (__ARM_NEON__)
static int hasNeon = 1;
#elif defined (__arm__)
#else
static int hasNeon = 0;
#endif
/* Destination and source images may have their dimensions inverted.*/
mblk_t *copy_ycbcrbiplanar_to_true_yuv_with_rotation(uint8_t* y, uint8_t * cbcr, int rotation, int w, int h, int y_byte_per_row,int cbcr_byte_per_row, bool_t uFirstvSecond) {
mblk_t *copy_ycbcrbiplanar_to_true_yuv_with_rotation_and_down_scale_by_2(uint8_t* y, uint8_t * cbcr, int rotation, int w, int h, int y_byte_per_row,int cbcr_byte_per_row, bool_t uFirstvSecond, bool_t down_scale) {
MSPicture pict;
mblk_t *yuv_block = ms_yuv_buf_alloc(&pict, w, h);
int uv_w = w/2;
int uv_h = h/2;
#ifdef ANDROID
if (hasNeon == -1) {
hasNeon = (android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM && (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0);
}
#endif
if (down_scale && !hasNeon) {
ms_error("down scaling by two requires NEON, returning empty block");
return yuv_block;
}
if (!uFirstvSecond) {
unsigned char* tmp = pict.planes[1];
......@@ -616,38 +621,47 @@ mblk_t *copy_ycbcrbiplanar_to_true_yuv_with_rotation(uint8_t* y, uint8_t * cbcr,
pict.planes[2] = tmp;
}
int uv_w = w/2;
int uv_h = h/2;
if (rotation % 180 == 0) {
int i,j;
uint8_t* u_dest=pict.planes[1], *v_dest=pict.planes[2];
if (rotation == 0) {
// plain copy
for(i=0; i<h; i++) {
memcpy(&pict.planes[0][i*w], &y[i*y_byte_per_row], w);
}
// de-interlace u/v
for (i=0; i<uv_h; i++) {
for(j=0; j<uv_w; j++) {
*u_dest++ = cbcr[cbcr_byte_per_row*i + 2*j];
*v_dest++ = cbcr[cbcr_byte_per_row*i + 2*j + 1];
#ifdef __arm__
if (hasNeon) {
deinterlace_down_scale_neon(y, cbcr, pict.planes[0], u_dest, v_dest, w, h, y_byte_per_row, cbcr_byte_per_row,down_scale);
} else
#endif
{
// plain copy
for(i=0; i<h; i++) {
memcpy(&pict.planes[0][i*w], &y[i*y_byte_per_row], w);
}
// de-interlace u/v
for (i=0; i<uv_h; i++) {
for(j=0; j<uv_w; j++) {
*u_dest++ = cbcr[cbcr_byte_per_row*i + 2*j];
*v_dest++ = cbcr[cbcr_byte_per_row*i + 2*j + 1];
}
}
}
} else {
#ifdef __arm__
if (hasNeon) {
deinterlace_and_rotate_180_neon(y, cbcr, pict.planes[0], u_dest, v_dest, w, h, y_byte_per_row, cbcr_byte_per_row);
deinterlace_down_scale_and_rotate_180_neon(y, cbcr, pict.planes[0], u_dest, v_dest, w, h, y_byte_per_row, cbcr_byte_per_row,down_scale);
} else
#endif
{
// 180° y rotation
uint8_t* ysrc=y;
uint8_t* uvsrc=&cbcr[uv_h*uv_w*2-2];
uint8_t* ydst=&pict.planes[0][h*w-1];
// 180° y rotation
for(i=0; i<h*w; i++) {
*ydst-- = *ysrc++;
}
// 180° rotation + de-interlace u/v
uint8_t* uvsrc=&cbcr[uv_h*uv_w*2-2];
for (i=0; i<uv_h*uv_w*2; i++) {
*u_dest++ = *uvsrc--;
*v_dest++ = *uvsrc--;
......@@ -660,7 +674,7 @@ mblk_t *copy_ycbcrbiplanar_to_true_yuv_with_rotation(uint8_t* y, uint8_t * cbcr,
#ifdef __arm__
if (hasNeon) {
if (clockwise) {
rotate_plane_neon_clockwise(w,h,y_byte_per_row,(uint8_t*)y,pict.planes[0]);
rotate_down_scale_plane_neon_clockwise(w,h,y_byte_per_row,(uint8_t*)y,pict.planes[0],down_scale);
} else {
rotate_plane_neon_anticlockwise(w,h,y_byte_per_row,(uint8_t*)y,pict.planes[0]);
}
......@@ -674,25 +688,26 @@ mblk_t *copy_ycbcrbiplanar_to_true_yuv_with_rotation(uint8_t* y, uint8_t * cbcr,
#ifdef __arm__
if (hasNeon) {
rotate_cbcr_to_cr_cb(uv_w,uv_h, cbcr_byte_per_row/2, (uint8_t*)cbcr, pict.planes[2], pict.planes[1],clockwise);
rotate_down_scale_cbcr_to_cr_cb(uv_w,uv_h, cbcr_byte_per_row/2, (uint8_t*)cbcr, pict.planes[2], pict.planes[1],clockwise,down_scale);
} else
#endif
{
// Copying U
uint8_t* srcu = cbcr;
uint8_t* dstu = pict.planes[1];
uint8_t* srcv = srcu + 1;
uint8_t* dstv = pict.planes[2];
// Copying U
rotate_plane(uv_w,uv_h,cbcr_byte_per_row/2,srcu,dstu, 2, clockwise);
// Copying V
uint8_t* srcv = srcu + 1;
uint8_t* dstv = pict.planes[2];
rotate_plane(uv_w,uv_h,cbcr_byte_per_row/2,srcv,dstv, 2, clockwise);
}
}
return yuv_block;
}
mblk_t *copy_ycbcrbiplanar_to_true_yuv_with_rotation(uint8_t* y, uint8_t * cbcr, int rotation, int w, int h, int y_byte_per_row,int cbcr_byte_per_row, bool_t uFirstvSecond) {
return copy_ycbcrbiplanar_to_true_yuv_with_rotation_and_down_scale_by_2(y, cbcr, rotation, w, h, y_byte_per_row, cbcr_byte_per_row, uFirstvSecond, FALSE);
}
void ms_video_init_framerate_controller(MSFrameRateController* ctrl, float fps) {
ctrl->start_time = 0;
ctrl->th_frame_count = -1;
......
This diff is collapsed.
......@@ -27,7 +27,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "mediastreamer2/msrtp.h"
#include "mediastreamer2/msvideoout.h"
#include "mediastreamer2/msextdisplay.h"
#ifndef TARGET_OS_IPHONE
#include <ortp/zrtp.h>
#endif
#ifndef TARGET_OS_IPHONE
#define TARGET_OS_IPHONE 0
......@@ -206,6 +208,8 @@ static void choose_display_name(VideoStream *stream){
stream->display_name=ms_strdup("MSAndroidDisplay");
#elif defined (HAVE_X11_EXTENSIONS_XV_H)
stream->display_name=ms_strdup("MSX11Video");
#elif defined (TARGET_OS_IPHONE)
stream->display_name=ms_strdup("IOSDisplay");
#else
stream->display_name=ms_strdup("MSVideoOut");
#endif
......@@ -236,10 +240,10 @@ void video_stream_set_relay_session_id(VideoStream *stream, const char *id){
void video_stream_enable_self_view(VideoStream *stream, bool_t val){
MSFilter *out=stream->output;
stream->corner=val ? 0 : -1;
if (out) {
ms_filter_call_method(out,MS_VIDEO_DISPLAY_SET_LOCAL_VIEW_MODE,&stream->corner);
}
stream->corner=val ? 0 : -1;
if (out){
ms_filter_call_method(out,MS_VIDEO_DISPLAY_SET_LOCAL_VIEW_MODE,&stream->corner);
}
}
void video_stream_enable_adaptive_bitrate_control(VideoStream *s, bool_t yesno){
......@@ -284,7 +288,7 @@ static MSVideoSize get_compatible_size(MSVideoSize maxsize, MSVideoSize wished_s
int max_area=maxsize.width*maxsize.height;
int whished_area=wished_size.width*wished_size.height;
if (whished_area>max_area){
return ms_video_size_change_orientation(maxsize,ms_video_size_get_orientation(wished_size));
return maxsize;
}
return wished_size;
}
......@@ -359,9 +363,6 @@ int video_stream_start (VideoStream *stream, RtpProfile *profile, const char *re
rtp_session_set_profile(rtps,profile);
if (remport>0) rtp_session_set_remote_addr_full(rtps,remip,remport,rem_rtcp_port);
if (rem_rtcp_port<=0){
rtp_session_enable_rtcp(rtps,FALSE);
}
rtp_session_set_payload_type(rtps,payload);
rtp_session_set_jitter_compensation(rtps,jitt_comp);
......@@ -498,7 +499,7 @@ void video_stream_update_video_params(VideoStream *stream){
void video_stream_change_camera(VideoStream *stream, MSWebCam *cam){
bool_t keep_source=(cam==stream->cam);
if (stream->ticker && stream->source){
ms_ticker_detach(stream->ticker,stream->source);
/*unlink source filters and subsequent post processin filters */
......@@ -514,7 +515,7 @@ void video_stream_change_camera(VideoStream *stream, MSWebCam *cam){
if (!keep_source) stream->source = ms_web_cam_create_reader(cam);
stream->cam=cam;
configure_video_source(stream);
ms_filter_link (stream->source, 0, stream->pixconv, 0);
ms_filter_link (stream->pixconv, 0, stream->sizeconv, 0);
ms_filter_link (stream->sizeconv, 0, stream->tee, 0);
......@@ -609,7 +610,7 @@ unsigned long video_stream_get_native_preview_window_id(VideoStream *stream){
return id;
}
if (stream->source){
if (ms_filter_has_method(stream->source,MS_VIDEO_DISPLAY_GET_NATIVE_WINDOW_ID)
if (ms_filter_has_method(stream->source,MS_VIDEO_DISPLAY_GET_NATIVE_WINDOW_ID)
&& ms_filter_call_method(stream->source,MS_VIDEO_DISPLAY_GET_NATIVE_WINDOW_ID,&id)==0)
return id;
}
......@@ -621,12 +622,11 @@ void video_stream_use_preview_video_window(VideoStream *stream, bool_t yesno){
}
void video_stream_set_device_rotation(VideoStream *stream, int orientation){
MSFilter* target_filter = NULL;
if (stream == 0)
return;
stream->device_orientation = orientation;
target_filter=stream->source;
MSFilter* target_filter=stream->source;
if (target_filter){
ms_filter_call_method(target_filter,MS_VIDEO_CAPTURE_SET_DEVICE_ORIENTATION,&orientation);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment