1

我正在尝试将使用 FFmpeg 的视频转换为 jni 中的 OpenGL ES 纹理,但我得到的只是黑色纹理。我已经用 输出了 OpenGL glGetError(),但没有错误。

这是我的代码:

void* pixels;
int err;
int i;
int frameFinished = 0;
AVPacket packet;
static struct SwsContext *img_convert_ctx;
static struct SwsContext *scale_context = NULL;
int64_t seek_target;

 int target_width = 320;
 int target_height = 240;
 GLenum error = GL_NO_ERROR;
 sws_freeContext(img_convert_ctx);  

i = 0;
while((i==0) && (av_read_frame(pFormatCtx, &packet)>=0)) {
        if(packet.stream_index==videoStream) {
        avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);

        if(frameFinished) {
            LOGI("packet pts %llu", packet.pts);
            img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, 
                   pCodecCtx->pix_fmt, 
                   target_width, target_height, PIX_FMT_RGB24, SWS_BICUBIC, 
                   NULL, NULL, NULL);
            if(img_convert_ctx == NULL) {
                LOGE("could not initialize conversion context\n");
                return;
            }
                sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
                LOGI("sws_scale");

                videoTextures = new Texture*[1];
                videoTextures[0]->mWidth = 256; //(unsigned)pCodecCtx->width;
                videoTextures[0]->mHeight = 256; //(unsigned)pCodecCtx->height;
                videoTextures[0]->mData = pFrameRGB->data[0];

                glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

                glGenTextures(1, &(videoTextures[0]->mTextureID));
                glBindTexture(GL_TEXTURE_2D, videoTextures[0]->mTextureID);
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

                if(0 == got_texture)
                {
                    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, videoTextures[0]->mWidth, videoTextures[0]->mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *)videoTextures[0]->mData);

                    glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, videoTextures[0]->mWidth, videoTextures[0]->mHeight, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *)videoTextures[0]->mData);
                }else
                {
                    glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, videoTextures[0]->mWidth, videoTextures[0]->mHeight, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *)videoTextures[0]->mData);

                }

                i = 1;
                error = glGetError();
                if( error != GL_NO_ERROR ) {
                    LOGE("couldn't create texture!!");
                       switch (error) {
                        case GL_INVALID_ENUM:
                        LOGE("GL Error: Enum argument is out of range");
                        break;
                        case GL_INVALID_VALUE:
                            LOGE("GL Error: Numeric value is out of range");
                        break;
                        case GL_INVALID_OPERATION:
                            LOGE("GL Error: Operation illegal in current state");
                        break;
                        case GL_OUT_OF_MEMORY:
                            LOGE("GL Error: Not enough memory to execute command");
                        break;
                        default:
                            break;
                       }
                }
        }
    }
    av_free_packet(&packet);
}

我已经成功将pFrameRGB改成java位图,但是我只想在c代码中改成纹理。

Edit1 我已经输出了Texture ID,它是0;纹理 ID 可以为零吗?我更改了我的代码,但它始终为零。

Edit2Texture 显示,但它是一团糟。

4

2 回答 2

2

不习惯GLES,而是GL。在那里 320, 240 不是 512,256 的 2 次幂。否则,您需要使用纹理矩形扩展,其 texcoords 不是从 0-1 而是从 0-w/h。至于上传纹理数据,第一次需要使用 glTexImage(...) (即使数据为 0),然后 glTexSubImage 就足够了,我认为第一个初始化大小等,第二个只是发送肉。

关于 ffmpeg 的使用,可能是版本问题,但 img_context 更接近重命名为 sws_getContext,并且只初始化一次,如果 cpu 使用是一个问题,请使用 SWS_LINEAR 而不是 SWS_CUBIC,我也假设 pFrameRGB 已正确 avcodec_alloc_frame()'ed,如果您将使用 GL_RGBA 您应该使用 PIX_FMT_RGBA,PIX_FMT_RGB24 将用于 GL_RGB 纹理管道,最后您缺少数据包堆栈,因此您可以提前阅读以保持良好的同步显示,而不是迟到。

我已经阅读了一些关于解包对齐的评论,我不需要它(并且看到它在该领域的成功)来实现一个 ffmpeg 到 OpenGL/OpenAL 媒体库(http://code.google.com/p /openmedialibrary),很好地,音频位也已被提取到 ffmpeg 到 OpenAL 加载程序(http://code.google.com/p/openalextensions)。有一些不错的功能,目前我正在尝试使用纹理压缩,看看它是否可以表现得更好。考虑一下教程,甚至准备使用 gpl 代码。

希望对 ffmpeg 对 OpenGL/AL 集成的晦涩(缺乏)艺术给予一些启示。

于 2012-11-09T15:59:37.337 回答
0

在传递给解码器之前,尝试将 16 个零字节附加到每个数据包。

来自avcodec.h的一些评论:

 /*
 * @warning The input buffer must be FF_INPUT_BUFFER_PADDING_SIZE larger than
 * the actual read bytes because some optimized bitstream readers read 32 or 64
 * bits at once and could read over the end.
 * @warning The end of the input buffer buf should be set to 0 to ensure that
 * no overreading happens for damaged MPEG streams.
  */
于 2012-07-26T13:23:40.080 回答