bmp的码流相当费空间,所以一般在传输时,都会编码为其他格式,就效率来说,一般rgb32的原始码流在转换为yuv时是减半的,如果说对画面质素要求不高的,可以转换为jpg码流,当然h264是传输码流的首选,代码如下
#include <iostream> extern "C" { #include <libavformat/avformat.h> #include <libswscale/swscale.h> } #pragma comment(lib,"avformat.lib") #pragma comment(lib,"avcodec.lib") #pragma comment(lib,"avutil.lib") #pragma comment(lib,"swscale.lib") using namespace std; int main() { char infile[] = "dove_BGRA.rgb"; char outfile[] = "out.264"; // 源图像参数 int width = 640; int height = 360; int fps = 25; //1 打开RGB和H264文件 FILE *fpin = fopen(infile, "rb"); if (!fpin) { cout << infile << "open infile failed!" << endl; getchar(); return -1; } FILE *fpout = fopen(outfile, "wb"); if (!fpout) { cout << "open outfile failed!" << endl; exit(1); } // 创建RGB缓冲区同时分配内存 unsigned char *rgbBuf = new unsigned char[width*height * 4]; // 注册所有和编解码器有关的组件 av_register_all(); /* 2 创建编码器 */ // 查找编码器 AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264); if (!codec) { cout << "avcodec_find_encoder AV_CODEC_ID_H264 failed!" << endl; getchar(); return -1; } // 给编码器分配内存,返回对应编码器上下文 AVCodecContext *codecCtx = avcodec_alloc_context3(codec); if (!codecCtx) { cout << "avcodec_alloc_context3 failed!" << endl; getchar(); return -1; } // 配置编码器上下文的成员 codecCtx->width = width; // 设置编码视频宽度 codecCtx->height = height; // 设置编码视频高度 codecCtx->time_base.num = 1; codecCtx->time_base.den = 25; // 设置帧率,num为分子,den为分母,如果是1/25则表示25帧/s codecCtx->pix_fmt = AV_PIX_FMT_YUV420P; // 设置输出像素格式 // 打开编码器 int ret = avcodec_open2(codecCtx, codec, NULL); if (ret < 0) { cout << "avcodec_open2 failed!" << endl; getchar(); return -1; } cout << "avcodec_open2 success!" << endl; // 3 创建视频重采样上下文:指定源和目标图像分辨率、格式 SwsContext *swsCtx = NULL; swsCtx = sws_getCachedContext(swsCtx, width, height, AV_PIX_FMT_BGRA, width, height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL ); //4 创建YUV视频帧并配置 AVFrame *yuvFrame = av_frame_alloc(); yuvFrame->format = AV_PIX_FMT_YUV420P; yuvFrame->width = width; yuvFrame->height = height; ret = av_frame_get_buffer(yuvFrame, 32); if (ret < 0) { cout << "av_frame_get_buffer failed!" << endl; getchar(); return -1; } // 循环写视频文件 int pts = 0; int count = 0; for (;;) { //5 每次读取一帧RGB数据到rgbBuf,读取完毕则退出 int len = fread(rgbBuf, 1, width*height * 4, fpin); if (len <= 0) { break; } //5 创建RGB视频帧并绑定RGB缓冲区(avpicture_fill是给rgbFrame初始化一些字段,并且会自动填充data和linesize) AVFrame *rgbFrame = av_frame_alloc(); avpicture_fill((AVPicture *)rgbFrame, rgbBuf, AV_PIX_FMT_BGRA, width, height); //7 像素格式转换,转换后的YUV数据存放在yuvFrame int outSliceH = sws_scale(swsCtx, rgbFrame->data, rgbFrame->linesize, 0, height, yuvFrame->data, yuvFrame->linesize ); if (outSliceH <= 0) break; /* 8 H264编码 */ // 将未压缩的AVFrame数据(yuv)给编码器 yuvFrame->pts = count++ * (codecCtx->time_base.num * 1000 / codecCtx->time_base.den); ret = avcodec_send_frame(codecCtx, yuvFrame); if (ret != 0) { continue; } // 将编码数据保存在AVPacket AVPacket pkt; av_init_packet(&pkt); ret = avcodec_receive_packet(codecCtx, &pkt); if (ret != 0) continue; //9 写入H264文件 fwrite(pkt.data, 1, pkt.size, fpout); //av_packet_unref(&pkt); cout << "<" << pkt.size << ">"; } // 关闭RGB和YUV文件 fclose(fpin); fclose(fpout); // 释放RGB缓冲区 delete rgbBuf; //关闭编码器 avcodec_close(codecCtx); //清理编码器上下文 avcodec_free_context(&codecCtx); //清理视频重采样上下文 sws_freeContext(swsCtx); cout << "======================end=========================" << endl; getchar(); return 0; }jpg格式的文件也有许多操作库,经常用的libjpeg库,不过网络上有另外一套针对文件操作的jpg png bmp的综合库,stb_image,这套库支持的格式比较多,也比较常用,但是对于裸流来说,还是不太方便做一些操作,比如rgb的裸流的缩放等等效果。一般和ffmpeg这类编解码库结合来用,比较常见。
jpg格式的图像,一般是不支持alpha通道的,常用的是针对于灰度以及rgb格式文件的压缩,当然通道数越少,压缩效果越好,但是stb_image将写入jpg文件头封装在库内,很不方便使用。对于文件操作来说,还可以,但是对于流的操作就比较繁复了