FFMPEG-初探认识-YUV转RGB用例
来源:互联网 发布:淘宝号实名认证几个 编辑:程序博客网 时间:2024/05/16 04:59
前段时间因为项目需要,尝试通过FFMPEG将图像帧进行格式转换,评估测试了一下,记录一下FFMPEG的一些基本信息资料
概念:
来自百科:
FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。它包括了领先的音/视频编码库libavcodec等。
libavformat:用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构
和读取音视频帧等功能;
libavcodec:用于各种类型声音/图像编解码;
libavutil:包含一些公共的工具函数;
libswscale:用于视频场景比例缩放、色彩映射转换;
libpostproc:用于后期效果处理;
ffmpeg:该项目提供的一个工具,可用于格式转换、解码或电视卡即时编码等;
ffsever:一个 HTTP 多媒体即时广播串流服务器;
ffplay:是一个简单的播放器,使用ffmpeg 库解析和解码,通过SDL显示;
通俗理解为一个 音视频流处理库集合,跟之前接触过的opencv有相同之处,都涉及不深,个人感觉感觉侧重点不同,ffmpeg侧重音视频源数据流的格式编解码,opencv侧重的是对已存在视图的算法处理操作
ffmpeg 官网下载:https://ffmpeg.org/
编译:
ubuntu 32bit 下编译,目标平台android,需要配置NDK ,下载ffmpeg-3.1.4的根目录下创建一个编译脚本build_android.sh,内容如下:
#!/bin/bashNDK=/home/xxx/tool/android-ndk-r10SYSROOT=$NDK/platforms/android-19/arch-arm/TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86function build_one{./configure \ --prefix=$PREFIX \ --enable-shared \ --disable-static \ --disable-doc \ --disable-ffmpeg \ --disable-ffplay \ --disable-ffprobe \ --disable-ffserver \ --enable-gpl \ --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \ --target-os=linux \ --arch=arm \ --enable-cross-compile \ --sysroot=$SYSROOT \ --extra-cflags="-Os -fpic $ADDI_CFLAGS" \ --extra-ldflags="$ADDI_LDFLAGS" \ $ADDITIONAL_CONFIGURE_FLAG#make cleanmakemake install}CPU=armPREFIX=$(pwd)/android/$CPU ADDI_CFLAGS="-marm"build_one
关键是NDK的路径,根据实际情况配置,native-api 的版本以及交叉编译工具链的选择,需注意 32-64 x86主机区别,目标平台为arm
按上面编译之后对应ffmpeg-3.1.4\android\arm 目录下生成 头文件以及 lib库,直接拿到android上使用
YUV格式概念:
网上的总结:
YUV。分为三个分量,“Y”表示明亮度(Luminance或Luma)。也就是灰度值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),
作用是描写叙述影像色彩及饱和度,用于指定像素的颜色。
与我们熟知的RGB类似。YUV也是一种颜色编码方法,主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,
没有UV信息一样能够显示完整的图像,仅仅只是是黑白的,这种设计非常好地攻克了彩色电视机与黑白电视的兼容问题。
而且,YUV不像RGB那样要求三个独立的视频信号同一时候传输,所以用YUV方式传送占用极少的频宽。
通过YUV与RGB的转换公式提取出每一个像素点的RGB值,然后显示出来。
YUV 4:4:4採样,每个Y相应一组UV分量。
YUV 4:2:2採样。每两个Y共用一组UV分量。
YUV 4:2:0採样,每四个Y共用一组UV分量。
参考网上的博客 http://blog.csdn.net/beyond_cn/article/details/12998247
YUV转RGB:
通过ffmpeg将一帧YUV格式的图像转换成成RGB格式并存储,需要用到 libavutil 以及 libswscale
网上摘的转换实现:
#include <stdio.h>#include <utils/Log.h>#define LOG_TAG "ffmpeg"extern "C"{#include "libswscale/swscale.h"#include "libavutil/opt.h"#include "libavutil/imgutils.h"};#include <android/log.h>#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , "ffmpeg", __VA_ARGS__)int main(int argc, char* argv[]){ //Parameters FILE *src_file =fopen("1088p_yuv420p.yuv", "rb"); const int src_w=1920,src_h=1088; AVPixelFormat src_pixfmt=AV_PIX_FMT_YUV420P; int src_bpp=av_get_bits_per_pixel(av_pix_fmt_desc_get(src_pixfmt)); FILE *dst_file = fopen("480p_rgb24.rgb", "wb"); const int dst_w=800,dst_h=480; AVPixelFormat dst_pixfmt=AV_PIX_FMT_RGB565LE/*AV_PIX_FMT_RGB24*/; int dst_bpp=av_get_bits_per_pixel(av_pix_fmt_desc_get(dst_pixfmt)); //Structures uint8_t *src_data[4]; int src_linesize[4]; uint8_t *dst_data[4]; int dst_linesize[4]; int rescale_method=SWS_BILINEAR/*SWS_POINT*//*SWS_BICUBIC*/; struct SwsContext *img_convert_ctx; uint8_t *temp_buffer=(uint8_t *)malloc(src_w*src_h*src_bpp/8); int frame_idx=0; int ret=0; ret= av_image_alloc(src_data, src_linesize,src_w, src_h, src_pixfmt, 1); if (ret< 0) { printf( "Could not allocate source image\n"); return -1; } ret = av_image_alloc(dst_data, dst_linesize,dst_w, dst_h, dst_pixfmt, 1); if (ret< 0) { printf( "Could not allocate destination image\n"); return -1; } //----------------------------- //Init Method 1// img_convert_ctx =sws_alloc_context();// //Show AVOption// av_opt_show2(img_convert_ctx,stdout,AV_OPT_FLAG_VIDEO_PARAM,NULL);// //Set Value// av_opt_set_int(img_convert_ctx,"sws_flags",SWS_BICUBIC|SWS_PRINT_INFO,NULL);// av_opt_set_int(img_convert_ctx,"srcw",src_w,NULL);// av_opt_set_int(img_convert_ctx,"srch",src_h,NULL);// av_opt_set_int(img_convert_ctx,"src_format",src_pixfmt,NULL);// //'0' for MPEG (Y:0-235);'1' for JPEG (Y:0-255)// av_opt_set_int(img_convert_ctx,"src_range",1,NULL);// av_opt_set_int(img_convert_ctx,"dstw",dst_w,NULL);// av_opt_set_int(img_convert_ctx,"dsth",dst_h,NULL);// av_opt_set_int(img_convert_ctx,"dst_format",dst_pixfmt,NULL);// av_opt_set_int(img_convert_ctx,"dst_range",1,NULL);// sws_init_context(img_convert_ctx,NULL,NULL); //Init Method 2 img_convert_ctx = sws_getContext(src_w, src_h,src_pixfmt, dst_w, dst_h, dst_pixfmt, rescale_method, NULL, NULL, NULL); //----------------------------- /* //Colorspace ret=sws_setColorspaceDetails(img_convert_ctx,sws_getCoefficients(SWS_CS_ITU601),0, sws_getCoefficients(SWS_CS_ITU709),0, 0, 1 << 16, 1 << 16); if (ret==-1) { printf( "Colorspace not support.\n"); return -1; } */ while(1) { if (fread(temp_buffer, 1, src_w*src_h*src_bpp/8, src_file) != src_w*src_h*src_bpp/8){ break; } switch(src_pixfmt){ case AV_PIX_FMT_GRAY8:{ memcpy(src_data[0],temp_buffer,src_w*src_h); break; } case AV_PIX_FMT_YUV420P:{ memcpy(src_data[0],temp_buffer,src_w*src_h); //Y memcpy(src_data[1],temp_buffer+src_w*src_h,src_w*src_h/4); //U memcpy(src_data[2],temp_buffer+src_w*src_h*5/4,src_w*src_h/4); //V break; } case AV_PIX_FMT_YUV422P:{ memcpy(src_data[0],temp_buffer,src_w*src_h); //Y memcpy(src_data[1],temp_buffer+src_w*src_h,src_w*src_h/2); //U memcpy(src_data[2],temp_buffer+src_w*src_h*3/2,src_w*src_h/2); //V break; } case AV_PIX_FMT_YUV444P:{ memcpy(src_data[0],temp_buffer,src_w*src_h); //Y memcpy(src_data[1],temp_buffer+src_w*src_h,src_w*src_h); //U memcpy(src_data[2],temp_buffer+src_w*src_h*2,src_w*src_h); //V break; } case AV_PIX_FMT_YUYV422:{ memcpy(src_data[0],temp_buffer,src_w*src_h*2); //Packed break; } case AV_PIX_FMT_RGB24:{ memcpy(src_data[0],temp_buffer,src_w*src_h*3); //Packed break; } default:{ printf("Not Support Input Pixel Format.\n"); break; } } ALOGE("-Finish process frame %5d\n",frame_idx); sws_scale(img_convert_ctx, src_data, src_linesize, 0, src_h, dst_data, dst_linesize); ALOGE("*Finish process frame %5d\n",frame_idx); printf("test-Finish process frame %5d\n",frame_idx); frame_idx++; switch(dst_pixfmt){ case AV_PIX_FMT_GRAY8:{ fwrite(dst_data[0],1,dst_w*dst_h,dst_file); break; } case AV_PIX_FMT_YUV420P:{ fwrite(dst_data[0],1,dst_w*dst_h,dst_file); //Y fwrite(dst_data[1],1,dst_w*dst_h/4,dst_file); //U fwrite(dst_data[2],1,dst_w*dst_h/4,dst_file); //V break; } case AV_PIX_FMT_YUV422P:{ fwrite(dst_data[0],1,dst_w*dst_h,dst_file); //Y fwrite(dst_data[1],1,dst_w*dst_h/2,dst_file); //U fwrite(dst_data[2],1,dst_w*dst_h/2,dst_file); //V break; } case AV_PIX_FMT_YUV444P:{ fwrite(dst_data[0],1,dst_w*dst_h,dst_file); //Y fwrite(dst_data[1],1,dst_w*dst_h,dst_file); //U fwrite(dst_data[2],1,dst_w*dst_h,dst_file); //V break; } case AV_PIX_FMT_YUYV422:{ fwrite(dst_data[0],1,dst_w*dst_h*2,dst_file); //Packed break; } case AV_PIX_FMT_RGB24:{ fwrite(dst_data[0],1,dst_w*dst_h*3,dst_file); //Packed break; } case AV_PIX_FMT_RGB565LE:{ fwrite(dst_data[0],1,dst_w*dst_h*2,dst_file); //Packed break; } default:{ printf("Not Support Output Pixel Format.\n"); break; } } } sws_freeContext(img_convert_ctx); free(temp_buffer); fclose(dst_file); av_freep(&src_data[0]); av_freep(&dst_data[0]); printf("ffmpeg_scale complete \n"); return 0;}
代码比较简单明了,需要注意的是 img_convert_ctx Init Method 方法有两种,
调用swscale中的接口 sws_scale(…)实现缩放,第一种init默认缩放算法为 SWS_BICUBIC ,第二种可以自己设定指定rescale_method
支持格式头文件:ffmpeg-3.1.4\libavutil\pixfmt.h
scale算法种类: ffmpeg-3.1.4\libswscale\swscale.h
至于算法的选择可参考 http://www.cnblogs.com/acloud/archive/2011/10/29/sws_scale.html
有具体的测试数据
- FFMPEG-初探认识-YUV转RGB用例
- ffmpeg开发系列-YUV转RGB
- ffmpeg rgb转yuv 生成H264文件
- 认识RGB和YUV
- RGB转YUV YUV转RGB
- YUV转RGB函数
- YUV转RGB
- YUV转RGB
- RGB转YUV
- YUV转RGB
- YUV转RGB汇总
- android YUV转RGB
- YUV转RGB
- YUV转RGB
- RGB转YUV
- yuv转rgb
- yuv转RGB
- RGB转YUV
- LINUX内核内存管理kmalloc,vmalloc
- 工作常用的android adb shell命令 (mac环境)
- lua中操作符的优先级
- 程序计算精确圆周率Pai的方法
- 软件发布版本区别介绍
- FFMPEG-初探认识-YUV转RGB用例
- C语言中最常用标准库函数
- MySQL上线后根据status状态进行适当优化
- 关于斯诺登暴料部分卡商SIM卡密钥被窃取的几点想法
- react native 环境配置
- Swift3.0 功能一(持续更新)
- Android GridView实现多种不同布局样式显示数据
- SSD的配置安装与测试
- CK+表情数据库及使用