2012-06-05 98 views
1

我试图从使用FFmpeg的视频转换为jni中的OpenGL ES纹理,但是我得到的所有图像都是黑色纹理。我输出了带有glGetError()的OpenGL,但没有错误。将FFmpeg帧转换为OpenGL ES纹理

这里是我的代码:

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代码的纹理。

编辑1我输出了纹理ID,它是0;纹理ID可能为零?我更改了我的代码 ,但它始终为零。

编辑2 纹理显示,但它是一团糟。

回答

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. 
    */ 
2

不习惯GLES,但GL。在那里,320,240的值不等于512,256,否则你需要使用tex_reords不是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),很好的音频位也被提取到Openf loader的ffmpeg(http://code.google.com/p/openalextensions)。有一些不错的功能,目前我正在尝试使用纹理压缩来查看它是否可以执行得更好。考虑这些教程甚至可以使用gpl代码。

希望能够对ffmpeg对OpenGL/AL整合的晦涩(缺乏)艺术给予启发。