#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;
}