android yuv2rgb方案

之前项目里面需要解码h264视频,使用的是ffmpeg,解码出来的是yuv,最好的显示方法是通过opengl es 2.0来实现视频的显示,如果不会opengl es 2.0的话,那么就必须将yuv2rgb然后在绘制图像,而yuv2rgb我只知道两种方法1.通过ffmpeg里面的sws_scale来实现,不过这种方法比较慢,2.这是我之前使用的方法在http://wss.co.uk/pinknoise/yuv2rgb/ 官网上有yuv2rgb的优化代码,里面有c实现和汇编实现两种,实现汇编这种方法yuv2rgb消耗10ms。

下面的rgb格式是PIX_FMT_RGB565

前提:拿到解码以后的AVFrame *frame,frame里面存放解码后的yuv数据。下面是需要用到的变量:


 AVCodecContext      *codec_ctx;  uint8_t    *fill_buffer;   struct SwsContext     *img_convert_ctx;

AVFrame   *frame_rgb;AVFrame *frame;


方法一:

if(frame){

int numBytes = avpicture_get_size(PIX_FMT_RGB565, codec_ctx->width,codec_ctx->height);
                        fill_buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
                        avpicture_fill((AVPicture *)frame_rgb, fill_buffer, PIX_FMT_RGB565,codec_ctx->width, codec_ctx->height);
img_convert_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt,
                                         codec_ctx->width, codec_ctx->height, PIX_FMT_RGB565, SWS_BICUBIC, NULL, NULL, NULL);
sws_scale(img_convert_ctx, frame->data, frame->linesize, 0,  codec_ctx->height, frame_rgb->data, frame_rgb->linesize);

}
方法二:

1、到官网http://wss.co.uk/pinknoise/yuv2rgb/ 下载源码,最新的版本yuv2rgb003

2、解压文件,能够看到里面有如下的文件,包含了不同的格式互相转换,由于我这边是需要yuv420转换为rgb565,所以就使用yuv420rgb565.s这个文件:

root@zhangjie:/home/yuv2rgb# ls
COPYING         yuv2rgbX.s        yuv422rgb565c.c   yuv444rgb565.s
out.yuv         yuv420rgb565c.c   yuv422rgb565.s    yuv444rgb8888c.c
README          yuv420rgb565.s    yuv422rgb8888c.c  yuv444rgb8888.s
test.c          yuv420rgb8888c.c  yuv422rgb8888.s   yuv444rgb888c.c
yuv2rgb16tab.c  yuv420rgb8888.s   yuv422rgb888c.c   yuv444rgb888.s
yuv2rgb555.s    yuv420rgb888c.c   yuv422rgb888.s
yuv2rgb.h       yuv420rgb888.s    yuv444rgb565c.c
3、首先将yuv422rgb565.s,yuv2rgb.h,yuv2rgb16tab.c这三个文件拷贝到你们项目里面去

4、在解码.c文件中,添加"yuv2rgb.h","#include "yuv2rgb16tab.c""然后在文件里添加

extern const uint32_t yuv2rgb565_table[];
extern void yuv420_2_rgb565(uint8_t  *dst_ptr,  //存放rgb的指针
               const uint8_t  *y_ptr, //y数据
               const uint8_t  *u_ptr,  //u数据
               const uint8_t  *v_ptr,  //v数据
                     int32_t   width,  //视频的宽度
                     int32_t   height,  //视频的高度
                     int32_t   y_span,  //frame->linesize[0]
                     int32_t   uv_span,//frame->linesize[1]
                     int32_t   dst_span,  //codec_ctx->width << 1
               const uint32_t *tables,  //之前声明的yuv2rgb565_table
                     int32_t   dither);  //dither可以有四个选择 0,1,2,3
5、使用方法:

 if(first == 0){
                int numBytes = avpicture_get_size(PIX_FMT_RGB565, codec_ctx->width, codec_ctx->height);
                uint8_t *fill_buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
                avpicture_fill(&frame_rgb, fill_buffer, PIX_FMT_RGB565, codec_ctx->width, codec_ctx->height);
                first = 1;
        }

        yuv420_2_rgb565(frame_rgb.data[0], frame->data[0], frame->data[1],frame->data[2], codec_ctx->width, codec_ctx->height, frame->linesize[0],
                        frame->linesize[1], codec_ctx->width << 1, yuv2rgb565_table,3);
6、如果从java传进数组指针,然后从c传出方法(jbyteArray output):

uint8_t *buffer = (uint8_t *)(*env)->GetByteArrayElements(env, output, JNI_FALSE);
memcpy(buffer, frame_rgb.data[0], codec_ctx->width * codec_ctx->height * 2);
(*env)->ReleaseByteArrayElements(env, output, (jbyte *)buffer, 0);

7、如上步骤就可以将yuv420数据转换为rgb565数据,并且从c传递给java层。



你可能感兴趣的:(android yuv2rgb方案)