如何在android ndk中进行surfaceview缩放?

时间:2018-02-19 14:08:15

标签: android android-ndk

早上好。

我正在使用ffmpeg制作相机视频播放器。

在制作过程中,我们面临一个问题。

如果您通过ffmpeg拍摄一帧,请对帧进行解码,并将其sws_scale以适合屏幕尺寸,这将花费太长时间,相机图像将会负担。

例如,当输入分辨率为1920 * 1080,手机分辨率为2550 * 1440时,sws_scale的速度大约慢6倍。   [更改为相同尺寸时的对比度]

目前,NDK将sws_scale转换为从相机输入的分辨率,因此速度得到改善,图像不会中断。

但是,SurfaceView是全屏的,但输入分辨率低于全分辨率。

缩放AVFrame

ctx->m_SwsCtx = sws_getContext(
        ctx->m_CodecCtx->width,
        ctx->m_CodecCtx->height,
        ctx->m_CodecCtx->pix_fmt,
        //width,                  // 2550 (SurfaceView)
        //height,                 // 1440
        ctx->m_CodecCtx->width,   // 1920 (Camera)
        ctx->m_CodecCtx->height,  // 1080
        AV_PIX_FMT_RGBA,
        SWS_FAST_BILINEAR,
        NULL, NULL, NULL);
if(ctx->m_SwsCtx == NULL)
{
    __android_log_print(
        ANDROID_LOG_DEBUG,
        "[ VideoStream::SetResolution Fail ] ",
        "[ Error Message : %s ]",
            "SwsContext Alloc fail");

    SET_FIELD_TO_INT(pEnv, ob, err, 0x40);

    return ob;
}

sws_scale(
    ctx->m_SwsCtx,
    (const uint8_t * const *)ctx->m_SrcFrame->data,
    ctx->m_SrcFrame->linesize,
    0,
    ctx->m_CodecCtx->height,
    ctx->m_DstFrame->data,
    ctx->m_DstFrame->linesize);

    PDRAWOBJECT drawObj = (PDRAWOBJECT)malloc(sizeof(DRAWOBJECT));
    if(drawObj != NULL)
    {
        drawObj->m_Width = ctx->m_Width;
        drawObj->m_Height = ctx->m_Height;
        drawObj->m_Format = WINDOW_FORMAT_RGBA_8888;
        drawObj->m_Frame = ctx->m_DstFrame;

        SET_FIELD_TO_INT(pEnv, ob, err, -1);
        SET_FIELD_TO_LONG(pEnv, ob, addr, (jlong)drawObj);
    }

绘制SurfaceView;

PDRAWOBJECT d = (PDRAWOBJECT)drawObj;

long long curr1 = CurrentTimeInMilli();

ANativeWindow *window = ANativeWindow_fromSurface(pEnv, surface);
ANativeWindow_setBuffersGeometry(window, 0, 0, WINDOW_FORMAT_RGBA_8888);

ANativeWindow_setBuffersGeometry(
        window,
        d->m_Width,
        d->m_Height,
        WINDOW_FORMAT_RGBA_8888);

ANativeWindow_Buffer windowBuffer;

ANativeWindow_lock(window, &windowBuffer, 0);

uint8_t * dst = (uint8_t*)windowBuffer.bits;
int  dstStride = windowBuffer.stride * 4;
uint8_t * src = (uint8_t*) (d->m_Frame->data[0]);
int srcStride = d->m_Frame->linesize[0];

for(int h = 0; h < d->m_Height; ++h)
{
    // Draw SurfaceView;
    memcpy(dst + h * dstStride, src + h * srcStride, srcStride);
}

ANativeWindow_unlockAndPost(window);
ANativeWindow_release(window);

结果;

enter image description here

我想将整个屏幕从全屏更改为全屏。有没有办法在NDK或Android中更改SurfaceView的大小,而不是sws_scale?

谢谢。

1 个答案:

答案 0 :(得分:0)

您不需要扩展视频。实际上,您甚至不需要将其转换为RGB(这对CPU来说也是一个很大的负担)。

诀窍是使用带有YUV输入的着色器的OpenGL渲染,并在屏幕上显示此纹理。

从此解决方案开始(重用Android系统中的代码): https://stackoverflow.com/a/14999912/192373