Get Base64 codec images from RTSP
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> #include <libswscale/swscale.h> #include <libavutil/imgutils.h> #include <libavutil/base64.h> #include <libavutil/mem.h> static const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; void save_frame_as_image(AVFrame *frame, const char *filename) { // 查找编码器(示例使用JPEG编码器) AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG); AVCodecContext *codec_ctx = avcodec_alloc_context3(codec); // 设置编码参数 codec_ctx->width = frame->width; codec_ctx->height = frame->height; codec_ctx->pix_fmt = AV_PIX_FMT_YUVJ420P; // JPEG兼容格式 codec_ctx->time_base = (AVRational){1, 25}; // 打开编码器 if (avcodec_open2(codec_ctx, codec, NULL) < 0) { fprintf(stderr, "无法打开编码器\n"); return; } // 创建包对象 AVPacket pkt; av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; // 发送帧到编码器 if (avcodec_send_frame(codec_ctx, frame) < 0) { fprintf(stderr, "编码错误\n"); return; } // 接收编码数据 printf(" before save file pkt.size=%d\n", pkt.size); if (avcodec_receive_packet(codec_ctx, &pkt) == 0) { printf(" save file pkt.size=%d\n", pkt.size); // 写入文件 FILE *file = fopen(filename, "wb"); fwrite(pkt.data, 1, pkt.size, file); fclose(file); } av_packet_unref(&pkt); avcodec_free_context(&codec_ctx); } char * frame_to_base64(AVFrame *frame) { // 查找编码器(示例使用JPEG编码器) printf(" nicholas 1 \n"); AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG); AVCodecContext *codec_ctx = avcodec_alloc_context3(codec); printf(" nicholas 2 \n"); // 设置编码参数 codec_ctx->width = frame->width; codec_ctx->height = frame->height; codec_ctx->pix_fmt = AV_PIX_FMT_YUVJ420P; // JPEG兼容格式 codec_ctx->time_base = (AVRational){1, 25}; // 打开编码器 if (avcodec_open2(codec_ctx, codec, NULL) < 0) { printf("can't open codec\n"); return NULL; } printf(" nicholas 3.0 \n"); // 创建包对象 AVPacket pkt; av_init_packet(&pkt); printf(" nicholas 3.1\n"); pkt.data = NULL; pkt.size = 0; // 发送帧到编码器 if (avcodec_send_frame(codec_ctx, frame) < 0) { printf("codec error\n"); return NULL; } printf(" nicholas 4 \n"); // 接收编码数据 printf(" before receive pkt.size=%d\n", pkt.size); if (avcodec_receive_packet(codec_ctx, &pkt) != 0) { printf(" save file pkt.size=%d\n", pkt.size); av_packet_unref(&pkt); avcodec_free_context(&codec_ctx); return NULL; } printf(" save file pkt.size=%d\n", pkt.size); // Base64编码 //int b64_len = (int)av_base64_encode(NULL, 0, aligned_data, data_size); int b64_len = AV_BASE64_SIZE(pkt.size); //4 * ((data_size + 2) / 3); printf(" receive pkt.size=%d", pkt.size); char *b64_data = av_malloc(b64_len + 1); // 包含NULL终止符 printf(" nicholas 5 \n"); av_base64_encode(b64_data, b64_len + 1, pkt.data, pkt.size); printf(" nicholas 6 \n"); int i=0; char path[250]={0}; if(i >100){ return 0; } i++; sprintf(path, "images/N%d.html", i); FILE* file = fopen(path, "w"); if (file == NULL) { perror("Error opening file"); return 0; } printf(" nicholas 7 \n"); fprintf(file, "<img src='data:image/png;base64,%s' />", b64_data); fclose(file); printf(" ********888nicholas \n"); return 0; av_packet_unref(&pkt); avcodec_free_context(&codec_ctx); } void save_rgb(AVFrame *rgb_frame, AVFrame *frame){ // 写入BMP文件(无压缩) FILE *file = fopen("test2.png", "wb"); if(file) { // BMP文件头 unsigned char header[54] = { 0x42,0x4D,0,0,0,0,0,0,0,0,54,0,0,0,40,0,0,0, 0,0,0,0,0,0,0,0,1,0,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; int filesize = 54 + 3 * frame->width * frame->height; header[2] = (unsigned char)(filesize); header[3] = (unsigned char)(filesize>>8); header[4] = (unsigned char)(filesize>>16); header[5] = (unsigned char)(filesize>>24); header[18] = (unsigned char)(frame->width); header[19] = (unsigned char)(frame->width>>8); header[20] = (unsigned char)(frame->width>>16); header[21] = (unsigned char)(frame->width>>24); header[22] = (unsigned char)(frame->height); header[23] = (unsigned char)(frame->height>>8); header[24] = (unsigned char)(frame->height>>16); header[25] = (unsigned char)(frame->height>>24); fwrite(header, 1, 54, file); // 写入RGB数据(需处理linesize可能存在的padding) for(int y=frame->height-1; y>=0; y--) { fwrite(rgb_frame->data[0] + y*rgb_frame->linesize[0], 1, 3*frame->width, file); } fclose(file); } return ; } char* yuv_to_base64(AVFrame *frame) { if (!frame || !frame->data[0]) return NULL; char *b64 = frame_to_base64(frame); printf("ooook\n"); save_frame_as_image(frame, "nnnnnnnnnnn2.png"); printf(" org format:%d, width:%d, height:%d\n", frame->format, frame->width, frame->height); //save_frame_as_image(frame, "test.png"); //return 0; // 转换为RGB格式确保浏览器兼容 struct SwsContext *sws_ctx = sws_getContext( frame->width, frame->height, frame->format, frame->width, frame->height, AV_PIX_FMT_RGB24, SWS_BILINEAR | SWS_ACCURATE_RND, NULL, NULL, NULL); if (!sws_ctx) { printf("Failed to create sws context\n"); return NULL; } AVFrame *rgb_frame = av_frame_alloc(); rgb_frame->format = AV_PIX_FMT_RGB24; rgb_frame->width = frame->width; rgb_frame->height = frame->height; av_frame_get_buffer(rgb_frame, 32); // 实际执行像素格式转换 sws_scale(sws_ctx, (const uint8_t* const*)frame->data, frame->linesize, 0, frame->height, rgb_frame->data, rgb_frame->linesize); if(rgb_frame->format != AV_PIX_FMT_RGB24) { return NULL; } printf(" hello2\n"); save_rgb(rgb_frame, frame); save_frame_as_image(rgb_frame, "nnnnnnnnnnn.png"); frame_to_base64(rgb_frame); printf(" bye22\n"); return NULL; // 计算实际数据长度(处理linesize padding) int data_size = rgb_frame->width * rgb_frame->height * 3; uint8_t *aligned_data = av_malloc(data_size); av_image_copy_to_buffer(aligned_data, data_size, (const uint8_t* const*)rgb_frame->data, rgb_frame->linesize, AV_PIX_FMT_RGB24, rgb_frame->width, rgb_frame->height, 1); // Base64编码 //int b64_len = (int)av_base64_encode(NULL, 0, aligned_data, data_size); int b64_len = AV_BASE64_SIZE(data_size); //4 * ((data_size + 2) / 3); printf(" len=%d\n",b64_len); char *b64_data = av_malloc(b64_len + 1); // 包含NULL终止符 av_base64_encode(b64_data, b64_len + 1, aligned_data, data_size); int i=0; char path[250]={0}; if(i >100){ return 0; } i++; sprintf(path, "images/%d.html", i); FILE* file = fopen(path, "w"); if (file == NULL) { perror("Error opening file"); return 0; } fprintf(file, "<img src='data:image/png;base64,%s' />", b64_data); fclose(file); return 0; // 创建对齐的缓冲区 int aligned_width = FFALIGN(frame->width, 32); uint8_t *aligned_buffer = av_malloc(aligned_width * frame->height * 3); // 将RGB数据复制到对齐的缓冲区 av_image_copy_to_buffer(aligned_buffer, aligned_width * frame->height * 3, (const uint8_t* const*)rgb_frame->data, rgb_frame->linesize, AV_PIX_FMT_RGB24, frame->width, frame->height, 1); // 使用对齐后的buffer进行base64编码 int in_len = frame->width * frame->height * 3; // RGB24数据大小 uint8_t *in = aligned_buffer; int out_len = 4 * ((in_len + 2) / 3); char *b64_str = malloc(out_len + 1); for (int i=0, j=0; i<in_len;) { uint32_t triple = (i<in_len?in[i++]:0)<<16; triple |= (i<in_len?in[i++]:0)<<8; triple |= (i<in_len?in[i++]:0); b64_str[j++] = base64_table[(triple>>18)&0x3F]; b64_str[j++] = base64_table[(triple>>12)&0x3F]; b64_str[j++] = base64_table[(triple>>6)&0x3F]; b64_str[j++] = base64_table[triple&0x3F]; } for (int pad=in_len%3; pad; pad--) b64_str[out_len-pad] = '='; b64_str[out_len] = '\0'; // 释放资源 sws_freeContext(sws_ctx); av_frame_free(&rgb_frame); av_free(aligned_buffer); return b64_str; } char* packet_to_base64(AVPacket *pkt) { if (!pkt || !pkt->data[0]) return NULL; // Base64编码 //int b64_len = (int)av_base64_encode(NULL, 0, aligned_data, data_size); int b64_len = AV_BASE64_SIZE(pkt->size); //4 * ((data_size + 2) / 3); char *b64_data = av_malloc(b64_len + 1); // 包含NULL终止符 av_base64_encode(b64_data, b64_len + 1, pkt->data, pkt->size); int i=0; char path[250]={0}; if(i >100){ return 0; } i++; sprintf(path, "images/%d.html", i); FILE* file = fopen(path, "w"); if (file == NULL) { perror("Error opening file"); return 0; } fprintf(file, "<img src='data:image/png;base64,%s' />", b64_data); fclose(file); return 0; return b64_data; } int main() { AVFormatContext *fmt_ctx = NULL; AVCodecContext *codec_ctx = NULL; AVCodec *codec = NULL; AVFrame *frame = av_frame_alloc(); AVPacket *pkt = av_packet_alloc(); char path[250] = {0}; int i = 0; avformat_network_init(); // 初始化解码器 AVDictionary* options = NULL; av_dict_set(&options, "rtsp_transport", "tcp", 0); av_dict_set(&options, "stimeout", "5000000", 0); // 设置超时5秒 fmt_ctx = avformat_alloc_context(); fmt_ctx->probesize = 10000000; // 将探测大小增至10MB fmt_ctx->max_analyze_duration = 5 * AV_TIME_BASE; // 设置5秒分析时长 avformat_open_input(&fmt_ctx, "rtsp://stream.strba.sk:1935/strba/VYHLAD_JAZERO.stream", NULL, &options); avformat_find_stream_info(fmt_ctx, NULL); int video_stream = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0); //AVCodecParameters *codecpar = fmt_ctx->streams[video_stream]->codecpar; //codec = avcodec_find_decoder(codecpar->codec_id); codec_ctx = avcodec_alloc_context3(codec); avcodec_parameters_to_context(codec_ctx, fmt_ctx->streams[video_stream]->codecpar); avcodec_open2(codec_ctx, codec, NULL); // 处理流程 while (av_read_frame(fmt_ctx, pkt) >= 0) { if (pkt->stream_index == video_stream) { avcodec_send_packet(codec_ctx, pkt); if (avcodec_receive_frame(codec_ctx, frame) == 0) { char *b64 = yuv_to_base64(frame); //printf("<img src=\"data:image/jpeg;base64,%s\">\n", b64); free(b64); } } av_packet_unref(pkt); } // 释放资源 av_frame_free(&frame); av_packet_free(&pkt); avcodec_free_context(&codec_ctx); avformat_close_input(&fmt_ctx); return 0; }
标签: C++
零到一»
日历
最新微语
- 有的时候,会站在分叉路口,不知道向左还是右
2023-12-26 15:34
- 繁花乱开,鸟雀逐风。心自宁静,纷扰不闻。
2023-03-14 09:56
- 对于不可控的事,我们保持乐观,对于可控的事情,我们保持谨慎。
2023-02-09 11:03
- 小时候,
暑假意味着无忧无虑地玩很长一段时间,
节假意味着好吃好喝还有很多长期不见的小朋友来玩...
长大后,
这是女儿第一个暑假,
一个半月...
2022-07-11 08:54
- Watching the autumn leaves falling as you grow older together
2018-10-25 09:45
分类
最新评论
- Goonog
i get it now :) - 萧
@Fluzak:The web host... - Fluzak
Nice blog here! Also... - Albertarive
In my opinion you co... - ChesterHep
What does it plan? - ChesterHep
No, opposite. - mojoheadz
Everything is OK!... - Josephmaigh
I just want to say t... - ChesterHep
What good topic - AnthonyBub
Certainly, never it ...
发表评论: