使用ffmpeg解码raw图

本文详细介绍使用FFmpeg工具处理不同格式的RAW图方法,包括从RAW图转换为常见图片格式,如RGB8888到BMP,RGB565到BMP,以及反向操作。文章还探讨了直接通过设备文件解码RAW图遇到的问题,并提供了具体的命令实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

调试过程中,生成了一张raw图,如何显示raw图的内容的,可参考如下的命令

原图16bit 320*240(https://download.youkuaiyun.com/download/mike8825/12342954)

ffmpeg -vcodec rawvideo -f rawvideo -pix_fmt rgb565 -s 320*240 -i 1.raw -f image2 -vcodec bmp 1.bmp

原图32bit 1920*1080

ffmpeg -vcodec rawvideo -f rawvideo -pix_fmt rgb32 -s 1920x1080 -i 2.raw -f image2 -vcodec bmp 2.bmp

最开始想通过cat /dev/fb0 >2.raw,用2.raw来解码,但解码出来是黑屏的,可能跟显示架构有关系,这里不深究。

参考下面的命令,可以将图片转换成raw图,然后raw在装换成图片,这样就可以验证命令的正确性了。

# rgb8888 -> bmp
ffmpeg -vcodec rawvideo -f rawvideo -pix_fmt rgb32 -s 640x480 -i fb.raw -f image2 -vcodec bmp fb.bmp

# rgb565 -> bmp
ffmpeg -vcodec rawvideo -f rawvideo -pix_fmt rgb565 -s 640x480 -i fb.raw -f image2 -vcodec bmp fb.bmp

# bmp -> rgb8888
ffmpeg -vcodec bmp -i fb.bmp -vcodec rawvideo -f rawvideo -pix_fmt rgb32 fb.raw

# bmp -> rgb565
ffmpeg -vcodec bmp -i fb.bmp -vcodec rawvideo -f rawvideo -pix_fmt rgb565 fb.raw

 参考https://qiita.com/koara-local/items/0b750355b1a9135ff53f

### 使用 Qt 和 FFmpeg 解码 uint16 Raw 格式的视频 为了使用 Qt 和 FFmpeg解码 `uint16` 原始格式的视频文件,可以遵循以下方法。此过程涉及配置项目环境、编写必要的 C++ 代码来初始化 FFMpeg 库并读取帧数据。 #### 配置项目环境 在 `.pro` 文件中加入特定路径以便访问静态库和头文件[^2]: ```makefile TEMPLATE = app CONFIG += console c++11 CONFIG -= app_bundle CONFIG -= qt SOURCES += main.cpp decode_video.cpp INCLUDEPATH += /path/to/ffmpeg/include LIBS += -L/path/to/ffmpeg/lib \ -lavcodec -lavdevice -lavfilter -lavformat -lavutil -lswresample -lswscale ``` 请注意替换 `/path/to/ffmpeg/...` 为实际安装目录下的相应子目录。 #### 初始化 FFMpeg 并打开输入文件 创建一个新的源文件用于编码逻辑,在其中包含必要的头文件,并通过 `av_register_all()` 注册所有可用组件: ```cpp extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> } int init_ffmpeg() { av_register_all(); return 0; } ``` 接着尝试加载目标媒体资源作为输入流: ```cpp AVFormatContext *fmt_ctx = nullptr; if (avformat_open_input(&fmt_ctx, filename.c_str(), NULL, NULL) != 0){ // 打开失败处理... return -1; } if(avformat_find_stream_info(fmt_ctx, NULL)<0){ // 获取流信息失败处理... return -1; } ``` #### 查找视频流索引及分配上下文空间 遍历找到第一个匹配类型的流(这里假设只关心视频),同时准备解码器实例及其私有数据结构体: ```cpp int videoStreamIndex=-1; for(unsigned int i=0; i<fmt_ctx->nb_streams;i++){ if(fmt_ctx->streams[i]->codecpar->codec_type== AVMEDIA_TYPE_VIDEO){ videoStreamIndex=i; break; } } if(videoStreamIndex==-1){ // 没有发现合适的视频轨道时返回错误. return -1; } const AVCodecParameters* codec_params = fmt_ctx->streams[videoStreamIndex]->codecpar; AVCodec *decoder = avcodec_find_decoder(codec_params->codec_id); if (!decoder || avcodec_parameters_to_context(decoderCtx, codec_params) < 0 || avcodec_open2(decoderCtx, decoder, NULL) < 0){ // 创建或开启解码器失败处理... return -1; } ``` 对于 `uint16` 的原始像素格式(`raw`),通常意味着每两个字节表示一个亮度样本值(灰度级),因此需要特别注意设置正确的色彩空间参数. #### 循环读取包并送入解码队列 一旦成功设置了上述条件,则可以通过循环调用 `av_read_frame()` 函数获取压缩后的NALU单元或其他封装形式的数据包(Packets),再传递给对应的解码函数进行进一步解析成完整的像帧(Frame): ```cpp while(true){ AVPacket packet; if(int ret = av_read_frame(fmt_ctx,&packet)>=0 && packet.stream_index == videoStreamIndex){ if(int sendRet = avcodec_send_packet(decoderCtx,&packet)==0){ while(int recvRet = avcodec_receive_frame(decoderCtx,pFrame)>=0){ // 成功接收到一帧后在此处添加渲染逻辑 // 清理当前接收完毕的对象 av_frame_unref(pFrame); } }else{ // 发送分组至解码器过程中出现问题 } // 不论是否正常结束都应当释放临时使用的内存区域 av_packet_unref(&packet); continue; }else{ // 当到达文件结尾或者其他异常情况发生时退出循环 break; } } ``` 最后一步就是根据实际情况调整显示方式了——这取决于具体应用场景下希望怎样呈现这些经过解压还原出来的视觉内容。如果是在基于Qt的应用程序内部操作的话,那么很可能还需要借助于QWidget类族中的某些成员比如QImage/QPixmap等完成最终的画面展现工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值