利用ffmpeg将H264流 解码为RGB

利用H264解码分为几个步骤:

 

注意一点在添加头文件的时候要添加extern "C",不然会出现错误

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. extern "C"  
  2. {  
  3. #include <avcodec.h>  
  4. #include <avformat.h>  
  5. #include <avutil.h>  
  6. #include <swscale.h>  
  7. };  


 

 

这里申明了几个全局变量

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. AVCodec         *pCodec = NULL;  
  2. AVCodecContext  *pCodecCtx = NULL;  
  3. SwsContext      *img_convert_ctx = NULL;  
  4. AVFrame         *pFrame = NULL;  
  5. AVFrame         *pFrameRGB = NULL;  


 

1. 初始化

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int H264_Init(void)  
  2. {  
  3.     /* must be called before using avcodec lib*/  
  4.     avcodec_init();  
  5.     /* register all the codecs */  
  6.     avcodec_register_all();  
  7.   
  8.     /* find the h264 video decoder */  
  9.     pCodec = avcodec_find_decoder(CODEC_ID_H264);  
  10.     if (!pCodec) {  
  11.         fprintf(stderr, "codec not found\n");  
  12.     }  
  13.     pCodecCtx = avcodec_alloc_context();  
  14.   
  15.     /* open the coderc */  
  16.     if (avcodec_open(pCodecCtx, pCodec) < 0) {  
  17.         fprintf(stderr, "could not open codec\n");  
  18.     }  
  19.     // Allocate video frame  
  20.     pFrame = avcodec_alloc_frame();  
  21.     if(pFrame == NULL)  
  22.         return -1;  
  23.     // Allocate an AVFrame structure  
  24.     pFrameRGB=avcodec_alloc_frame();  
  25.     if(pFrameRGB == NULL)  
  26.         return -1;  
  27.   
  28.   
  29.       
  30.     return 0;  
  31.   
  32. }  

在最早使用的时候没有使用全局变量,初始化中也就只有init和regisger这两个函数,而这样做的下场是,非关键帧全部无法解码,只有关键帧才有办法解码。

2. 解码

解码的时候avcodec_decode_video函数是进行解码操作,在外部定义outputbuf的大小时,pixes*3,outsize是返回的outputbuf的size,值也是pixes*3。

 

在解码的时候这几句话的意义是将YUV420P的数据倒置。在原先使用中,发现解出来的图像居然是中心旋转图,后面在网上找了些办法,觉得这个比较实用。解码实时是很重要的,图像转化完之后也可以讲RGB图再次转化,那样也能成为一个正的图,但是那样效率就明显低了。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height-1);  
  2. pFrame->linesize[0] *= -1;  
  3. pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height/2 - 1);;  
  4. pFrame->linesize[1] *= -1;  
  5. pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height/2 - 1);;  
  6. pFrame->linesize[2] *= -1;  


 

 

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int H264_2_RGB(unsigned char *inputbuf, int frame_size, unsigned char *outputbuf, unsigned int*outsize)  
  2. {  
  3.       
  4.     int             decode_size;  
  5.     int             numBytes;  
  6.     int             av_result;  
  7.     uint8_t         *buffer = NULL;  
  8.   
  9.     printf("Video decoding\n");  
  10.   
  11.     av_result = avcodec_decode_video(pCodecCtx, pFrame, &decode_size, inputbuf, frame_size);  
  12.     if (av_result < 0)  
  13.     {  
  14.         fprintf(stderr, "decode failed: inputbuf = 0x%x , input_framesize = %d\n", inputbuf, frame_size);  
  15.         return -1;  
  16.     }  
  17.   
  18.     // Determine required buffer size and allocate buffer  
  19.     numBytes=avpicture_get_size(PIX_FMT_BGR24, pCodecCtx->width,  
  20.         pCodecCtx->height);  
  21.     buffer = (uint8_t*)malloc(numBytes * sizeof(uint8_t));  
  22.     // Assign appropriate parts of buffer to image planes in pFrameRGB  
  23.     avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_BGR24,  
  24.         pCodecCtx->width, pCodecCtx->height);  
  25.   
  26.     img_convert_ctx = sws_getCachedContext(img_convert_ctx,pCodecCtx->width,pCodecCtx->height,  
  27.         //PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,  
  28.         pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,PIX_FMT_RGB24 ,  
  29.         SWS_X ,NULL,NULL,NULL) ;  
  30.     if (img_convert_ctx == NULL)   
  31.     {  
  32.   
  33.         printf("can't init convert context!\n") ;  
  34.         return -1;  
  35.     }  
  36.     pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height-1);  
  37.     pFrame->linesize[0] *= -1;  
  38.     pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height/2 - 1);;  
  39.     pFrame->linesize[1] *= -1;  
  40.     pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height/2 - 1);;  
  41.     pFrame->linesize[2] *= -1;  
  42.     sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize,  
  43.         0, 0 - pCodecCtx->width, pFrameRGB->data, pFrameRGB->linesize);  
  44.       
  45.     if (decode_size)  
  46.     {  
  47.         *outsize = pCodecCtx->width * pCodecCtx->height * 3;  
  48.         memcpy(outputbuf, pFrameRGB->data[0], *outsize);  
  49.     }     
  50.   
  51.   
  52.     free(buffer);  
  53.     return 0;  
  54. }  

