使用android ndk方式与mediacodec进行编码

问题描述 投票:1回答:1

这是我关于堆栈溢出的第一个问题,我的确是一个新来的人。

我正在尝试使用NDK方法将yuv(I420)文件编码为Android 5.0中的H264文件。实际上,yuv文件由从屏幕(1440x2560)捕获的原始数据组成,为了使用,我将数据格式从ARGB转换为I420,并将其大小调整为固定尺寸(如720x1280)。用queueInputbuffer方法代替createInputSurface作为数据源推送方式。

为什么我不直接使用createInputSurface是因为在某些情况下,尤其是对于静态或缓慢变化的屏幕场景,编码器dequeueOutputbuffer不实时公开缓冲区。它首先在服务器时间返回EAGAIN,然后返回NO_ERROR(带有数据)。这可能会导致应用程序不允许的延迟。因此,我尝试自己隐蔽。它在某些Android手机上工作正常,但在其他一些手机上却失败了这是我的代码:

sp<ProcessState> self = ProcessState::self();
self->startThreadPool();

get_displayinfo();
int fd0 = open("/data/local/tmp/test.yuv",O_RDWR ,0664);
if(fd0 < 0) {
    printf("test.yuv open fail\n");
} else {
    printf("test.yuv open ok\n");
}
int fd1 = open("/data/local/tmp/test.h264",O_RDWR | O_CREAT,0664);
if(fd1 < 0) {
    printf("test.h264 open fail\n");
} else {
    printf("test.h264 open ok\n");
}
int readBytes;

status_t err;
sp<AMessage> format = new AMessage;
format->setInt32("width", gVideoWidth);
format->setInt32("height", gVideoHeight);
format->setString("mime", kMimeTypeAvc);
format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
format->setInt32("bitrate", 4000000);
format->setFloat("frame-rate",25);
format->setInt32("i-frame-interval", 10);
//format->setInt32("repeat-previous-frame-after",1000000/(25*4));

sp<ALooper> looper = new ALooper;
looper->setName("streamer_looper");
looper->start();
printf("Creating encoder\n");

sp<MediaCodec> encoder = MediaCodec::CreateByType(looper, kMimeTypeAvc, true);
if (encoder == NULL) {
    printf("unable to create %s encoder instance\n",kMimeTypeAvc);
    return (void*)err;
}
err = encoder->configure(format, NULL, NULL,MediaCodec::CONFIGURE_FLAG_ENCODE);
if (err != NO_ERROR) {
    printf("unable to configure %s encoder at %dx%d (err=%d)\n",
            kMimeTypeAvc, gVideoWidth, gVideoHeight, err);
    encoder->release();
    return (void*)err;
}
printf("Starting encoder\n");
err = encoder->start();
if(err != NO_ERROR){
    printf("unable to start enoder (err=%d)\n",err);
    return (void*)err;
}

//no more createInputSurface
Vector<sp<ABuffer>> Inbuffers;
Vector<sp<ABuffer>> Outbuffers;

err = encoder->getInputBuffers(&Inbuffers);
if(err != NO_ERROR){
    printf("unable to getInputBuffers (err=%d)\n",err);
    return (void*)err;
}

size_t inputIndex = 0;
int frameSize = gVideoWidth * gVideoHeight * 3 / 2;
unsigned char* base = (unsigned char*)malloc(frameSize);

