网上ffmpeg开发的代码很多,但是因为版本接口变化很大,都不知道用什么接口。找了很多资料和测试,总算有个可以执行的版本了。直接贴代码,需要的拿去测试吧。
capturertsp.c文件
/*
* read from rtsp,and capture images with FFMPEG4.0.2
* Only support video decoder, not support audio and subtitle.
* Created by zzacn@163.com
*/
#include <stdio.h>
#include <windows.h>
#include <wingdi.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
static AVFormatContext *fmt_ctx = NULL;
static AVStream *video_stream = NULL;
static AVCodec *dec = NULL;
static AVCodecContext *video_dec_ctx = NULL;
static AVFrame *video_frame = NULL;
static AVFrame *pFrameRGB = NULL;
static AVPacket pkt;
static FILE *dst_video_file = NULL;
static int video_stream_index = -1;
void SaveBmp(AVFrame* avPacket, int nWidth, int nHeight, int nBpp,int index)
{
BITMAPFILEHEADER bmpHeader;
bmpHeader.bfType = 0x4d42;
bmpHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + nWidth * nHeight * 3;
bmpHeader.bfReserved1 = 0;
bmpHeader.bfReserved2 = 0;
bmpHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
BITMAPINFOHEADER bmpInfoHeader;
bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfoHeader.biWidth = nWidth;
bmpInfoHeader.biHeight = nHeight;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = nBpp;
bmpInfoHeader.biCompression = BI_RGB;
bmpInfoHeader.biSizeImage = (nWidth*nBpp + 31) / 32 * 4 * nHeight;
bmpInfoHeader.biXPelsPerMeter = 100;
bmpInfoHeader.biYPelsPerMeter = 100;
bmpInfoHeader.biClrUsed = 0;
bmpInfoHeader.biClrImportant = 0;
FILE *fp;
//char *filename = new char[255];
char a[255]={};
char *filename = a;
//文件存放路径,根据自己的修改
sprintf_s(filename, 255, "%s%d.bmp", "F:\\", index);
if ((fp = fopen(filename, "wb+")) == NULL){
return;
}
fwrite(&bmpHeader, sizeof(bmpHeader), 1, fp);
fwrite(&bmpInfoHeader, sizeof(bmpInfoHeader), 1, fp);
fwrite(avPacket->data[0], nWidth * nHeight * 3, 1, fp);
fclose(fp);
}
int main()
{
unsigned char *out_buffer;
struct SwsContext *img_convert_ctx;
// 设置日志的标准, 高于该标准的将不会被显示
av_log_set_level(AV_LOG_DEBUG);
char src_file_name[] = "rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov";
int ret = avformat_network_init();
/* Open an input stream and read the reader. The codecs are not opened.
* The stream must be closed with avformat_close_input().*/
if(avformat_open_input(&fmt_ctx, src_file_name, NULL, NULL) < 0) {
printf("Could not open %s\n", src_file_name);
return -1;
}
if(avformat_find_stream_info(fmt_ctx, NULL) < 0) {
printf("Could not find stream information\n");
goto END;
}
/* Open codec for video stream */
ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if(ret < 0) {
printf("Could not find video stream in input file %s\n", src_file_name);
goto END;
} else {
video_stream_index = ret;
}
video_stream = fmt_ctx->streams[video_stream_index];
dec = avcodec_find_decoder(video_stream->codecpar->codec_id);
if(!dec) {
printf("Failed to find %s codec\n", av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
goto END;
}
/* Allocate a codec context for the decoder.
* The resulting struct should be freed with avcodec_free_context().*/
video_dec_ctx = avcodec_alloc_context3(dec);
if(!video_dec_ctx) {
printf("Failed to allocate the %s codec context\n",
av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
goto END;
}
/* Copy codec parameters from input stream to output codec context */
ret = avcodec_parameters_to_context(video_dec_ctx, video_stream->codecpar);
if(ret < 0) {
printf("Failed to copy %s codec parameters to decoder context\n",
av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
goto END;
}
/* Init the decoders */
ret = avcodec_open2(video_dec_ctx, dec, NULL);
if(ret < 0) {
printf("Failed to open %s codec\n", av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
goto END;
}
/* Dump information */
printf("----------------------File Info---------------------");
av_dump_format(fmt_ctx, 0, src_file_name, 0);
printf("----------------------------------------------------\n");
video_frame = av_frame_alloc(); /* must be freed using av_frame_free(). */
if(!video_frame) {
printf("Could not allocate frame\n");
goto END;
}
pFrameRGB = av_frame_alloc();
if(!pFrameRGB) {
printf("Could not allocate pFrameRGB frame\n");
goto END;
}
/* av_image_get_buffer_size() returns the size in bytes of the amount of data required to store an image with the given parameters. */
out_buffer = (unsigned char *)av_malloc(av_image_get_buffer_size(
AV_PIX_FMT_RGB24, video_dec_ctx->width, video_dec_ctx->height, 1));
av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, out_buffer,
AV_PIX_FMT_RGB24, video_dec_ctx->width, video_dec_ctx->height, 1);
img_convert_ctx = sws_getContext(video_dec_ctx->width, video_dec_ctx->height, video_dec_ctx->pix_fmt,
video_dec_ctx->width, video_dec_ctx->height, AV_PIX_FMT_RGB24,
SWS_BICUBIC, NULL, NULL, NULL);
/* Initialize packet, send data to NULL, let the demuxer fill it */
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
/* Read frames from the file */
int i = 0;
while(av_read_frame(fmt_ctx, &pkt) >= 0) { /* The packet must be freed with av_packet_unref() */
if(pkt.stream_index != video_stream_index) {
av_packet_unref(&pkt);
continue;
}
ret = avcodec_send_packet(video_dec_ctx, &pkt);
if(ret < 0) {
av_packet_unref(&pkt);
continue;
}
do {
ret = avcodec_receive_frame(video_dec_ctx, video_frame);
if(ret < 0)
break;
else if(ret == 0) { /* Got a frame successfully */
sws_scale(img_convert_ctx, (const unsigned char * const *)video_frame->data, video_frame->linesize, 0,
video_dec_ctx->height, pFrameRGB->data, pFrameRGB->linesize);
SaveBmp(pFrameRGB, video_dec_ctx->width, video_dec_ctx->height,24, i ++);
} else if(ret == AVERROR_EOF) {
avcodec_flush_buffers(video_dec_ctx);
break;
}
} while(ret != AVERROR(EAGAIN));
av_packet_unref(&pkt);
if(i >= 100)
break;
}
printf("Demuxing succeeded.\n");
END:
if(pFrameRGB)
av_frame_free(&pFrameRGB);
if(video_frame)
av_frame_free(&video_frame);
if(dst_video_file)
fclose(dst_video_file);
if(video_dec_ctx)
avcodec_free_context(&video_dec_ctx);
if(fmt_ctx)
avformat_close_input(&fmt_ctx);
return 0;
}
MakeFile文件,方便编译。
CC=gcc
CCFLAGS=-IC:/ffmpeg/include -O2
LDFLAGS=-LC:/ffmpeg/lib -lavformat -lavfilter -lavcodec -lswresample -lavdevice -lavutil -lswscale -lpostproc -lpthread -lm -lz
TARGET=capturertsp
OBJS=capturertsp.o
RM=del
STRIP=strip
$(TARGET):$(OBJS)
$(CC) -o $(TARGET) $(OBJS) $(LDFLAGS)
# $(STRIP) $(TARGET)
$(OBJS):%.o:%.c
$(CC) -c -g $(CCFLAGS) $< -o $@
clean:
$(RM) $(TARGET) $(OBJS) *~
用mingw32-make就可以编译了。