//解码yuv 修改 PIX_FMT_YUV420P	
memcpy(outputbuf, pFrameRGB->data[2], 720*576/4);
			memcpy(outputbuf, pFrameRGB->data[1], 720*576/4);
			memcpy(outputbuf, pFrameRGB->data[0], 720*576);



3. 释放资源

资源的回收。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void H264_Release(void)  
  2. {  
  3.     avcodec_close(pCodecCtx);  
  4.     av_free(pCodecCtx);  
  5.     av_free(pFrame);  
  6.     av_free(pFrameRGB);  
  7. }  
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用FFmpeg C++库将RGB图像转换为H.264编码,并将其推,可以按照以下步骤进行: 1. 初始化FFmpeg库和相关的编码器、解码器、格式器等组件。 2. 创建输入的RGB图像数据,可以使用OpenCV等库读取图像文件,或者使用自己的算法生成RGB图像数据。 3. 创建输出的H.264编码器,并初始化编码器参数。可以使用FFmpeg提供的编码器,如libx264,或者其他第三方编码器。 4. 将RGB图像数据转换为YUV420P格式,这是H.264编码器所需的格式。可以使用FFmpeg提供的sws_scale函数进行转换。 5. 将YUV420P格式的图像数据输入到编码器中进行编码,生成H.264码。 6. 创建输出的网络或文件,将编码后的H.264码写入到网络或文件中。 7. 循环执行步骤2到6,直到所有图像都被编码并推完毕。 下面是一个简单的代码示例,仅供参考: ```c++ #include <iostream> #include <string> #include <cstdlib> #include <cstdio> extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavutil/opt.h> #include <libavutil/imgutils.h> } using namespace std; int main(int argc, char* argv[]) { // 初始化FFmpeg库 av_register_all(); avcodec_register_all(); // 输入RGB图像的宽度和高度 int width = 640; int height = 480; // 创建输入的RGB图像数据,这里使用随机数据代替 uint8_t* rgb_data = new uint8_t[width * height * 3]; for (int i = 0; i < width * height * 3; i++) rgb_data[i] = rand() % 256; // 创建输出的H.264编码器 AVCodec* codec = avcodec_find_encoder_by_name("libx264"); if (!codec) { cerr << "Codec libx264 not found" << endl; exit(1); } AVCodecContext* codec_ctx = avcodec_alloc_context3(codec); if (!codec_ctx) { cerr << "Could not allocate video codec context" << endl; exit(1); } codec_ctx->bit_rate = 400000; codec_ctx->width = width; codec_ctx->height = height; codec_ctx->time_base = { 1, 25 }; codec_ctx->gop_size = 10; codec_ctx->max_b_frames = 1; codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; if (avcodec_open2(codec_ctx, codec, NULL) < 0) { cerr << "Could not open codec" << endl; exit(1); } // 创建输出的网络或文件 const char* filename = "output.mp4"; AVOutputFormat* fmt = av_guess_format(NULL, filename, NULL); AVFormatContext* fmt_ctx = avformat_alloc_context(); if (!fmt_ctx) { cerr << "Could not allocate output format context" << endl; exit(1); } fmt_ctx->oformat = fmt; if (avio_open(&fmt_ctx->pb, filename, AVIO_FLAG_WRITE) < 0) { cerr << "Could not open output file '" << filename << "'" << endl; exit(1); } // 创建输出的视频 AVStream* video_stream = avformat_new_stream(fmt_ctx, NULL); if (!video_stream) { cerr << "Could not allocate video stream" << endl; exit(1); } video_stream->id = fmt_ctx->nb_streams - 1; AVCodecParameters* codecpar = video_stream->codecpar; codecpar->codec_type = AVMEDIA_TYPE_VIDEO; codecpar->codec_id = codec->id; codecpar->bit_rate = codec_ctx->bit_rate; codecpar->width = codec_ctx->width; codecpar->height = codec_ctx->height; codecpar->format = codec_ctx->pix_fmt; avcodec_parameters_to_context(codec_ctx, codecpar); av_dump_format(fmt_ctx, 0, filename, 1); // 初始化编码器 AVFrame* frame = av_frame_alloc(); if (!frame) { cerr << "Could not allocate video frame" << endl; exit(1); } frame->format = codec_ctx->pix_fmt; frame->width = codec_ctx->width; frame->height = codec_ctx->height; if (av_frame_get_buffer(frame, 0) < 0) { cerr << "Could not allocate video frame data" << endl; exit(1); } AVPacket* pkt = av_packet_alloc(); if (!pkt) { cerr << "Could not allocate packet" << endl; exit(1); } // 将RGB图像数据转换为YUV420P格式 int y_size = codec_ctx->width * codec_ctx->height; uint8_t* yuv_data = new uint8_t[y_size * 3 / 2]; SwsContext* sws_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_YUV420P, 0, NULL, NULL, NULL); sws_scale(sws_ctx, &rgb_data, &width, 0, codec_ctx->height, &yuv_data, &codec_ctx->width); // 编码并推 int ret = 0; int frame_count = 0; while (frame_count < 100) { // 循环100次,测试用,可以根据实际情况修改 // 将YUV420P格式的图像数据输入到编码器中进行编码 frame->data[0] = yuv_data; frame->data[1] = yuv_data + y_size; frame->data[2] = yuv_data + y_size * 5 / 4; frame->pts = frame_count * codec_ctx->time_base.den / codec_ctx->time_base.num; ret = avcodec_send_frame(codec_ctx, frame); if (ret < 0) { cerr << "Error sending a frame for encoding" << endl; exit(1); } while (ret >= 0) { ret = avcodec_receive_packet(codec_ctx, pkt); if (ret < 0) { if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break; cerr << "Error during encoding" << endl; exit(1); } av_packet_rescale_ts(pkt, codec_ctx->time_base, video_stream->time_base); pkt->stream_index = video_stream->index; ret = av_interleaved_write_frame(fmt_ctx, pkt); if (ret < 0) { cerr << "Error writing video frame" << endl; exit(1); } } frame_count++; } // 清理资源 av_write_trailer(fmt_ctx); av_packet_free(&pkt); av_frame_free(&frame); avcodec_free_context(&codec_ctx); avformat_close_input(&fmt_ctx); avio_close(fmt_ctx->pb); avformat_free_context(fmt_ctx); sws_freeContext(sws_ctx); delete[] rgb_data; delete[] yuv_data; return 0; } ``` 运行该程序后,会将生成的H.264编码后的码写入到文件"output.mp4"中。要将编码后的码到网络上,可以使用FFmpeg提供的RTMP协议或者其他协议进行推

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值