int queueflag;
size_t bufIndex, offset, size;
int64_t ptsUsec;
uint32_t flags;
size_t  orientation;
static size_t i = 0;
int64_t startWhenUsec = systemTime(CLOCK_MONOTONIC)/1000;
//int64_t startWhenUsec = 0;
while (!gStopRequested){
    err = encoder->dequeueInputBuffer(&inputIndex,-1);
    if(err != NO_ERROR){
        printf("encoder dequeueuInputBuffer err=%s\n",strerror(err));
        return (void*)err;
    }

    Inbuffers[inputIndex]->setRange(0,frameSize);
    printf("InputBuffer inputIndex = %d cap = %d\n",inputIndex,
            Inbuffers[inputIndex]->capacity());
    readBytes = 0;
    readBytes = read(fd0,Inbuffers[inputIndex]->data(),frameSize);
    printf("readBytes = %d  i=%d\n",readBytes,i++);
    if(readBytes)
        queueflag = 0;
    else
        queueflag = MediaCodec::BUFFER_FLAG_EOS ;

    //memcpy(Inbuffers[inputIndex]->data(),(void*)base,frameSize);


    err = encoder->getOutputBuffers(&Outbuffers);
    if(err != NO_ERROR){
        printf("unable to getOutputBuffers (err=%d)\n",err);
        return (void*)err;
    }

    printf("timestamp = %lld\n",startWhenUsec);
    err = encoder->queueInputBuffer(
                inputIndex,
                0,
                frameSize,
                startWhenUsec,//timestamp needs to be set up
                //MediaCodec::BUFFER_FLAG_CODECCONFIG);
                queueflag);
    if(err != NO_ERROR){
        printf("encoder queueuInputBuffer err=%s\n",strerror(err));
        return (void*)err;
    }

    //sleep(1);
    startWhenUsec += 33000;
    err = encoder->dequeueOutputBuffer(&bufIndex, &offset, &size, &ptsUsec,
            &flags, 250000);
    //printf("dequeueoutputbuffer err = %d, %s\n",err,strerror(errno));
    switch (err) {
        case NO_ERROR:
            //printf("& = %d\n",(flags & MediaCodec::BUFFER_FLAG_CODECCONFIG));
            if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) != 0) {
                printf("Got sps/pps in buffer %zu, size=%zu, pts=%lld\n",bufIndex, size, ptsUsec);
                //dump_l("encodered data",Outbuffers[bufIndex]->data(),size);
                write(fd1,Outbuffers[bufIndex]->data(),size);
                size = 0;
                }
            if (size != 0) {
                printf("Got data in buffer %zu, size=%zu, pts=%lld\n",bufIndex, size, ptsUsec);
                //dump_l("encodered data",Outbuffers[bufIndex]->data(),size);
                write(fd1,Outbuffers[bufIndex]->data(),size);
                err = encoder->releaseOutputBuffer(bufIndex);
                if (err != NO_ERROR) {
                    printf("Unable to release output buffer (err=%d)\n",err);
                    return (void*)err;
                }
                if ((flags & MediaCodec::BUFFER_FLAG_EOS) != 0) {
                    printf("Received end-of-stream\n");
                    gStopRequested = true;
                }
            }
            break;
        case -EAGAIN:                       // INFO_TRY_AGAIN_LATER
            printf("Got -EAGAIN, looping\n");
            break;
        case INFO_FORMAT_CHANGED:           // INFO_OUTPUT_FORMAT_CHANGED
            break;
        case INFO_OUTPUT_BUFFERS_CHANGED:   // INFO_OUTPUT_BUFFERS_CHANGED
            // Not expected for an encoder; handle it anyway.
            printf("Encoder buffers changed\n");
            err = encoder->getOutputBuffers(&Outbuffers);
            if (err != NO_ERROR) {
                printf("Unable to get new output buffers (err=%d)\n", err);
                return (void*)err;
            }
            break;
        case INVALID_OPERATION:
            printf("dequeueOutputBuffer returned INVALID_OPERATION\n");
            return (void*)err;
        default:
            printf("Got weird result %d from dequeueOutputBuffer\n", err);
            return (void*)err;
    }
}

encoder->stop();
encoder->release();

失败的案例有以下错误:

test.yuv打开确定

test.h264打开确定

创建编码器

启动编码器

[InputBuffer inputIndex = 0 cap = 1425408

readBytes = 1382400 i = 0

时间戳= 51771085711

[dequeueOutputBuffer返回INVALID_OPERATION

也许我错过了编码器的某些键设置?或忽略了某些平台差异?(例如MTK与Qualcomm Snapdragon的比较...)我知道@fadden是这个Android领域的专家。希望可以从您那里获得帮助。谢谢。

android encoding android-ndk mediacodec
1个回答
0
投票

您能与makefile和头文件共享完整的代码吗?我迫切需要一个我的项目。.

请求您共享代码..

© www.soinside.com 2019 - 2024. All rights reserved.